OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, 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 import 'dart:async'; |
| 6 |
| 7 import 'package:fake_async/fake_async.dart'; |
| 8 import 'package:pool/pool.dart'; |
| 9 import 'package:stack_trace/stack_trace.dart'; |
| 10 import 'package:test/test.dart'; |
| 11 |
| 12 void main() { |
| 13 group("request()", () { |
| 14 test("resources can be requested freely up to the limit", () { |
| 15 var pool = new Pool(50); |
| 16 for (var i = 0; i < 50; i++) { |
| 17 expect(pool.request(), completes); |
| 18 } |
| 19 }); |
| 20 |
| 21 test("resources block past the limit", () { |
| 22 new FakeAsync().run((async) { |
| 23 var pool = new Pool(50); |
| 24 for (var i = 0; i < 50; i++) { |
| 25 expect(pool.request(), completes); |
| 26 } |
| 27 expect(pool.request(), doesNotComplete); |
| 28 |
| 29 async.elapse(new Duration(seconds: 1)); |
| 30 }); |
| 31 }); |
| 32 |
| 33 test("a blocked resource is allocated when another is released", () { |
| 34 new FakeAsync().run((async) { |
| 35 var pool = new Pool(50); |
| 36 for (var i = 0; i < 49; i++) { |
| 37 expect(pool.request(), completes); |
| 38 } |
| 39 |
| 40 pool.request().then((lastAllocatedResource) { |
| 41 // This will only complete once [lastAllocatedResource] is released. |
| 42 expect(pool.request(), completes); |
| 43 |
| 44 new Future.delayed(new Duration(microseconds: 1)).then((_) { |
| 45 lastAllocatedResource.release(); |
| 46 }); |
| 47 }); |
| 48 |
| 49 async.elapse(new Duration(seconds: 1)); |
| 50 }); |
| 51 }); |
| 52 }); |
| 53 |
| 54 group("withResource()", () { |
| 55 test("can be called freely up to the limit", () { |
| 56 var pool = new Pool(50); |
| 57 for (var i = 0; i < 50; i++) { |
| 58 pool.withResource(expectAsync(() => new Completer().future)); |
| 59 } |
| 60 }); |
| 61 |
| 62 test("blocks the callback past the limit", () { |
| 63 new FakeAsync().run((async) { |
| 64 var pool = new Pool(50); |
| 65 for (var i = 0; i < 50; i++) { |
| 66 pool.withResource(expectAsync(() => new Completer().future)); |
| 67 } |
| 68 pool.withResource(expectNoAsync()); |
| 69 |
| 70 async.elapse(new Duration(seconds: 1)); |
| 71 }); |
| 72 }); |
| 73 |
| 74 test("a blocked resource is allocated when another is released", () { |
| 75 new FakeAsync().run((async) { |
| 76 var pool = new Pool(50); |
| 77 for (var i = 0; i < 49; i++) { |
| 78 pool.withResource(expectAsync(() => new Completer().future)); |
| 79 } |
| 80 |
| 81 var completer = new Completer(); |
| 82 pool.withResource(() => completer.future); |
| 83 var blockedResourceAllocated = false; |
| 84 pool.withResource(() { |
| 85 blockedResourceAllocated = true; |
| 86 }); |
| 87 |
| 88 new Future.delayed(new Duration(microseconds: 1)).then((_) { |
| 89 expect(blockedResourceAllocated, isFalse); |
| 90 completer.complete(); |
| 91 return new Future.delayed(new Duration(microseconds: 1)); |
| 92 }).then((_) { |
| 93 expect(blockedResourceAllocated, isTrue); |
| 94 }); |
| 95 |
| 96 async.elapse(new Duration(seconds: 1)); |
| 97 }); |
| 98 }); |
| 99 }); |
| 100 |
| 101 group("with a timeout", () { |
| 102 test("doesn't time out if there are no pending requests", () { |
| 103 new FakeAsync().run((async) { |
| 104 var pool = new Pool(50, timeout: new Duration(seconds: 5)); |
| 105 for (var i = 0; i < 50; i++) { |
| 106 expect(pool.request(), completes); |
| 107 } |
| 108 |
| 109 async.elapse(new Duration(seconds: 6)); |
| 110 }); |
| 111 }); |
| 112 |
| 113 test("resets the timer if a resource is returned", () { |
| 114 new FakeAsync().run((async) { |
| 115 var pool = new Pool(50, timeout: new Duration(seconds: 5)); |
| 116 for (var i = 0; i < 49; i++) { |
| 117 expect(pool.request(), completes); |
| 118 } |
| 119 |
| 120 pool.request().then((lastAllocatedResource) { |
| 121 // This will only complete once [lastAllocatedResource] is released. |
| 122 expect(pool.request(), completes); |
| 123 |
| 124 new Future.delayed(new Duration(seconds: 3)).then((_) { |
| 125 lastAllocatedResource.release(); |
| 126 expect(pool.request(), doesNotComplete); |
| 127 }); |
| 128 }); |
| 129 |
| 130 async.elapse(new Duration(seconds: 6)); |
| 131 }); |
| 132 }); |
| 133 |
| 134 test("resets the timer if a resource is requested", () { |
| 135 new FakeAsync().run((async) { |
| 136 var pool = new Pool(50, timeout: new Duration(seconds: 5)); |
| 137 for (var i = 0; i < 50; i++) { |
| 138 expect(pool.request(), completes); |
| 139 } |
| 140 expect(pool.request(), doesNotComplete); |
| 141 |
| 142 new Future.delayed(new Duration(seconds: 3)).then((_) { |
| 143 expect(pool.request(), doesNotComplete); |
| 144 }); |
| 145 |
| 146 async.elapse(new Duration(seconds: 6)); |
| 147 }); |
| 148 }); |
| 149 |
| 150 test("times out if nothing happens", () { |
| 151 new FakeAsync().run((async) { |
| 152 var pool = new Pool(50, timeout: new Duration(seconds: 5)); |
| 153 for (var i = 0; i < 50; i++) { |
| 154 expect(pool.request(), completes); |
| 155 } |
| 156 expect(pool.request(), throwsA(new isInstanceOf<TimeoutException>())); |
| 157 |
| 158 async.elapse(new Duration(seconds: 6)); |
| 159 }); |
| 160 }); |
| 161 }); |
| 162 |
| 163 group("allowRelease()", () { |
| 164 test("runs the callback once the resource limit is exceeded", () async { |
| 165 var pool = new Pool(50); |
| 166 var requests = []; |
| 167 for (var i = 0; i < 49; i++) { |
| 168 expect(pool.request(), completes); |
| 169 } |
| 170 |
| 171 var resource = await pool.request(); |
| 172 var onReleaseCalled = false; |
| 173 resource.allowRelease(() => onReleaseCalled = true); |
| 174 await new Future.delayed(Duration.ZERO); |
| 175 expect(onReleaseCalled, isFalse); |
| 176 |
| 177 expect(pool.request(), completes); |
| 178 await new Future.delayed(Duration.ZERO); |
| 179 expect(onReleaseCalled, isTrue); |
| 180 }); |
| 181 |
| 182 test("runs the callback immediately if there are blocked requests", |
| 183 () async { |
| 184 var pool = new Pool(1); |
| 185 var resource = await pool.request(); |
| 186 |
| 187 // This will be blocked until [resource.allowRelease] is called. |
| 188 expect(pool.request(), completes); |
| 189 |
| 190 var onReleaseCalled = false; |
| 191 resource.allowRelease(() => onReleaseCalled = true); |
| 192 await new Future.delayed(Duration.ZERO); |
| 193 expect(onReleaseCalled, isTrue); |
| 194 }); |
| 195 |
| 196 test("blocks the request until the callback completes", () async { |
| 197 var pool = new Pool(1); |
| 198 var resource = await pool.request(); |
| 199 |
| 200 var requestComplete = false; |
| 201 pool.request().then((_) => requestComplete = true); |
| 202 |
| 203 var completer = new Completer(); |
| 204 resource.allowRelease(() => completer.future); |
| 205 await new Future.delayed(Duration.ZERO); |
| 206 expect(requestComplete, isFalse); |
| 207 |
| 208 completer.complete(); |
| 209 await new Future.delayed(Duration.ZERO); |
| 210 expect(requestComplete, isTrue); |
| 211 }); |
| 212 |
| 213 test("completes requests in request order regardless of callback order", |
| 214 () async { |
| 215 var pool = new Pool(2); |
| 216 var resource1 = await pool.request(); |
| 217 var resource2 = await pool.request(); |
| 218 |
| 219 var request1Complete = false; |
| 220 pool.request().then((_) => request1Complete = true); |
| 221 var request2Complete = false; |
| 222 pool.request().then((_) => request2Complete = true); |
| 223 |
| 224 var onRelease1Called = false; |
| 225 var completer1 = new Completer(); |
| 226 resource1.allowRelease(() { |
| 227 onRelease1Called = true; |
| 228 return completer1.future; |
| 229 }); |
| 230 await new Future.delayed(Duration.ZERO); |
| 231 expect(onRelease1Called, isTrue); |
| 232 |
| 233 var onRelease2Called = false; |
| 234 var completer2 = new Completer(); |
| 235 resource2.allowRelease(() { |
| 236 onRelease2Called = true; |
| 237 return completer2.future; |
| 238 }); |
| 239 await new Future.delayed(Duration.ZERO); |
| 240 expect(onRelease2Called, isTrue); |
| 241 expect(request1Complete, isFalse); |
| 242 expect(request2Complete, isFalse); |
| 243 |
| 244 // Complete the second resource's onRelease callback first. Even though it |
| 245 // was triggered by the second blocking request, it should complete the |
| 246 // first one to preserve ordering. |
| 247 completer2.complete(); |
| 248 await new Future.delayed(Duration.ZERO); |
| 249 expect(request1Complete, isTrue); |
| 250 expect(request2Complete, isFalse); |
| 251 |
| 252 completer1.complete(); |
| 253 await new Future.delayed(Duration.ZERO); |
| 254 expect(request1Complete, isTrue); |
| 255 expect(request2Complete, isTrue); |
| 256 }); |
| 257 |
| 258 test("runs onRequest in the zone it was created", () async { |
| 259 var pool = new Pool(1); |
| 260 var resource = await pool.request(); |
| 261 |
| 262 var outerZone = Zone.current; |
| 263 runZoned(() { |
| 264 var innerZone = Zone.current; |
| 265 expect(innerZone, isNot(equals(outerZone))); |
| 266 |
| 267 resource.allowRelease(expectAsync(() { |
| 268 expect(Zone.current, equals(innerZone)); |
| 269 })); |
| 270 }); |
| 271 |
| 272 pool.request(); |
| 273 }); |
| 274 }); |
| 275 } |
| 276 |
| 277 /// Returns a function that will cause the test to fail if it's called. |
| 278 /// |
| 279 /// This should only be called within a [FakeAsync.run] zone. |
| 280 Function expectNoAsync() { |
| 281 var stack = new Trace.current(1); |
| 282 return () => registerException( |
| 283 new TestFailure("Expected function not to be called."), stack); |
| 284 } |
| 285 |
| 286 /// A matcher for Futures that asserts that they don't complete. |
| 287 /// |
| 288 /// This should only be called within a [FakeAsync.run] zone. |
| 289 Matcher get doesNotComplete => predicate((future) { |
| 290 expect(future, new isInstanceOf<Future>()); |
| 291 |
| 292 var stack = new Trace.current(1); |
| 293 future.then((_) => registerException( |
| 294 new TestFailure("Expected future not to complete."), stack)); |
| 295 return true; |
| 296 }); |
OLD | NEW |