|
|
@@ -1537,6 +1537,155 @@ exit 0
|
|
|
Usm.Util.delete_tree(scratch);
|
|
|
}
|
|
|
|
|
|
+ // ---- Granular progress reporting ----------------------------------------------
|
|
|
+
|
|
|
+ /** Whether the reports climb monotonically from start to end. */
|
|
|
+ bool monotonic(float[] fractions) {
|
|
|
+ for(int i = 1; i < fractions.length; i++) {
|
|
|
+ if(fractions[i] < fractions[i - 1]) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ void test_unarchive_with_progress() throws Error {
|
|
|
+ var scratch = make_scratch();
|
|
|
+ var source = Path.build_filename(scratch, "src");
|
|
|
+ DirUtils.create(source, 0755);
|
|
|
+ for(int i = 0; i < 5; i++) {
|
|
|
+ FileUtils.set_contents(Path.build_filename(source, @"file$i.txt"), @"content $i");
|
|
|
+ }
|
|
|
+ var archive = Path.build_filename(scratch, "pkg.usmc");
|
|
|
+ Usm.Util.archive(source, archive);
|
|
|
+
|
|
|
+ float[] fractions = {};
|
|
|
+ var destination = Path.build_filename(scratch, "out");
|
|
|
+ Usm.Util.unarchive_with_progress(archive, destination, f => { fractions += f; });
|
|
|
+ check(fractions.length == 6, "one progress report fires per extracted archive member (including the root)");
|
|
|
+ check(fractions[0] > 0.0f, "the first member already reports progress");
|
|
|
+ check(fractions[fractions.length - 1] == 1.0f, "the last member reports full progress");
|
|
|
+ check(monotonic(fractions), "extraction progress never regresses");
|
|
|
+ check(File.new_for_path(Path.build_filename(destination, "file3.txt")).query_exists(), "the archive extracts fully");
|
|
|
+
|
|
|
+ var bare = Path.build_filename(scratch, "out-bare");
|
|
|
+ Usm.Util.unarchive_with_progress(archive, bare, null);
|
|
|
+ check(File.new_for_path(Path.build_filename(bare, "file0.txt")).query_exists(), "a null delegate extracts without progress reporting");
|
|
|
+
|
|
|
+ Usm.Util.delete_tree(scratch);
|
|
|
+ }
|
|
|
+
|
|
|
+ void test_resolver_resolution_progress() throws Error {
|
|
|
+ var scratch = make_scratch();
|
|
|
+ var resolver = new Usm.Resolver(new Usm.ResourceFinder());
|
|
|
+ resolver.supply_package(make_package_archive(scratch, "pa", {}));
|
|
|
+ resolver.supply_package(make_package_archive(scratch, "pb", { "bin:pkg-pa" }));
|
|
|
+
|
|
|
+ var roots = new Vector<Usm.AbstractPackage>();
|
|
|
+ roots.add(((!)resolver.find_package("pkg-pb")));
|
|
|
+
|
|
|
+ float[] fractions = {};
|
|
|
+ resolver.resolution_progress = f => { fractions += f; };
|
|
|
+ var result = resolver.resolve(roots, null);
|
|
|
+
|
|
|
+ check(result.packages.count() == 2, "resolution still closes the closure with reporting enabled");
|
|
|
+ check(fractions.length == 3, "one report fires per resolved package plus a completion clamp");
|
|
|
+ check(fractions[0] == 0.5f, "the first package reports against the roots-x-2 estimate");
|
|
|
+ check(fractions[fractions.length - 1] == 1.0f, "completion clamps to full progress");
|
|
|
+ check(monotonic(fractions), "resolution progress never regresses");
|
|
|
+
|
|
|
+ Usm.Util.delete_tree(scratch);
|
|
|
+ }
|
|
|
+
|
|
|
+ void test_install_script_progress_parsing() throws Error {
|
|
|
+ var scratch = make_scratch();
|
|
|
+ var original_dir = Environment.get_current_dir();
|
|
|
+ var source = Path.build_filename(scratch, "src");
|
|
|
+ DirUtils.create(source, 0755);
|
|
|
+ FileUtils.set_contents(Path.build_filename(source, "MANIFEST.usm"), """
|
|
|
+ {
|
|
|
+ "name": "meson-pkg",
|
|
|
+ "version": "1.0.0",
|
|
|
+ "summary": "install progress fixture",
|
|
|
+ "licences": [],
|
|
|
+ "flags": ["ninjaStyleProgress"],
|
|
|
+ "provides": { "bin:meson-pkg": "as-expected" },
|
|
|
+ "depends": { "runtime": [], "build": [], "manage": [] },
|
|
|
+ "execs": { "install": "install.sh" }
|
|
|
+ }
|
|
|
+ """);
|
|
|
+ FileUtils.set_contents(Path.build_filename(source, "install.sh"), """#!/bin/bash
|
|
|
+echo "Installing meson-pkg to /usr/bin"
|
|
|
+echo "noise that is not an install line"
|
|
|
+echo "Installing libmeson-pkg.so to /usr/lib"
|
|
|
+""");
|
|
|
+ FileUtils.chmod(Path.build_filename(source, "install.sh"), 0755);
|
|
|
+
|
|
|
+ Environment.set_current_dir(source);
|
|
|
+ var manifest = new Usm.Manifest.from_file("MANIFEST.usm");
|
|
|
+ float[] fractions = {};
|
|
|
+ var install_dir = Path.build_filename(scratch, "install");
|
|
|
+ DirUtils.create(install_dir, 0755);
|
|
|
+ var proc = manifest.run_install(Path.build_filename(scratch, "build"), install_dir, new Usm.Paths(),
|
|
|
+ Usm.InstallType.FRESH, SubprocessFlags.STDOUT_SILENCE, f => { fractions += f; });
|
|
|
+ check(proc != null, "a ninjaStyleProgress install script spawns through the parsing path");
|
|
|
+ ((!)proc).wait_check();
|
|
|
+
|
|
|
+ check(fractions.length == 2, "each Installing line reports exactly once and noise is skipped");
|
|
|
+ check(fractions[0] == 0.5f, "reports run against the provides-count-x-2 estimate");
|
|
|
+ check(fractions[1] == 1.0f, "the last Installing line reaches full progress");
|
|
|
+
|
|
|
+ Environment.set_current_dir(original_dir);
|
|
|
+ Usm.Util.delete_tree(scratch);
|
|
|
+ }
|
|
|
+
|
|
|
+ void test_transaction_unpack_progress() throws Error {
|
|
|
+ var original_dir = Environment.get_current_dir();
|
|
|
+ var scratch = make_scratch();
|
|
|
+ var state = make_state(scratch);
|
|
|
+
|
|
|
+ var cache_path = Path.build_filename(scratch, "state", "packages", "unpack-pkg-1.0.0");
|
|
|
+ DirUtils.create_with_parents(cache_path, 0755);
|
|
|
+ var source = Path.build_filename(scratch, "src-unpack-pkg");
|
|
|
+ DirUtils.create(source, 0755);
|
|
|
+ FileUtils.set_contents(Path.build_filename(source, "MANIFEST.usm"), BUILD_MANIFEST.printf("unpack-pkg", "1.0.0"));
|
|
|
+ FileUtils.set_contents(Path.build_filename(source, "build.sh"), NOOP_BUILD_SCRIPT);
|
|
|
+ FileUtils.chmod(Path.build_filename(source, "build.sh"), 0755);
|
|
|
+ for(int i = 0; i < 4; i++) {
|
|
|
+ FileUtils.set_contents(Path.build_filename(source, @"payload$i.txt"), "data");
|
|
|
+ }
|
|
|
+ Usm.Util.archive(source, Path.build_filename(cache_path, "package.usmc"));
|
|
|
+ Usm.Util.delete_tree(source);
|
|
|
+
|
|
|
+ var to_install = new HashSet<Usm.CachedPackage>();
|
|
|
+ to_install.add(new Usm.CachedPackage(cache_path));
|
|
|
+
|
|
|
+ var transaction = new Usm.Transaction() {
|
|
|
+ paths = scratch_paths(scratch),
|
|
|
+ resource_finder = new Usm.ResourceFinder(),
|
|
|
+ to_install = to_install,
|
|
|
+ to_remove = new HashSet<Usm.CachedPackage>(),
|
|
|
+ state = state
|
|
|
+ };
|
|
|
+
|
|
|
+ float[] unpack_fractions = {};
|
|
|
+ transaction.progress_updated.connect((task_type, subject, current_task, total_tasks, task_progress) => {
|
|
|
+ if(task_type == Usm.TransactionTask.UNPACKING) {
|
|
|
+ unpack_fractions += task_progress;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ transaction.run();
|
|
|
+
|
|
|
+ check(unpack_fractions.length >= 6, "unpacking reports the clean, every extracted member and completion");
|
|
|
+ check(unpack_fractions[0] == 0.0f, "the task opens at zero before the source clean");
|
|
|
+ check(unpack_fractions[1] == 0.5f, "the source clean lands at the half-way report");
|
|
|
+ check(unpack_fractions[unpack_fractions.length - 1] == 1.0f, "unpacking completes at full progress");
|
|
|
+ check(monotonic(unpack_fractions), "unpack progress never regresses");
|
|
|
+
|
|
|
+ Environment.set_current_dir(original_dir);
|
|
|
+ Usm.Util.delete_tree(scratch);
|
|
|
+ }
|
|
|
+
|
|
|
int main() {
|
|
|
test_default_ignore();
|
|
|
try {
|
|
|
@@ -1656,6 +1805,17 @@ exit 0
|
|
|
print("FAIL transaction rollback test threw: %s\n", e.message);
|
|
|
}
|
|
|
|
|
|
+ try {
|
|
|
+ test_unarchive_with_progress();
|
|
|
+ test_resolver_resolution_progress();
|
|
|
+ test_install_script_progress_parsing();
|
|
|
+ test_transaction_unpack_progress();
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ failures++;
|
|
|
+ print("FAIL progress reporting test threw: %s\n", e.message);
|
|
|
+ }
|
|
|
+
|
|
|
print("%d passed, %d failed\n", passes, failures);
|
|
|
return failures == 0 ? 0 : 1;
|
|
|
}
|