import 'dart:convert'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; import 'package:appsok/src/models/jenkins_build.dart'; import 'package:appsok/src/services/artifact_staging_service.dart'; import 'package:appsok/src/services/jenkins_artifact_session.dart'; import 'package:appsok/src/services/jenkins_client.dart'; import 'package:appsok/src/services/token_store.dart'; void main() { const credentials = JenkinsCredentials(username: 'user', apiToken: 'token'); const baseUrl = 'https://jenkins.example'; setUp(() { FlutterSecureStorage.setMockInitialValues({}); }); test('restore validates stored session with current user api', () async { FlutterSecureStorage.setMockInitialValues({ 'jenkins.baseUrl': baseUrl, 'jenkins.username': credentials.username, 'jenkins.apiToken': credentials.apiToken, }); Uri? capturedUri; Map? capturedHeaders; final session = JenkinsArtifactSession( store: TokenStore(), client: JenkinsClient( client: MockClient((request) async { capturedUri = request.url; capturedHeaders = request.headers; if (request.url.path.endsWith('whoAmI/api/json')) { return http.Response(jsonEncode({'id': 'user'}), 200); } return http.Response('unexpected', 400); }), ), stager: ArtifactStagingService(), ); final restored = await session.restore(); expect(restored, isTrue); expect(capturedUri?.path, '/whoAmI/api/json'); expect( capturedHeaders?['Authorization'], 'Basic ${base64Encode(utf8.encode('user:token'))}', ); }); test('loadJobs delegates to JenkinsClient with stored base url and credentials', () async { FlutterSecureStorage.setMockInitialValues({ 'jenkins.baseUrl': baseUrl, 'jenkins.username': credentials.username, 'jenkins.apiToken': credentials.apiToken, }); Uri? jobsUri; final session = JenkinsArtifactSession( store: TokenStore(), client: JenkinsClient( client: MockClient((request) async { if (request.url.path.endsWith('whoAmI/api/json')) { return http.Response(jsonEncode({'id': 'user'}), 200); } if (request.url.path.endsWith('api/json')) { jobsUri = request.url; return http.Response( jsonEncode({'jobs': []}), 200, ); } return http.Response('unexpected', 400); }), ), stager: ArtifactStagingService(), ); await session.restore(); await session.loadJobs(); expect(jobsUri, isNotNull); expect(jobsUri?.path, '/api/json'); expect(jobsUri?.host, 'jenkins.example'); }); test('downloadArtifact builds Jenkins artifact URL from build url and relative path', () async { FlutterSecureStorage.setMockInitialValues({ 'jenkins.baseUrl': baseUrl, 'jenkins.username': credentials.username, 'jenkins.apiToken': credentials.apiToken, }); Uri? artifactUri; final session = JenkinsArtifactSession( store: TokenStore(), client: JenkinsClient( client: MockClient((request) async { if (request.url.path.endsWith('whoAmI/api/json')) { return http.Response(jsonEncode({'id': 'user'}), 200); } if (request.url.path.endsWith('artifact/file.apk')) { artifactUri = request.url; return http.Response.bytes([], 200); } if (request.url.path.endsWith('api/json')) { return http.Response(jsonEncode({'jobs': []}), 200); } return http.Response('unexpected', 400); }), ), stager: ArtifactStagingService(), ); await session.restore(); final task = session.downloadArtifact( JenkinsBuild( number: 1, jobName: 'app', url: Uri.parse('$baseUrl/job/app/1/'), startedAt: DateTime(2026), result: 'SUCCESS', artifacts: const [ BuildArtifact(fileName: 'app.apk', relativePath: 'artifact/file.apk'), ], ), const BuildArtifact(fileName: 'file.apk', relativePath: 'artifact/file.apk'), ); await task.events.toList(); expect(artifactUri, isNotNull); expect(artifactUri?.path, '/job/app/1/artifact/artifact/file.apk'); }); test('returns unavailable state when session config is missing', () async { final session = JenkinsArtifactSession( store: TokenStore(), client: JenkinsClient( client: MockClient((_) async => http.Response('', 200)), ), stager: ArtifactStagingService(), ); final restored = await session.restore(); expect(restored, isFalse); expect(session.isRestored, isFalse); }); }