Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Side by Side Diff: samples/tests/samples/src/proxy/MintMakerRpcTest.dart

Issue 10253022: test rename overhaul: step 13 - samples (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #library("mintmakerrpctest");
6 #import("dart:isolate");
7 #import("../../../../proxy/proxy.dart");
8
9 /***
10 * Background:
11 *
12 * There are two "target" classes here that are the actual implementation
13 * of some service that performs some function. These "target" classes
14 * do not know about ports, isolates or rpc. They expose a local (usually
15 * synchronous) interface to perform some task. In this example, the "target"
16 * classes are very simple:
17 *
18 * Mint - creates new Purse objects with an initial amount of money
19 * Purse - holds an amount of money, and supports making deposits
20 * by taking money out of another purse.
21 *
22 * The point of this example is to show how to create a new Dart isolate
23 * and run Mint and Purse objects in that isolate, and communicate with
24 * these objects with a SendPort/ReceivePort message/reply conversation,
25 * where command arguments are marshalled and unmarshalled by RpcProxy and
26 * RpcReceiver objects.
27 *
28 * This example also shows:
29 * 1. how the messages in the conversation can refer to target
30 * objects besides the direct recipient of the message
31 * 2. how target objects can throw exceptions and these are propagated back
32 * through the SendPort/ReceivePort channel and back to the Future
33 * object that is waiting for the reply.
34 *
35 * Classes:
36 *
37 * Mint - used to create Purse objects
38 * Purse - holds a bank balance, supports depositing money from another Purse
39 * MintReceiver - listens on a ReceivePort and forwards commands to Mint
40 * PurseReceiver - listens on a ReceivePort and forwards commands to Purse
41 * MintProxy - sends commands to a SendPort (which is connected to a
42 * MintReceiver)
43 * PurseProxy - sends commands to a SendPort (which is connected to a
44 * PurseReceiver)
45 * MintIsolate - used to spawn a new Isolate and return the initial MintProxy
46 *
47 * Base classes used: (these are defined in proxy.dart)
48 * RpcReceiver - MintReceiver and PurseReceiver derive from RpcReceiver to
49 * get behavior common to all Receivers.
50 * RpcProxy - MintProxy and PurseProxy derive from RpcProxy to get behavior
51 * common to all proxies
52 *
53 * Explanation:
54 *
55 * We make a "receiver" object (MintReceiver and PurseReceiver) for each
56 * target object that is being exposed. Each "receiver" object gets
57 * its own ReceivePort, where it listen for messages that it interprets
58 * as commands for its target object.
59 *
60 * When a command is received by a receiver, the receiver calls the appropriate
61 * method on the the target object. The receiver object runs in the same
62 * isolate as its target object. This isolate is called the "service" isolate.
63 *
64 * RpcProxy objects run in the "client" isolate. Each proxy object has a
65 * SendPort which is connected to the ReceivePort of a corresponding receiver
66 * object.
67 *
68 * So, a MintProxy object (running in the "client" isolate) is connected
69 * to a MintReceiver object (running in the "service" isolate) which is
70 * connected to a Mint target object (also running in the "service" isolate).
71 *
72 * Startup/Shutdown:
73 *
74 * The MintIsolate has a method open that spawns a new isolate and returns
75 * a MintProxy object.
76 *
77 * To shut down the MintIsolate, call 'close' on the MintProxy object. This
78 * will close all receive ports of all receivers in the isolate, which will
79 * cause the mint isolate to shutdown.
80 */
81
82 class Mint {
83 Mint();
84 Purse createPurse(int initialBalance) {
85 return new Purse(initialBalance);
86 }
87 }
88
89 class Purse {
90 int _balance;
91
92 Purse(this._balance) {}
93
94 int queryBalance() {
95 return _balance;
96 }
97
98 int deposit(int amount, Purse source) {
99 if (source._balance < amount) {
100 throw "OverdraftException";
101 }
102 source._balance -= amount;
103 _balance += amount;
104 return _balance;
105 }
106 }
107
108
109 class MintProxy extends RpcProxy {
110 MintProxy(Future<SendPort> sendPort) : super(sendPort) { }
111 Future<PurseProxy> createPurse(int initialBalance) {
112 return sendCommand("createPurse", [initialBalance], (sendPort) {
113 Completer<SendPort> completer = new Completer();
114 completer.complete(sendPort);
115 return new PurseProxy(completer.future);
116 });
117 }
118 Future<String> close() {
119 return sendCommand("close", null, null);
120 }
121 }
122
123 class MintReceiver extends RpcReceiver<Mint> {
124 MintReceiver(ReceivePort receivePort) : super(new Mint(), receivePort) {}
125 Object receiveCommand(String command, List args) {
126 switch(command) {
127 case "createPurse":
128 int balance = args[0];
129 Purse purse = target.createPurse(balance);
130 return new PurseReceiver(purse, new ReceivePort());
131 case "close":
132 RpcReceiver.closeAll();
133 return "close command processed";
134 default:
135 throw "MintReceiver unrecognized command";
136 }
137 }
138 }
139
140 class PurseProxy extends RpcProxy {
141 PurseProxy(Future<SendPort> sendPort) : super(sendPort) { }
142 Future<int> queryBalance() {
143 return sendCommand("queryBalance", null, null);
144 }
145 Future<int> deposit(int amount, PurseProxy from) {
146 return sendCommand("deposit", [amount, from], null);
147 }
148 }
149
150 class PurseReceiver extends RpcReceiver<Purse> {
151
152 PurseReceiver(Purse purse, ReceivePort receivePort) : super(purse, receivePort ) {}
153
154 Object receiveCommand(String command, List args) {
155 switch(command) {
156 case "queryBalance":
157 return target.queryBalance();
158 case "deposit":
159 int amount = args[0];
160 Purse fromPurse = args[1];
161 return target.deposit(amount, fromPurse);
162 default:
163 throw "PurseReceiver unrecognized command";
164 }
165 }
166 }
167
168 class MintIsolate extends Isolate {
169 MintIsolate() : super.light() {}
170
171 MintProxy open() {
172 return new MintProxy(spawn());
173 }
174
175 void main() {
176 // Note: 'super.' is needed here because the isolate library also defines a
177 // top-level port, and that port is resolved first.
178 ReceivePort receivePort = super.port;
179 new MintReceiver(receivePort);
180 }
181 }
182
183 class MintTest {
184 static void testMain() {
185 print("starting test");
186 MintProxy mint = new MintIsolate().open();
187 mint.createPurse(100).then((PurseProxy purse1) {
188 purse1.queryBalance().then((int balance) {
189 Expect.equals(100, balance);
190 mint.createPurse(0).then((PurseProxy purse2) {
191 purse2.queryBalance().then((int balance) {
192 Expect.equals(0, balance);
193 purse2.deposit(5, purse1).then((int newBalance) {
194 Expect.equals(0 + 5, newBalance);
195 purse1.queryBalance().then((int balance) {
196 Expect.equals(100 - 5, balance);
197 });
198 purse2.deposit(42, purse1).then((int newBalance) {
199 int balance2 = newBalance;
200 Expect.equals(0 + 5 + 42, balance2);
201 purse1.queryBalance().then((int balance) {
202 int balance1 = balance;
203 Expect.equals(100 - 5 - 42, balance);
204 // Now try to deposit more money into purse1 than
205 // is currently in purse2. Make sure we get an exception
206 // doing this.
207 Future<int> badBalance = purse1.deposit(1000, purse2);
208 badBalance.then((int newBalance) {
209 // Should never arrive here because there are
210 // insufficient funds to actually do the deposit
211 Expect.fail("did not detect overdraft");
212 });
213 badBalance.handleException((Object exception) {
214 if (exception.toString().contains(
215 "OverdraftException", 0)) {
216 print("Correctly detected overdraft.");
217 // Check that the balance in each purse is unchanged from
218 // before we attempted to do the overdraft.
219 purse1.queryBalance().then((int balance) {
220 Expect.equals(balance, balance1);
221 purse2.queryBalance().then((int balance) {
222 Expect.equals(balance, balance2);
223 // OK, we're all done now, close down the mint isolate
224 mint.close().then((reply) {
225 print(reply);
226 });
227 });
228 });
229 return true;
230 } else {
231 return false;
232 }
233 });
234 });
235 });
236 });
237 });
238 });
239 });
240 });
241 print ("exit main");
242 }
243 }
244
245 main() {
246 MintTest.testMain();
247 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698