swagger_generator_flutter/tests/performance_test.dart

489 lines
15 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:swagger_generator_flutter/core/models.dart';
import 'package:swagger_generator_flutter/core/performance_parser.dart';
import 'package:swagger_generator_flutter/core/smart_cache.dart';
import 'package:swagger_generator_flutter/generators/performance_generator.dart';
import 'package:test/test.dart';
void main() {
group('Performance Tests', () {
group('PerformanceParser', () {
late PerformanceParser parser;
setUp(() {
parser = PerformanceParser(
config: ParseConfig(
enableParallelParsing: true,
enableStreamParsing: false,
enablePerformanceStats: true,
maxConcurrency: 4,
),
);
});
test('parses document with performance tracking', () async {
final jsonString = jsonEncode({
'openapi': '3.0.3',
'info': {
'title': 'Test API',
'version': '1.0.0',
},
'paths': {
'/users': {
'get': {
'summary': 'Get users',
'responses': {
'200': {
'description': 'Success',
},
},
},
},
},
});
final document = await parser.parseDocument(jsonString);
expect(document.title, equals('Test API'));
expect(document.version, equals('1.0.0'));
expect(document.paths, hasLength(1));
final stats = parser.lastStats;
expect(stats, isNotNull);
expect(stats!.totalTime.inMicroseconds, greaterThan(0));
expect(stats.documentSize, equals(jsonString.length));
expect(stats.pathCount, equals(1));
});
test('handles large documents efficiently', () async {
// 创建大型文档
final paths = <String, dynamic>{};
for (int i = 0; i < 100; i++) {
paths['/api/v1/resource$i'] = {
'get': {
'summary': 'Get resource $i',
'responses': {
'200': {'description': 'Success'},
},
},
'post': {
'summary': 'Create resource $i',
'responses': {
'201': {'description': 'Created'},
},
},
};
}
final largeDoc = {
'openapi': '3.0.3',
'info': {
'title': 'Large API',
'version': '1.0.0',
},
'paths': paths,
};
final jsonString = jsonEncode(largeDoc);
final stopwatch = Stopwatch()..start();
final document = await parser.parseDocument(jsonString);
stopwatch.stop();
expect(document.paths.length, greaterThan(50)); // 应该解析出多个路径
expect(stopwatch.elapsedMilliseconds, lessThan(5000)); // 应该在5秒内完成
final stats = parser.lastStats;
expect(stats, isNotNull);
expect(stats!.pathsPerSecond, greaterThan(10)); // 每秒至少处理10个路径
});
test('parallel parsing improves performance', () async {
final sequentialParser = PerformanceParser(
config: ParseConfig(
enableParallelParsing: false,
enablePerformanceStats: true,
),
);
final parallelParser = PerformanceParser(
config: ParseConfig(
enableParallelParsing: true,
enablePerformanceStats: true,
maxConcurrency: 4,
),
);
// 创建中等大小的文档
final paths = <String, dynamic>{};
for (int i = 0; i < 50; i++) {
paths['/api/v1/resource$i'] = {
'get': {
'summary': 'Get resource $i',
'responses': {
'200': {'description': 'Success'}
},
},
};
}
final doc = {
'openapi': '3.0.3',
'info': {'title': 'Test API', 'version': '1.0.0'},
'paths': paths,
};
final jsonString = jsonEncode(doc);
// 顺序解析
await sequentialParser.parseDocument(jsonString);
final sequentialTime = sequentialParser.lastStats!.totalTime;
// 并行解析
await parallelParser.parseDocument(jsonString);
final parallelTime = parallelParser.lastStats!.totalTime;
// 并行解析应该更快(在有足够任务的情况下)
print('Sequential: ${sequentialTime.inMilliseconds}ms');
print('Parallel: ${parallelTime.inMilliseconds}ms');
// 注意:在小型文档上,并行可能不会更快,因为开销
expect(parallelTime.inMilliseconds,
lessThan(sequentialTime.inMilliseconds * 2));
});
});
group('SmartCache', () {
late SmartCache<String> cache;
setUp(() {
cache = SmartCache<String>(
maxSize: 10,
strategy: CacheStrategy.smart,
defaultTtl: Duration(seconds: 1),
);
});
test('basic cache operations work correctly', () {
cache.put('key1', 'value1');
expect(cache.get('key1'), equals('value1'));
expect(cache.containsKey('key1'), isTrue);
cache.remove('key1');
expect(cache.get('key1'), isNull);
expect(cache.containsKey('key1'), isFalse);
});
test('cache eviction works when full', () {
// 填满缓存
for (int i = 0; i < 10; i++) {
cache.put('key$i', 'value$i');
}
expect(cache.getStats().size, equals(10));
// 添加新项应该触发驱逐
cache.put('key10', 'value10');
expect(cache.getStats().size, equals(10));
expect(cache.getStats().evictions, greaterThan(0));
});
test('TTL expiration works', () async {
cache.put('key1', 'value1', ttl: Duration(milliseconds: 100));
expect(cache.get('key1'), equals('value1'));
await Future.delayed(Duration(milliseconds: 150));
expect(cache.get('key1'), isNull);
});
test('cache statistics are accurate', () {
cache.put('key1', 'value1');
cache.get('key1'); // hit
cache.get('key2'); // miss
final stats = cache.getStats();
expect(stats.totalRequests, equals(2));
expect(stats.hits, equals(1));
expect(stats.misses, equals(1));
expect(stats.hitRate, equals(0.5));
});
test('smart eviction strategy works', () {
// 添加一些项并模拟不同的访问模式
cache.put('frequent', 'value1');
cache.put('recent', 'value2');
cache.put('old', 'value3');
// 频繁访问第一个
for (int i = 0; i < 5; i++) {
cache.get('frequent');
}
// 最近访问第二个
cache.get('recent');
// 第三个很久没访问
// 填满缓存以触发驱逐
for (int i = 0; i < 8; i++) {
cache.put('filler$i', 'value$i');
}
// 频繁访问的项应该还在
expect(cache.get('frequent'), equals('value1'));
// 旧的项可能被驱逐了
// expect(cache.get('old'), isNull);
});
});
group('PerformanceGenerator', () {
late PerformanceGenerator generator;
late SwaggerDocument testDocument;
setUp(() {
generator = PerformanceGenerator(
maxConcurrency: 4,
enableCaching: true,
enableIncremental: true,
enableParallel: true,
);
testDocument = SwaggerDocument(
title: 'Performance Test API',
version: '1.0.0',
description: 'API for performance testing',
servers: [ApiServer(url: 'https://api.example.com')],
components: ApiComponents(schemas: {}, securitySchemes: {}),
paths: {
'/users': ApiPath(
path: '/users',
method: HttpMethod.get,
summary: 'Get users',
description: 'Get all users',
operationId: 'getUsers',
tags: ['users'],
parameters: [],
responses: {
'200': ApiResponse(
code: '200',
description: 'Success',
),
},
),
'/posts': ApiPath(
path: '/posts',
method: HttpMethod.get,
summary: 'Get posts',
description: 'Get all posts',
operationId: 'getPosts',
tags: ['posts'],
parameters: [],
responses: {
'200': ApiResponse(
code: '200',
description: 'Success',
),
},
),
},
models: {
'User': ApiModel(
name: 'User',
description: 'User model',
properties: {
'id': ApiProperty(
name: 'id',
type: PropertyType.integer,
description: 'User ID',
required: true,
),
'name': ApiProperty(
name: 'name',
type: PropertyType.string,
description: 'User name',
required: true,
),
},
required: ['id', 'name'],
),
},
controllers: {},
security: [],
);
});
test('generates code with performance tracking', () async {
final result = await generator.generateFromDocument(testDocument);
expect(result, isNotEmpty);
expect(result, contains('Performance Test API'));
expect(result, contains('class User'));
expect(result, contains('UsersApi'));
expect(result, contains('PostsApi'));
final stats = generator.getStats();
expect(stats.totalTasks, greaterThan(0));
expect(stats.completedTasks, greaterThan(0));
expect(stats.successRate, equals(1.0));
});
test('caching improves performance on repeated generation', () async {
// 第一次生成
final stopwatch1 = Stopwatch()..start();
await generator.generateFromDocument(testDocument);
stopwatch1.stop();
final firstTime = stopwatch1.elapsedMicroseconds;
// 第二次生成(应该使用缓存)
final stopwatch2 = Stopwatch()..start();
await generator.generateFromDocument(testDocument);
stopwatch2.stop();
final secondTime = stopwatch2.elapsedMicroseconds;
print('First generation: ${firstTime}μs');
print('Second generation: ${secondTime}μs');
// 第二次应该更快(由于缓存)
expect(secondTime, lessThan(firstTime));
final cacheStats = generator.getCacheStats();
expect(cacheStats.hits, greaterThan(0));
});
test('parallel generation works with multiple modules', () async {
// 创建有多个模块的大型文档
final largePaths = <String, ApiPath>{};
final modules = ['users', 'posts', 'comments', 'tags', 'categories'];
for (final module in modules) {
for (int i = 0; i < 5; i++) {
final path = '/api/v1/$module/$i';
largePaths[path] = ApiPath(
path: path,
method: HttpMethod.get,
summary: 'Get $module $i',
description: 'Get $module item $i',
operationId: 'get${module.toUpperCase()}$i',
tags: [module],
parameters: [],
responses: {
'200': ApiResponse(code: '200', description: 'Success'),
},
);
}
}
final largeDocument = SwaggerDocument(
title: 'Large API',
version: '1.0.0',
description: 'Large API for testing',
servers: [ApiServer(url: 'https://api.example.com')],
components: ApiComponents(schemas: {}, securitySchemes: {}),
paths: largePaths,
models: {},
controllers: {},
security: [],
);
final result = await generator.generateFromDocument(largeDocument);
expect(result, isNotEmpty);
expect(result, contains('Large API'));
// 应该包含所有模块的 API
for (final module in modules) {
final className =
'${module[0].toUpperCase()}${module.substring(1)}Api';
expect(result, contains(className));
}
final stats = generator.getStats();
expect(stats.totalTasks, greaterThan(modules.length));
expect(stats.parallelEfficiency, greaterThan(0.5));
});
test('incremental generation detects no changes', () async {
// 第一次生成
await generator.generateFromDocument(testDocument);
final firstStats = generator.getStats();
// 第二次生成相同文档(应该检测到无变更)
await generator.generateFromDocument(testDocument);
final secondStats = generator.getStats();
// 第二次生成的任务数应该更少(由于增量生成)
expect(
secondStats.totalTasks, lessThanOrEqualTo(firstStats.totalTasks));
});
});
group('Real Project Performance', () {
test('handles real swagger.json efficiently', () async {
final file = File('swagger.json');
if (!file.existsSync()) {
print(
'swagger.json not found, skipping real project performance test');
return;
}
final jsonString = await file.readAsString();
// 解析性能测试
final parser = PerformanceParser(
config: ParseConfig(
enableParallelParsing: true,
enablePerformanceStats: true,
maxConcurrency: 4,
),
);
final parseStopwatch = Stopwatch()..start();
final document = await parser.parseDocument(jsonString);
parseStopwatch.stop();
print('Parse Performance:');
print(' Time: ${parseStopwatch.elapsedMilliseconds}ms');
print(
' Document size: ${(jsonString.length / 1024).toStringAsFixed(2)}KB');
print(' Paths: ${document.paths.length}');
print(' Models: ${document.models.length}');
final parseStats = parser.lastStats!;
print(parseStats.toString());
expect(
parseStopwatch.elapsedMilliseconds, lessThan(10000)); // 应该在10秒内完成
expect(parseStats.pathsPerSecond, greaterThan(1)); // 每秒至少处理1个路径
// 生成性能测试
final generator = PerformanceGenerator(
maxConcurrency: 4,
enableCaching: true,
enableParallel: true,
);
final genStopwatch = Stopwatch()..start();
final result = await generator.generateFromDocument(document);
genStopwatch.stop();
print('\nGeneration Performance:');
print(' Time: ${genStopwatch.elapsedMilliseconds}ms');
print(
' Generated size: ${(result.length / 1024).toStringAsFixed(2)}KB');
print(' Lines: ${result.split('\n').length}');
final genStats = generator.getStats();
print(genStats.toString());
expect(genStopwatch.elapsedMilliseconds, lessThan(15000)); // 应该在15秒内完成
expect(result.length, greaterThan(1000)); // 应该生成足够的代码
expect(genStats.successRate, greaterThan(0.8)); // 至少80%的任务成功
});
});
});
}