Tester le SDK tk_ota_push
Cette page détaille comment exécuter la suite de tests unitaires du SDK, écrire vos propres mocks (FakeShorebirdUpdater, FakeDeviceIntegrityInspector, MockClient), et valider le cycle complet des mises à jour OTA sur émulateur Android et iPhone physique.
1. Exécuter la suite de tests unitaires fournie
Le package tk_ota_push embarque 6 fichiers de tests couvrant le SDK mobile et la CLI de déploiement dans tk_ota_push/test/ :
| Fichier de test | Périmètre vérifié |
|---|---|
test/tk_ota_push_test.dart | Gatekeeper 3 étapes, mode silencieux, report workmanager en 3G/4G, mode critique forcé, détection de rollback (OtaRollbackTracker), Anti-Repackaging Xender vs APK pirate, détection Root/Jailbreak, Certificate Pinning TLS, OtaAssetManager et readClientId / readShortSupportCode / readDeviceIdentity. |
test/native_app_id_detection_test.dart | Cascade de résolution de l'app_id (9 niveaux), détection Gradle Kotlin DSL / Groovy (productFlavors, buildTypes, applicationIdSuffix) et Xcode project.pbxproj. |
test/flavor_build_args_test.dart | Construction des arguments Flutter (--flavor, -t, --dart-define, --dart-define-from-file, --artifact, --export-method). |
test/native_integrity_test.dart | NativeIntegrityScanner sur archives Android (classes*.dex, AndroidManifest.xml, lib/*.so hors binaire d'application) et bundles iOS (Info.plist, Frameworks/). |
test/geo_rollout_cli_test.dart | Parsing des codes pays ISO-2 (--countries, geo.default_countries). |
test/cli_auth_test.dart | Authentification CLI et gestion de session locale. |
Pour lancer l'ensemble des tests :
cd tk_ota_push
dart test
2. Simuler le moteur Rust et l'environnement dans vos tests unitaires
En environnement de test unitaire (flutter test / dart test), le moteur natif C++/Rust n'est pas chargé (ShorebirdUpdater().isAvailable == false). L'architecture de TkOtaPush est entièrement injectable par constructeur pour vous permettre de tester votre logique de démarrage de façon déterministe.
Créer un FakeShorebirdUpdater et un FakeDeviceIntegrityInspector
import 'package:shorebird_code_push/shorebird_code_push.dart';
import 'package:tk_ota_push/tk_ota_push.dart';
class FakeShorebirdUpdater implements ShorebirdUpdater {
FakeShorebirdUpdater({
this.available = true,
this.installedPatchNumber,
this.nextStatus = UpdateStatus.outdated,
});
final bool available;
int? installedPatchNumber;
UpdateStatus nextStatus;
int checkForUpdateCalls = 0;
int updateCalls = 0;
bool get isAvailable => available;
Future<Patch?> readCurrentPatch() async =>
installedPatchNumber == null ? null : Patch(number: installedPatchNumber!);
Future<Patch?> readNextPatch() async => readCurrentPatch();
Future<UpdateStatus> checkForUpdate({UpdateTrack? track}) async {
checkForUpdateCalls++;
return nextStatus;
}
Future<void> update({UpdateTrack? track}) async {
updateCalls++;
}
}
class FakeDeviceIntegrityInspector extends OtaDeviceIntegrityInspector {
FakeDeviceIntegrityInspector({
this.installedApkSignatureSha256,
this.rootedOrJailbroken = false,
});
String? installedApkSignatureSha256;
bool rootedOrJailbroken;
Future<String?> readInstalledApkSignatureSha256() async =>
installedApkSignatureSha256;
Future<bool> isDeviceRootedOrJailbroken() async => rootedOrJailbroken;
}
Simuler les réponses serveur pour OtaAssetManager avec MockClient
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:tk_ota_push/tk_ota_push.dart';
Future<void> testAssetDownload() async {
final payload = utf8.encode('{"banner": "Offre Spéciale"}');
final expectedHash = sha256.convert(payload).toString();
final mockHttp = MockClient((request) async {
return http.Response.bytes(payload, 200);
});
final manager = OtaAssetManager(
cacheDirectory: Directory.systemTemp.createTempSync('asset_test_'),
httpClient: mockHttp,
);
final file = await manager.getOrDownloadAsset(
OtaRemoteAssetDescriptor(
assetKey: 'assets/config/banner.json',
downloadUrl: 'https://ota.internal/assets/banner.json',
expectedSha256: expectedHash,
),
);
assert(file.existsSync());
}
3. Tester sur Émulateur Android ou Smartphone Android physique
Le moteur natif OTA ne s'active qu'en mode Release compilé via tk-ota-push release. Une application lancée avec flutter run (mode debug JIT) aura toujours isAvailable == false.
Configuration réseau (base_url)
- Sur un smartphone Android physique connecté au même Wi-Fi que votre poste serveur :
Renseignez l'adresse IP LAN de votre machine dans
shorebird.yaml(ex:base_url: "http://192.168.0.199:8080") et assurez-vous queandroid:usesCleartextTraffic="true"est actif dansAndroidManifest.xml(en développement uniquement). - Sur l'émulateur Android Studio (AVD) :
Utilisez
base_url: "http://10.0.2.2:8080"(alias de l'interface loopback de la machine hôte) ou redirigez le port via ADB :adb reverse tcp:8080 tcp:8080
Protocole de test de bout en bout sur Android
# 1. Compiler et verrouiller la Release 1.0.0+1
tk-ota-push release -p android
# 2. Installer l'APK scellé sur le téléphone / émulateur
adb install -r build/app/outputs/flutter-apk/app-release.apk
# 3. Ouvrir l'application une première fois (génère le client_id dans state.json)
# 4. Modifier un élément visuel dans lib/main.dart, puis publier le Patch #1
tk-ota-push patch -p android -m "Test Patch #1"
# 5. Déclencher la synchronisation dans l'application (ou relancer si auto_update: true)
# 6. Fermer complètement (kill) et rouvrir l'application : le Patch #1 est affiché !
Pour observer les journaux du moteur Rust en direct sur Android :
adb logcat | grep -i shorebird
4. Tester sur iPhone physique (iOS)
Le moteur OTA iOS (gen_snapshot_arm64 / artefact de patch) cible l'architecture matérielle aarch64 d'un iPhone ou iPad physique :
# 1. Compiler la Release iOS (avec export IPA Ad-Hoc ou Development)
tk-ota-push release -p ios --artifact ipa --export-method development
# 2. Installer l'application compilée sur l'iPhone physique
flutter install -d <ID_IPHONE>
# 3. Modifier lib/main.dart et publier le Patch #1
tk-ota-push patch -p ios -m "Test Patch iOS #1"
Lors du test local sur Wi-Fi, le contrôleur ShorebirdUpdaterController.resolveClientReachableUrl réécrit automatiquement l'URL de téléchargement de artefact de patch avec l'en-tête Host utilisé par l'iPhone, permettant le téléchargement direct sur le réseau local.