178 lines
6.1 KiB
Dart
178 lines
6.1 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:pj_supermarket_cloud/common/utils/discounts/checkout_discount_session.dart';
|
|
|
|
const _key = CheckoutDiscountKey(tenantId: '1', hardId: '10', userId: '100');
|
|
|
|
void main() {
|
|
test('同结算的并发优惠查询合并,成功规则供后续计算复用', () async {
|
|
final session = CheckoutDiscountSession<int>();
|
|
final source = Completer<List<int>>();
|
|
var calls = 0;
|
|
Future<List<int>> lookup() {
|
|
calls++;
|
|
return source.future;
|
|
}
|
|
|
|
final first = session.load(key: _key, lookup: lookup);
|
|
final second = session.load(key: _key, lookup: lookup);
|
|
expect(identical(first, second), isTrue);
|
|
source.complete([7]);
|
|
expect(await first, [7]);
|
|
expect(await second, [7]);
|
|
expect(await session.load(key: _key, lookup: lookup), [7]);
|
|
expect(calls, 1);
|
|
});
|
|
|
|
test('成功的空优惠同样缓存,不会重复请求或变成失败结果', () async {
|
|
final session = CheckoutDiscountSession<int>();
|
|
var calls = 0;
|
|
Future<List<int>> lookup() async {
|
|
calls++;
|
|
return [];
|
|
}
|
|
|
|
final empty = await session.load(key: _key, lookup: lookup);
|
|
expect(empty, isEmpty);
|
|
expect(() => empty.add(1), throwsUnsupportedError);
|
|
expect(await session.load(key: _key, lookup: lookup), isEmpty);
|
|
expect(calls, 1);
|
|
});
|
|
|
|
test('过期刷新失败向上传播,不返回旧优惠,下一次会重新查询', () async {
|
|
var elapsed = Duration.zero;
|
|
final session = CheckoutDiscountSession<int>(elapsed: () => elapsed);
|
|
var calls = 0;
|
|
final failure = StateError('lookup rejected');
|
|
Future<List<int>> lookup() async {
|
|
calls++;
|
|
if (calls == 2) throw failure;
|
|
return [calls];
|
|
}
|
|
|
|
expect(await session.load(key: _key, lookup: lookup), [1]);
|
|
elapsed = const Duration(seconds: 30);
|
|
await expectLater(
|
|
session.load(key: _key, lookup: lookup), throwsA(same(failure)));
|
|
expect(await session.load(key: _key, lookup: lookup), [3]);
|
|
expect(calls, 3);
|
|
});
|
|
|
|
test('租户、设备、人员和结算实例之间不共用规则', () async {
|
|
final session = CheckoutDiscountSession<int>();
|
|
var calls = 0;
|
|
Future<List<int>> lookup() async => [++calls];
|
|
for (final key in [
|
|
_key,
|
|
const CheckoutDiscountKey(tenantId: '2', hardId: '10', userId: '100'),
|
|
const CheckoutDiscountKey(tenantId: '1', hardId: '11', userId: '100'),
|
|
const CheckoutDiscountKey(tenantId: '1', hardId: '10', userId: '101'),
|
|
]) {
|
|
await session.load(key: key, lookup: lookup);
|
|
}
|
|
await CheckoutDiscountSession<int>().load(key: _key, lookup: lookup);
|
|
expect(calls, 5);
|
|
});
|
|
|
|
test('失效前的迟到结果不能覆盖新请求或清掉新查询', () async {
|
|
final session = CheckoutDiscountSession<int>();
|
|
final old = Completer<List<int>>();
|
|
final next = Completer<List<int>>();
|
|
var calls = 0;
|
|
Future<List<int>> lookup() => ++calls == 1 ? old.future : next.future;
|
|
final first = session.load(key: _key, lookup: lookup);
|
|
session.invalidate();
|
|
final second = session.load(key: _key, lookup: lookup);
|
|
old.complete([1]);
|
|
expect(await first, [1]);
|
|
expect(identical(session.load(key: _key, lookup: lookup), second), isTrue);
|
|
next.complete([2]);
|
|
expect(await second, [2]);
|
|
expect(await session.load(key: _key, lookup: lookup), [2]);
|
|
expect(calls, 2);
|
|
});
|
|
|
|
test('旧代次的迟到成功结果不能执行离线快照持久化', () async {
|
|
final session = CheckoutDiscountSession<int>();
|
|
final old = Completer<List<int>>();
|
|
final persisted = <List<int>>[];
|
|
Future<void> persist(List<int> rules) async => persisted.add(rules);
|
|
final oldRequest = session.load(
|
|
key: _key,
|
|
lookup: () => old.future,
|
|
onAccepted: persist,
|
|
);
|
|
session.invalidate();
|
|
expect(
|
|
await session.load(
|
|
key: _key, lookup: () async => [2], onAccepted: persist),
|
|
[2]);
|
|
old.complete([1]);
|
|
expect(await oldRequest, [1]);
|
|
expect(persisted, [
|
|
[2]
|
|
]);
|
|
});
|
|
|
|
test('同一人员切换设备或租户时,旧上下文查询自动失效且不能写离线规则', () async {
|
|
for (final nextKey in [
|
|
const CheckoutDiscountKey(tenantId: '1', hardId: '11', userId: '100'),
|
|
const CheckoutDiscountKey(tenantId: '2', hardId: '10', userId: '100'),
|
|
]) {
|
|
final session = CheckoutDiscountSession<int>();
|
|
final old = Completer<List<int>>();
|
|
final persisted = <List<int>>[];
|
|
Future<void> persist(List<int> rules) async => persisted.add(rules);
|
|
final oldRequest = session.load(
|
|
key: _key,
|
|
lookup: () => old.future,
|
|
onAccepted: persist,
|
|
);
|
|
expect(
|
|
await session.load(
|
|
key: nextKey,
|
|
lookup: () async => [2],
|
|
onAccepted: persist,
|
|
),
|
|
[2]);
|
|
old.complete([1]);
|
|
expect(await oldRequest, [1]);
|
|
expect(persisted, [
|
|
[2]
|
|
]);
|
|
// 切回原上下文也必须重新读取,不能复用其已经作废的迟到结果。
|
|
expect(
|
|
await session.load(
|
|
key: _key,
|
|
lookup: () async => [3],
|
|
onAccepted: persist,
|
|
),
|
|
[3]);
|
|
expect(persisted, [
|
|
[2],
|
|
[3]
|
|
]);
|
|
}
|
|
});
|
|
|
|
test('有效期从成功完成计算,单调时钟回退不会提前复用过期结果', () async {
|
|
var elapsed = Duration.zero;
|
|
final session = CheckoutDiscountSession<int>(elapsed: () => elapsed);
|
|
final source = Completer<List<int>>();
|
|
final first = session.load(key: _key, lookup: () => source.future);
|
|
elapsed = const Duration(seconds: 29);
|
|
source.complete([1]);
|
|
await first;
|
|
var calls = 0;
|
|
Future<List<int>> refresh() async => [++calls + 1];
|
|
elapsed = const Duration(seconds: 50);
|
|
expect(await session.load(key: _key, lookup: refresh), [1]);
|
|
elapsed = const Duration(seconds: 59);
|
|
expect(await session.load(key: _key, lookup: refresh), [2]);
|
|
elapsed = const Duration(seconds: 5);
|
|
expect(await session.load(key: _key, lookup: refresh), [2]);
|
|
expect(calls, 1);
|
|
});
|
|
}
|