feat: 添加自动化任务(automation_jobs)功能模块

This commit is contained in:
qzl
2026-03-24 12:38:11 +08:00
parent f4b7eb7e09
commit 23359c2d01
43 changed files with 4266 additions and 1139 deletions
@@ -0,0 +1,297 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/features/settings/data/models/automation_job_model.dart';
void main() {
group('MessageContextConfigModel', () {
test('fromJson parses all fields correctly', () {
final json = {
'source': 'messages',
'window_mode': 'week',
'window_count': 5,
};
final model = MessageContextConfigModel.fromJson(json);
expect(model.source, 'messages');
expect(model.windowMode, 'week');
expect(model.windowCount, 5);
});
test('fromJson uses defaults for missing fields', () {
final model = MessageContextConfigModel.fromJson(null);
expect(model.source, 'latest_chat');
expect(model.windowMode, 'day');
expect(model.windowCount, 2);
});
test('toJson serializes correctly', () {
final model = MessageContextConfigModel(
source: 'messages',
windowMode: 'week',
windowCount: 5,
);
final json = model.toJson();
expect(json['source'], 'messages');
expect(json['window_mode'], 'week');
expect(json['window_count'], 5);
});
});
group('AutomationJobConfigModel', () {
test('fromJson parses all fields correctly', () {
final json = {
'input_template': 'Hello {{name}}',
'enabled_tools': ['tool1', 'tool2'],
'context': {
'source': 'messages',
'window_mode': 'week',
'window_count': 5,
},
};
final model = AutomationJobConfigModel.fromJson(json);
expect(model.inputTemplate, 'Hello {{name}}');
expect(model.enabledTools, ['tool1', 'tool2']);
expect(model.context.source, 'messages');
expect(model.context.windowMode, 'week');
expect(model.context.windowCount, 5);
});
test('fromJson uses defaults for null input', () {
final model = AutomationJobConfigModel.fromJson(null);
expect(model.inputTemplate, '');
expect(model.enabledTools, []);
expect(model.context.source, 'latest_chat');
expect(model.context.windowMode, 'day');
expect(model.context.windowCount, 2);
});
});
group('AutomationJobModel', () {
test('fromJson parses all fields correctly', () {
final json = {
'id': 'job-123',
'owner_id': 'user-456',
'bootstrap_key': 'key-789',
'title': 'Daily Report',
'schedule_type': 'DAILY',
'run_at': '09:00:00',
'timezone': 'America/New_York',
'status': 'ACTIVE',
'is_system': false,
'config': {
'input_template': 'Hello',
'enabled_tools': ['tool1'],
'context': {
'source': 'latest_chat',
'window_mode': 'day',
'window_count': 2,
},
},
'next_run_at': '2024-01-15T09:00:00Z',
'last_run_at': '2024-01-14T09:00:00Z',
'created_at': '2024-01-01T00:00:00Z',
'updated_at': '2024-01-14T12:00:00Z',
};
final model = AutomationJobModel.fromJson(json);
expect(model.id, 'job-123');
expect(model.ownerId, 'user-456');
expect(model.bootstrapKey, 'key-789');
expect(model.title, 'Daily Report');
expect(model.scheduleType, 'DAILY');
expect(model.runAt, '09:00:00');
expect(model.timezone, 'America/New_York');
expect(model.status, 'ACTIVE');
expect(model.isSystem, false);
expect(model.config.inputTemplate, 'Hello');
expect(model.config.enabledTools, ['tool1']);
expect(model.config.context.windowCount, 2);
expect(model.nextRunAt, DateTime.parse('2024-01-15T09:00:00Z'));
expect(model.lastRunAt, DateTime.parse('2024-01-14T09:00:00Z'));
expect(model.createdAt, DateTime.parse('2024-01-01T00:00:00Z'));
expect(model.updatedAt, DateTime.parse('2024-01-14T12:00:00Z'));
});
test('fromJson throws for missing required date fields', () {
final json = <String, dynamic>{
'id': 'job-123',
'owner_id': 'user-456',
'title': 'Test',
'schedule_type': 'DAILY',
'run_at': '09:00:00',
'timezone': 'UTC',
'status': 'ACTIVE',
'is_system': false,
'config': null,
};
expect(
() => AutomationJobModel.fromJson(json),
throwsA(isA<FormatException>()),
);
});
});
group('AutomationJobConfigPatchModel', () {
test('toJson only includes non-null fields', () {
final model = AutomationJobConfigPatchModel(
inputTemplate: 'Updated template',
);
final json = model.toJson();
expect(json.containsKey('input_template'), true);
expect(json.containsKey('enabled_tools'), false);
expect(json.containsKey('context'), false);
expect(json['input_template'], 'Updated template');
});
test('toJson includes all fields when set', () {
final model = AutomationJobConfigPatchModel(
inputTemplate: 'Template',
enabledTools: ['tool1', 'tool2'],
context: MessageContextConfigModel(
source: 'messages',
windowMode: 'week',
windowCount: 3,
),
);
final json = model.toJson();
expect(json['input_template'], 'Template');
expect(json['enabled_tools'], ['tool1', 'tool2']);
expect(json['context'], {
'source': 'messages',
'window_mode': 'week',
'window_count': 3,
});
});
});
group('AutomationJobUpdateRequest', () {
test('toJson only includes non-null fields', () {
final request = AutomationJobUpdateRequest(
title: 'Updated Title',
status: 'INACTIVE',
);
final json = request.toJson();
expect(json.containsKey('title'), true);
expect(json.containsKey('status'), true);
expect(json.containsKey('schedule_type'), false);
expect(json.containsKey('run_at'), false);
expect(json['title'], 'Updated Title');
expect(json['status'], 'INACTIVE');
});
test('toJson includes patch config with only non-null fields', () {
final request = AutomationJobUpdateRequest(
config: AutomationJobConfigPatchModel(inputTemplate: 'New template'),
);
final json = request.toJson();
expect(json.containsKey('config'), true);
final configJson = json['config'] as Map<String, dynamic>;
expect(configJson.containsKey('input_template'), true);
expect(configJson.containsKey('enabled_tools'), false);
expect(configJson.containsKey('context'), false);
});
});
group('AutomationJobCreateRequest', () {
test('toJson serializes correctly', () {
final request = AutomationJobCreateRequest(
title: 'New Job',
scheduleType: 'DAILY',
runAt: '10:00:00',
timezone: 'UTC',
status: 'ACTIVE',
config: AutomationJobConfigModel(
inputTemplate: 'Hello',
enabledTools: ['tool1'],
context: MessageContextConfigModel(
source: 'latest_chat',
windowMode: 'day',
windowCount: 2,
),
),
);
final json = request.toJson();
expect(json['title'], 'New Job');
expect(json['schedule_type'], 'DAILY');
expect(json['run_at'], '10:00:00');
expect(json['timezone'], 'UTC');
expect(json['status'], 'ACTIVE');
expect(json['config'], {
'input_template': 'Hello',
'enabled_tools': ['tool1'],
'context': {
'source': 'latest_chat',
'window_mode': 'day',
'window_count': 2,
},
});
});
});
group('AutomationJobListResponse', () {
test('fromJson parses items correctly', () {
final json = {
'items': [
{
'id': 'job-1',
'owner_id': 'user-1',
'title': 'Job 1',
'schedule_type': 'DAILY',
'run_at': '09:00:00',
'timezone': 'UTC',
'status': 'ACTIVE',
'is_system': false,
'config': null,
'next_run_at': '2024-01-15T09:00:00Z',
'created_at': '2024-01-01T00:00:00Z',
'updated_at': '2024-01-14T12:00:00Z',
},
{
'id': 'job-2',
'owner_id': 'user-1',
'title': 'Job 2',
'schedule_type': 'HOURLY',
'run_at': '00:00:00',
'timezone': 'UTC',
'status': 'INACTIVE',
'is_system': false,
'config': null,
'next_run_at': '2024-01-15T10:00:00Z',
'created_at': '2024-01-02T00:00:00Z',
'updated_at': '2024-01-14T12:00:00Z',
},
],
};
final response = AutomationJobListResponse.fromJson(json);
expect(response.items.length, 2);
expect(response.items[0].id, 'job-1');
expect(response.items[1].id, 'job-2');
});
test('fromJson returns empty list for null items', () {
final response = AutomationJobListResponse.fromJson(null);
expect(response.items, isEmpty);
});
});
}