OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2017, 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:async/async.dart'; |
| 8 import 'package:fake_async/fake_async.dart'; |
| 9 import 'package:test/test.dart'; |
| 10 |
| 11 void main() { |
| 12 AsyncCache<String> cache; |
| 13 |
| 14 setUp(() { |
| 15 // Create a cache that is fresh for an hour. |
| 16 cache = new AsyncCache(const Duration(hours: 1)); |
| 17 }); |
| 18 |
| 19 test('should fetch via a callback when no cache exists', () async { |
| 20 expect(await cache.fetch(() async => 'Expensive'), 'Expensive'); |
| 21 }); |
| 22 |
| 23 test('should not fetch via callback when a cache exists', () async { |
| 24 await cache.fetch(() async => 'Expensive'); |
| 25 expect(await cache.fetch(expectAsync0(() {}, count: 0)), 'Expensive'); |
| 26 }); |
| 27 |
| 28 test('should not fetch via callback when a future is in-flight', () async { |
| 29 // No actual caching is done, just avoid duplicate requests. |
| 30 cache = new AsyncCache.ephemeral(); |
| 31 |
| 32 var completer = new Completer<String>(); |
| 33 expect(cache.fetch(() => completer.future), completion('Expensive')); |
| 34 expect(cache.fetch(expectAsync0(() {}, count: 0)), completion('Expensive')); |
| 35 await completer.complete('Expensive'); |
| 36 }); |
| 37 |
| 38 test('should fetch via a callback again when cache expires', () { |
| 39 new FakeAsync().run((fakeAsync) async { |
| 40 var timesCalled = 0; |
| 41 call() async => 'Called ${++timesCalled}'; |
| 42 expect(await cache.fetch(call), 'Called 1'); |
| 43 expect(await cache.fetch(call), 'Called 1', reason: 'Cache still fresh'); |
| 44 |
| 45 fakeAsync.elapse(const Duration(hours: 1) - const Duration(seconds: 1)); |
| 46 expect(await cache.fetch(call), 'Called 1', reason: 'Cache still fresh'); |
| 47 |
| 48 fakeAsync.elapse(const Duration(seconds: 1)); |
| 49 expect(await cache.fetch(call), 'Called 2'); |
| 50 expect(await cache.fetch(call), 'Called 2', reason: 'Cache fresh again'); |
| 51 |
| 52 fakeAsync.elapse(const Duration(hours: 1)); |
| 53 expect(await cache.fetch(call), 'Called 3'); |
| 54 }); |
| 55 }); |
| 56 |
| 57 test('should fetch via a callback when manually invalidated', () async { |
| 58 var timesCalled = 0; |
| 59 call() async => 'Called ${++timesCalled}'; |
| 60 expect(await cache.fetch(call), 'Called 1'); |
| 61 await cache.invalidate(); |
| 62 expect(await cache.fetch(call), 'Called 2'); |
| 63 await cache.invalidate(); |
| 64 expect(await cache.fetch(call), 'Called 3'); |
| 65 }); |
| 66 |
| 67 test('should fetch a stream via a callback', () async { |
| 68 expect( |
| 69 await cache.fetchStream(expectAsync0(() { |
| 70 return new Stream.fromIterable(['1', '2', '3']); |
| 71 })).toList(), |
| 72 ['1', '2', '3']); |
| 73 }); |
| 74 |
| 75 test('should not fetch stream via callback when a cache exists', () async { |
| 76 await cache.fetchStream(() async* { |
| 77 yield '1'; |
| 78 yield '2'; |
| 79 yield '3'; |
| 80 }).toList(); |
| 81 expect(await cache.fetchStream(expectAsync0(() {}, count: 0)).toList(), |
| 82 ['1', '2', '3']); |
| 83 }); |
| 84 |
| 85 test('should not fetch stream via callback when request in flight', () async { |
| 86 // Unlike the above test, we want to verify that we don't make multiple |
| 87 // calls if a cache is being filled currently, and instead wait for that |
| 88 // cache to be completed. |
| 89 var controller = new StreamController<String>(); |
| 90 Stream<String> call() => controller.stream; |
| 91 expect(cache.fetchStream(call).toList(), completion(['1', '2', '3'])); |
| 92 controller.add('1'); |
| 93 controller.add('2'); |
| 94 await new Future.value(); |
| 95 expect(cache.fetchStream(call).toList(), completion(['1', '2', '3'])); |
| 96 controller.add('3'); |
| 97 await controller.close(); |
| 98 }); |
| 99 |
| 100 test('should fetch stream via a callback again when cache expires', () { |
| 101 new FakeAsync().run((fakeAsync) async { |
| 102 var timesCalled = 0; |
| 103 Stream<String> call() { |
| 104 return new Stream.fromIterable(['Called ${++timesCalled}']); |
| 105 } |
| 106 |
| 107 expect(await cache.fetchStream(call).toList(), ['Called 1']); |
| 108 expect(await cache.fetchStream(call).toList(), ['Called 1'], |
| 109 reason: 'Cache still fresh'); |
| 110 |
| 111 fakeAsync.elapse(const Duration(hours: 1) - const Duration(seconds: 1)); |
| 112 expect(await cache.fetchStream(call).toList(), ['Called 1'], |
| 113 reason: 'Cache still fresh'); |
| 114 |
| 115 fakeAsync.elapse(const Duration(seconds: 1)); |
| 116 expect(await cache.fetchStream(call).toList(), ['Called 2']); |
| 117 expect(await cache.fetchStream(call).toList(), ['Called 2'], |
| 118 reason: 'Cache fresh again'); |
| 119 |
| 120 fakeAsync.elapse(const Duration(hours: 1)); |
| 121 expect(await cache.fetchStream(call).toList(), ['Called 3']); |
| 122 }); |
| 123 }); |
| 124 |
| 125 test('should fetch via a callback when manually invalidated', () async { |
| 126 var timesCalled = 0; |
| 127 Stream<String> call() { |
| 128 return new Stream.fromIterable(['Called ${++timesCalled}']); |
| 129 } |
| 130 |
| 131 expect(await cache.fetchStream(call).toList(), ['Called 1']); |
| 132 await cache.invalidate(); |
| 133 expect(await cache.fetchStream(call).toList(), ['Called 2']); |
| 134 await cache.invalidate(); |
| 135 expect(await cache.fetchStream(call).toList(), ['Called 3']); |
| 136 }); |
| 137 |
| 138 test('should cancel a cached stream without affecting others', () async { |
| 139 Stream<String> call() => new Stream.fromIterable(['1', '2', '3']); |
| 140 |
| 141 expect(cache.fetchStream(call).toList(), completion(['1', '2', '3'])); |
| 142 |
| 143 // Listens to the stream for the initial value, then cancels subscription. |
| 144 expect(await cache.fetchStream(call).first, '1'); |
| 145 }); |
| 146 |
| 147 test('should pause a cached stream without affecting others', () async { |
| 148 Stream<String> call() => new Stream.fromIterable(['1', '2', '3']); |
| 149 |
| 150 StreamSubscription sub; |
| 151 sub = cache.fetchStream(call).listen(expectAsync1((event) { |
| 152 if (event == '1') sub.pause(); |
| 153 })); |
| 154 expect(cache.fetchStream(call).toList(), completion(['1', '2', '3'])); |
| 155 }); |
| 156 } |
OLD | NEW |