yx_tracking_flutter/test/validator_test.dart

204 lines
5.6 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:yx_tracking_flutter/src/config/analytics_config.dart';
import 'package:yx_tracking_flutter/src/config/config_manager.dart';
import 'package:yx_tracking_flutter/src/core/validator.dart';
import 'package:yx_tracking_flutter/src/model/device_info.dart';
import 'package:yx_tracking_flutter/src/model/event.dart';
import 'package:yx_tracking_flutter/src/model/system_dim_info.dart';
class StaticConfigManager extends ConfigManager {
StaticConfigManager({
required super.config,
required SystemDimInfo configValue,
}) : _configValue = configValue,
super(refreshInterval: Duration.zero);
final SystemDimInfo _configValue;
@override
SystemDimInfo? get currentConfig => _configValue;
@override
Future<void> init() async {}
@override
Future<void> fetchAndCacheConfig({bool force = false}) async {}
@override
Future<void> forceRefresh() async {}
@override
Future<void> dispose() async {}
}
const DeviceInfo _device = DeviceInfo(
os: 'test',
model: 'test',
screenResolution: '1x1',
);
AnalyticsConfig _config() {
return AnalyticsConfig(
systemCode: 'TEST_APP',
endpointBaseUrl: 'https://example.com',
enableMetrics: false,
);
}
Event _event({
required String type,
Map<String, dynamic>? customTags,
}) {
final now = DateTime.now();
final ts = now.millisecondsSinceEpoch;
return Event(
systemCode: 'TEST_APP',
eventType: type,
userInfo: null,
clientType: 3,
clientTimestamp: ts,
timestamp: now.toUtc().toIso8601String(),
deviceInfo: _device,
eventParams: null,
customTags: customTags,
createTime: now,
);
}
SystemDimInfo _dimInfo() {
return SystemDimInfo(
systemInfo: const SystemInfo(raw: <String, dynamic>{}),
eventDefinitions: const <EventDefinition>[
EventDefinition(eventCode: 'KNOWN'),
],
tagDefinitions: const <TagDefinition>[
TagDefinition(tagName: 'tenantId', tagType: 'string', isRequired: true),
TagDefinition(tagName: 'count', tagType: 'int', isRequired: false),
],
sdkStrategy: null,
lastFetchedAt: DateTime.now(),
);
}
SystemDimInfo _dimInfoWithTypes() {
return SystemDimInfo(
systemInfo: const SystemInfo(raw: <String, dynamic>{}),
eventDefinitions: const <EventDefinition>[
EventDefinition(eventCode: 'TYPED'),
],
tagDefinitions: const <TagDefinition>[
TagDefinition(tagName: 'intNum', tagType: 'int', isRequired: true),
TagDefinition(tagName: 'intStr', tagType: 'integer', isRequired: true),
TagDefinition(tagName: 'boolNum', tagType: 'bool', isRequired: true),
TagDefinition(tagName: 'boolStr', tagType: 'boolean', isRequired: true),
TagDefinition(tagName: 'doubleStr', tagType: 'double', isRequired: true),
TagDefinition(tagName: 'floatStr', tagType: 'float', isRequired: true),
TagDefinition(tagName: 'numStr', tagType: 'num', isRequired: true),
TagDefinition(tagName: 'unknown', tagType: 'mystery', isRequired: false),
],
sdkStrategy: null,
lastFetchedAt: DateTime.now(),
);
}
bool _isTypeMismatch(ValidationIssue issue) =>
issue.code == Validator.typeMismatch;
void main() {
group('Validator', () {
test('已配置事件且必填 tag 满足时无告警', () {
final manager = StaticConfigManager(
config: _config(),
configValue: _dimInfo(),
);
final validator = Validator(manager);
final result = validator.validate(
_event(
type: 'KNOWN',
customTags: const <String, dynamic>{'tenantId': 't1'},
),
);
expect(result.isEmpty, true);
});
test('未知事件会产生 error', () {
final manager = StaticConfigManager(
config: _config(),
configValue: _dimInfo(),
);
final validator = Validator(manager);
final result = validator.validate(_event(type: 'UNKNOWN'));
expect(result.hasErrors, true);
expect(result.errors.first.code, Validator.unknownEventType);
});
test('缺失必填 tag 会产生 warning', () {
final manager = StaticConfigManager(
config: _config(),
configValue: _dimInfo(),
);
final validator = Validator(manager);
final result = validator.validate(_event(type: 'KNOWN'));
expect(result.hasWarnings, true);
expect(result.warnings.first.code, Validator.missingRequiredTag);
});
test('类型不匹配会产生 warning', () {
final manager = StaticConfigManager(
config: _config(),
configValue: _dimInfo(),
);
final validator = Validator(manager);
final result = validator.validate(
_event(
type: 'KNOWN',
customTags: const <String, dynamic>{
'tenantId': 't1',
'count': 'not-an-int',
},
),
);
expect(result.hasWarnings, true);
expect(
result.warnings.any(_isTypeMismatch),
true,
);
});
test('多类型匹配路径均可通过', () {
final manager = StaticConfigManager(
config: _config(),
configValue: _dimInfoWithTypes(),
);
final validator = Validator(manager);
final result = validator.validate(
_event(
type: 'TYPED',
customTags: const <String, dynamic>{
'intNum': 1.0,
'intStr': '2',
'boolNum': 0,
'boolStr': 'no',
'doubleStr': '3.14',
'floatStr': '2.72',
'numStr': '42',
'unknown': <String, dynamic>{'any': 'value'},
},
),
);
expect(result.hasErrors, false);
expect(result.hasWarnings, false);
});
});
}