Files
Qlyra/test/update_artifact_test.dart
sevenhill 50816588e4
Build Android (FCM) / build-android-fcm (push) Canceled after 0s
Build Android / build-android (push) Canceled after 0s
Build iOS / build-ios (push) Canceled after 0s
Build Linux / build-linux (push) Canceled after 0s
Build macOS / build-macos (push) Canceled after 0s
Build Windows / build-windows (push) Canceled after 0s
Release (main) / android (oneme) (push) Canceled after 0s
Release (main) / android (qlyra) (push) Canceled after 0s
Release (main) / windows (push) Canceled after 0s
Release (main) / linux (push) Canceled after 0s
Release (main) / macos (push) Canceled after 0s
Release (main) / ios (push) Canceled after 0s
Release (main) / release (push) Canceled after 0s
Update Qlyra application
2026-08-30 22:53:15 +03:00

118 lines
3.4 KiB
Dart

import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:qlyra/core/utils/update_checker.dart';
import 'package:qlyra/core/utils/update_installer.dart';
void main() {
const qlyra = AppUpdateArtifact(
name: 'qlyra.apk',
url: 'https://example.test/qlyra.apk',
flavor: 'qlyra',
abi: 'universal',
sizeBytes: 100,
sha256: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
);
const onemeArm64 = AppUpdateArtifact(
name: 'oneme-arm64.apk',
url: 'https://example.test/oneme-arm64.apk',
flavor: 'oneme',
abi: 'arm64-v8a',
sizeBytes: 100,
sha256: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
);
const onemeUniversal = AppUpdateArtifact(
name: 'oneme.apk',
url: 'https://example.test/oneme.apk',
flavor: 'oneme',
abi: 'universal',
sizeBytes: 100,
sha256: 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
);
test('maps package identities to independent Argus slugs', () {
expect(UpdateChecker.manifestSlugForPackageName('ru.qlyra.app'), 'qlyra');
expect(UpdateChecker.manifestSlugForPackageName('ru.oneme.app'), 'oneme');
});
test('selects only an artifact for the installed flavor', () {
expect(
UpdateInstaller.selectArtifact(
[qlyra, onemeArm64, onemeUniversal],
'ru.qlyra.app',
['arm64-v8a'],
),
same(qlyra),
);
expect(
UpdateInstaller.selectArtifact(
[qlyra, onemeArm64, onemeUniversal],
'ru.oneme.app',
['arm64-v8a'],
),
same(onemeArm64),
);
});
test('falls back to a universal artifact of the same flavor', () {
expect(
UpdateInstaller.selectArtifact(
[qlyra, onemeUniversal],
'ru.oneme.app',
['x86_64'],
),
same(onemeUniversal),
);
});
test('does not cross-install another flavor', () {
expect(
UpdateInstaller.selectArtifact([qlyra], 'ru.oneme.app', ['arm64-v8a']),
isNull,
);
});
test('verifies artifact size and SHA-256', () async {
final directory = await Directory.systemTemp.createTemp('qlyra-update-');
addTearDown(() => directory.delete(recursive: true));
final file = File('${directory.path}/update.apk');
final bytes = [1, 2, 3, 4];
await file.writeAsBytes(bytes);
final artifact = AppUpdateArtifact(
name: 'update.apk',
url: 'https://example.test/update.apk',
flavor: 'qlyra',
abi: 'universal',
sizeBytes: bytes.length,
sha256: sha256.convert(bytes).toString(),
);
await expectLater(
UpdateInstaller.verifyArtifact(file, artifact),
completes,
);
});
test('rejects an artifact with a different digest', () async {
final directory = await Directory.systemTemp.createTemp('qlyra-update-');
addTearDown(() => directory.delete(recursive: true));
final file = File('${directory.path}/update.apk');
await file.writeAsBytes([1, 2, 3, 4]);
const artifact = AppUpdateArtifact(
name: 'update.apk',
url: 'https://example.test/update.apk',
flavor: 'qlyra',
abi: 'universal',
sizeBytes: 4,
sha256:
'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd',
);
await expectLater(
UpdateInstaller.verifyArtifact(file, artifact),
throwsA(isA<UpdateIntegrityException>()),
);
});
}