1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2 // Licensed under the MIT License:
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 module capnproto.benchmark.TestCase;
23 
24 import std.conv : to;
25 import std.stdio;
26 
27 import java.io.IOException;
28 import java.nio.ByteBuffer;
29 
30 import capnproto.ArrayInputStream;
31 import capnproto.ArrayOutputStream;
32 import capnproto.BufferedInputStreamWrapper;
33 import capnproto.BufferedOutputStreamWrapper;
34 import capnproto.FileDescriptor;
35 import capnproto.MessageBuilder;
36 import capnproto.MessageReader;
37 
38 import capnproto.benchmark.Common;
39 import capnproto.benchmark.Compression;
40 
41 abstract class TestCase(Request, Response, Expectation)
42 {
43 public: //Variables.
44 	enum SCRATCH_SIZE = 128 * 1024;
45 
46 public: //Methods.
47 	abstract Expectation setupRequest(Request.Builder request);
48 	abstract void handleRequest(Request.Reader request, Response.Builder response);
49 	abstract bool checkResponse(Response.Reader response, Expectation expected);
50 	
51 	void passByObject(Compression compression, long iters)
52 	{
53 		foreach(ii; 0..iters)
54 		{
55 			auto requestMessage = new MessageBuilder();
56 			auto responseMessage = new MessageBuilder();
57 			auto request = requestMessage.initRoot!Request;
58 			auto expected = this.setupRequest(request);
59 			auto response = responseMessage.initRoot!Response;
60 			this.handleRequest(request.asReader(), response);
61 			if(!this.checkResponse(response.asReader(), expected))
62 				writeln("Mismatch!");
63 		}
64 	}
65 	
66 	void passByBytes(Compression compression, long iters)
67 	{
68 		auto requestBytes = ByteBuffer(new ubyte[](SCRATCH_SIZE * 8));
69 		auto responseBytes = ByteBuffer(new ubyte[](SCRATCH_SIZE * 8));
70 		
71 		foreach(ii; 0..iters)
72 		{
73 			auto requestMessage = new MessageBuilder();
74 			auto responseMessage = new MessageBuilder();
75 			auto request = requestMessage.initRoot!Request;
76 			auto expected = this.setupRequest(request);
77 			auto response = responseMessage.initRoot!Response;
78 			
79 			{
80 				auto writer = new ArrayOutputStream(requestBytes);
81 				compression.writeBuffered(writer, requestMessage);
82 			}
83 			
84 			{
85 				auto messageReader = compression.newBufferedReader(new ArrayInputStream(requestBytes));
86 				this.handleRequest(messageReader.getRoot!Request, response);
87 			}
88 			
89 			{
90 				auto writer = new ArrayOutputStream(responseBytes);
91 				compression.writeBuffered(writer, responseMessage);
92 			}
93 			
94 			{
95 				auto messageReader = compression.newBufferedReader(new ArrayInputStream(responseBytes));
96 				if(!this.checkResponse(messageReader.getRoot!Response, expected))
97 					throw new Error("Incorrect response!");
98 			}
99 		}
100 	}
101 	
102 	void syncServer(Compression compression, long iters)
103 	{
104 		auto outBuffered = new BufferedOutputStreamWrapper(new FileDescriptor(stdout));
105 		auto inBuffered = new BufferedInputStreamWrapper(new FileDescriptor(stdin));
106 		
107 		foreach(ii; 0..iters)
108 		{
109 			auto responseMessage = new MessageBuilder();
110 			{
111 				auto response = responseMessage.initRoot!Response;
112 				auto messageReader = compression.newBufferedReader(inBuffered);
113 				auto request = messageReader.getRoot!Request;
114 				this.handleRequest(request, response);
115 			}
116 			compression.writeBuffered(outBuffered, responseMessage);
117 		}
118 	}
119 	
120 	void syncClient(Compression compression, long iters)
121 	{
122 		auto outBuffered = new BufferedOutputStreamWrapper(new FileDescriptor(stdout));
123 		auto inBuffered = new BufferedInputStreamWrapper(new FileDescriptor(stdin));
124 		
125 		foreach(ii; 0..iters)
126 		{
127 			auto requestMessage = new MessageBuilder();
128 			auto request = requestMessage.initRoot!Request;
129 			auto expected = this.setupRequest(request);
130 			
131 			compression.writeBuffered(outBuffered, requestMessage);
132 			auto messageReader = compression.newBufferedReader(inBuffered);
133 			auto response = messageReader.getRoot!Response;
134 			if(!this.checkResponse(response, expected))
135 				throw new Error("Incorrect response!");
136 		}
137 	}
138 	
139 	void execute(string[] args)
140 	{
141 		if(args.length != 5)
142 		{
143 			writeln("USAGE: TestCase MODE REUSE COMPRESSION ITERATION_COUNT");
144 			return;
145 		}
146 		
147 		auto mode = args[1];
148 		auto reuse = args[2];
149 		Compression compression;
150 		if(args[3] == "packed")
151 			compression = cast(Compression)Compression.packed;
152 		else if(args[3] == "none")
153 			compression = cast(Compression)Compression.uncompressed;
154 		else
155 			throw new Error("Unrecognized compression: " ~ args[2]);
156 		
157 		long iters = to!long(args[4]);
158 		
159 		if(mode == "object")
160 			passByObject(compression, iters);
161 		else if(mode == "bytes")
162 			passByBytes(compression, iters);
163 		else if(mode == "client")
164 			syncClient(compression, iters);
165 		else if(mode == "server")
166 			syncServer(compression, iters);
167 		else
168 			writefln("Unrecognized mode: %s", mode);
169 	}
170 }