blob: 5f159b627305cfe913138be1c2fcde1a618a1eca [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
2
csharptest68d831e2011-05-03 13:47:34 -05003// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc. All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15// * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19// * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
csharptest71f662c2011-05-20 15:15:34 -050034
csharptest68d831e2011-05-03 13:47:34 -050035#endregion
36
37using System;
38using Google.ProtocolBuffers;
39using Google.ProtocolBuffers.TestProtos;
40using NUnit.Framework;
41
42namespace Google.ProtocolBuffers
43{
44 /// <summary>
45 /// This class verifies the correct code is generated from unittest_rpc_interop.proto and provides a small demonstration
46 /// of using the new IRpcDispatch to write a client/server
47 /// </summary>
48 [TestFixture]
49 public class TestRpcGenerator
50 {
csharptest71f662c2011-05-20 15:15:34 -050051 /// <summary>
52 /// A sample implementation of the ISearchService for testing
53 /// </summary>
54 private class ExampleSearchImpl : ISearchService
55 {
56 SearchResponse ISearchService.Search(SearchRequest searchRequest)
57 {
58 if (searchRequest.CriteriaCount == 0)
59 {
60 throw new ArgumentException("No criteria specified.", new InvalidOperationException());
61 }
62 SearchResponse.Builder resp = SearchResponse.CreateBuilder();
63 foreach (string criteria in searchRequest.CriteriaList)
64 {
65 resp.AddResults(
66 SearchResponse.Types.ResultItem.CreateBuilder().SetName(criteria).SetUrl("http://search.com").
67 Build());
68 }
69 return resp.Build();
csharptest68d831e2011-05-03 13:47:34 -050070 }
csharptest71f662c2011-05-20 15:15:34 -050071
72 SearchResponse ISearchService.RefineSearch(RefineSearchRequest refineSearchRequest)
73 {
74 SearchResponse.Builder resp = refineSearchRequest.PreviousResults.ToBuilder();
75 foreach (string criteria in refineSearchRequest.CriteriaList)
76 {
77 resp.AddResults(
78 SearchResponse.Types.ResultItem.CreateBuilder().SetName(criteria).SetUrl("http://refine.com").
79 Build());
80 }
81 return resp.Build();
csharptest68d831e2011-05-03 13:47:34 -050082 }
csharptest68d831e2011-05-03 13:47:34 -050083 }
84
csharptest71f662c2011-05-20 15:15:34 -050085 /// <summary>
86 /// An example extraction of the wire protocol
87 /// </summary>
88 private interface IWireTransfer
89 {
90 byte[] Execute(string method, byte[] message);
csharptest68d831e2011-05-03 13:47:34 -050091 }
csharptest68d831e2011-05-03 13:47:34 -050092
csharptest71f662c2011-05-20 15:15:34 -050093 /// <summary>
94 /// An example of a server responding to a wire request
95 /// </summary>
96 private class ExampleServerHost : IWireTransfer
97 {
98 private readonly IRpcServerStub _stub;
csharptest68d831e2011-05-03 13:47:34 -050099
csharptest71f662c2011-05-20 15:15:34 -0500100 public ExampleServerHost(ISearchService implementation)
101 {
102 //on the server, we create a dispatch to call the appropriate method by name
103 IRpcDispatch dispatch = new SearchService.Dispatch(implementation);
104 //we then wrap that dispatch in a server stub which will deserialize the wire bytes to the message
105 //type appropriate for the method name being invoked.
106 _stub = new SearchService.ServerStub(dispatch);
107 }
csharptest68d831e2011-05-03 13:47:34 -0500108
csharptest71f662c2011-05-20 15:15:34 -0500109 byte[] IWireTransfer.Execute(string method, byte[] message)
110 {
111 //now when we recieve a wire transmission to invoke a method by name with a byte[] or stream payload
112 //we just simply call the sub:
113 IMessageLite response = _stub.CallMethod(method, CodedInputStream.CreateInstance(message),
114 ExtensionRegistry.Empty);
115 //now we return the expected response message:
116 return response.ToByteArray();
117 }
118 }
csharptest68d831e2011-05-03 13:47:34 -0500119
csharptest71f662c2011-05-20 15:15:34 -0500120 /// <summary>
121 /// An example of a client sending a wire request
122 /// </summary>
123 private class ExampleClient : IRpcDispatch
124 {
125 private readonly IWireTransfer _wire;
csharptest68d831e2011-05-03 13:47:34 -0500126
csharptest71f662c2011-05-20 15:15:34 -0500127 public ExampleClient(IWireTransfer wire)
128 {
129 _wire = wire;
130 }
131
132 TMessage IRpcDispatch.CallMethod<TMessage, TBuilder>(string method, IMessageLite request,
133 IBuilderLite<TMessage, TBuilder> response)
134 {
135 byte[] rawResponse = _wire.Execute(method, request.ToByteArray());
136 response.MergeFrom(rawResponse);
137 return response.Build();
138 }
139 }
csharptest68d831e2011-05-03 13:47:34 -0500140
141 /// <summary>
142 /// Put it all together to create one seamless client/server experience full of rich-type goodness ;)
143 /// All you need to do is send/recieve the method name and message bytes across the wire.
144 /// </summary>
145 [Test]
146 public void TestClientServerDispatch()
147 {
148 ExampleServerHost server = new ExampleServerHost(new ExampleSearchImpl());
149 //obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting
150 IWireTransfer wire = server;
151
152 ISearchService client = new SearchService(new ExampleClient(wire));
153 //now the client has a real, typed, interface to work with:
154 SearchResponse result = client.Search(SearchRequest.CreateBuilder().AddCriteria("Test").Build());
155 Assert.AreEqual(1, result.ResultsCount);
156 Assert.AreEqual("Test", result.ResultsList[0].Name);
157 Assert.AreEqual("http://search.com", result.ResultsList[0].Url);
158
159 //The test part of this, call the only other method
csharptest71f662c2011-05-20 15:15:34 -0500160 result =
161 client.RefineSearch(
162 RefineSearchRequest.CreateBuilder().SetPreviousResults(result).AddCriteria("Refine").Build());
csharptest68d831e2011-05-03 13:47:34 -0500163 Assert.AreEqual(2, result.ResultsCount);
164 Assert.AreEqual("Test", result.ResultsList[0].Name);
165 Assert.AreEqual("http://search.com", result.ResultsList[0].Url);
166
167 Assert.AreEqual("Refine", result.ResultsList[1].Name);
168 Assert.AreEqual("http://refine.com", result.ResultsList[1].Url);
169 }
170 }
171}