Files
pj_supermarket_cloud/test/checkout_discount_session_test.dart
T

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);
});
}