feat(code_push_client): add createReleaseArtifact (#185)

This commit is contained in:
Felix Angelov
2023-03-28 13:14:07 -05:00
committed by GitHub
parent 901986a12a
commit dcec738667
3 changed files with 167 additions and 0 deletions
@@ -31,6 +31,15 @@ Future<void> main() async {
displayName: '<DISPLAY NAME>', // e.g. 'v1.0.0'
);
// Create a release artifact.
final releaseArtifact = await client.createReleaseArtifact(
releaseId: release.id,
artifactPath: '<PATH TO ARTIFACT>', // e.g. 'libapp.so'
platform: '<PLATFORM>', // e.g. 'android'
arch: '<ARCHITECTURE>', // e.g. 'aarch64'
hash: '<HASH>', // 'sha256 hash of the artifact'
);
// Create a new patch.
final patch = await client.createPatch(releaseId: release.id);
@@ -75,6 +75,35 @@ class CodePushClient {
return PatchArtifact.fromJson(json.decode(body) as Map<String, dynamic>);
}
/// Create a new artifact for a specific [releaseId].
Future<ReleaseArtifact> createReleaseArtifact({
required String artifactPath,
required int releaseId,
required String arch,
required String platform,
required String hash,
}) async {
final request = http.MultipartRequest(
'POST',
Uri.parse('$hostedUri/api/v1/releases/$releaseId/artifacts'),
);
final file = await http.MultipartFile.fromPath('file', artifactPath);
request.files.add(file);
request.fields.addAll({
'arch': arch,
'platform': platform,
'hash': hash,
'size': '${file.length}',
});
request.headers.addAll(_apiKeyHeader);
final response = await _httpClient.send(request);
final body = await response.stream.bytesToString();
if (response.statusCode != HttpStatus.ok) throw _parseErrorResponse(body);
return ReleaseArtifact.fromJson(json.decode(body) as Map<String, dynamic>);
}
/// Create a new app with the provided [displayName].
/// Returns the newly created app.
Future<App> createApp({required String displayName}) async {
@@ -185,6 +185,135 @@ void main() {
});
});
group('createReleaseArtifact', () {
const releaseId = 0;
const arch = 'aarch64';
const platform = 'android';
const hash = 'test-hash';
const size = 42;
test('throws an exception if the http request fails (unknown)', () async {
when(() => httpClient.send(any())).thenAnswer((_) async {
return http.StreamedResponse(
Stream.empty(),
HttpStatus.failedDependency,
);
});
final tempDir = Directory.systemTemp.createTempSync();
final fixture = File(path.join(tempDir.path, 'release.txt'))
..createSync();
expect(
codePushClient.createReleaseArtifact(
artifactPath: fixture.path,
releaseId: releaseId,
arch: arch,
platform: platform,
hash: hash,
),
throwsA(
isA<CodePushException>().having(
(e) => e.message,
'message',
CodePushClient.unknownErrorMessage,
),
),
);
});
test('throws an exception if the http request fails', () async {
when(() => httpClient.send(any())).thenAnswer((_) async {
return http.StreamedResponse(
Stream.value(utf8.encode(json.encode(errorResponse.toJson()))),
HttpStatus.failedDependency,
);
});
final tempDir = Directory.systemTemp.createTempSync();
final fixture = File(path.join(tempDir.path, 'release.txt'))
..createSync();
expect(
codePushClient.createReleaseArtifact(
artifactPath: fixture.path,
releaseId: releaseId,
arch: arch,
platform: platform,
hash: hash,
),
throwsA(
isA<CodePushException>().having(
(e) => e.message,
'message',
errorResponse.message,
),
),
);
});
test('completes when request succeeds', () async {
const artifactId = 0;
const artifactUrl = 'https://example.com/artifact.zip';
when(() => httpClient.send(any())).thenAnswer((_) async {
return http.StreamedResponse(
Stream.value(
utf8.encode(
json.encode(
ReleaseArtifact(
id: artifactId,
url: artifactUrl,
releaseId: releaseId,
arch: arch,
platform: platform,
hash: hash,
size: size,
),
),
),
),
HttpStatus.ok,
);
});
final tempDir = Directory.systemTemp.createTempSync();
final fixture = File(path.join(tempDir.path, 'release.txt'))
..createSync();
await expectLater(
codePushClient.createReleaseArtifact(
artifactPath: fixture.path,
releaseId: releaseId,
arch: arch,
platform: platform,
hash: hash,
),
completion(
equals(
isA<ReleaseArtifact>()
.having((a) => a.id, 'id', artifactId)
.having((a) => a.releaseId, 'releaseId', releaseId)
.having((a) => a.arch, 'arch', arch)
.having((a) => a.platform, 'platform', platform)
.having((a) => a.hash, 'hash', hash)
.having((a) => a.url, 'artifactUrl', artifactUrl),
),
),
);
final request = verify(() => httpClient.send(captureAny()))
.captured
.single as http.MultipartRequest;
expect(
request.url,
codePushClient.hostedUri.replace(
path: '/api/v1/releases/$releaseId/artifacts',
),
);
});
});
group('createApp', () {
test('throws an exception if the http request fails (unknown)', () async {
when(