🏡 index : cold-air-networks/mirror-jetstream.git

// Copyright (C) 2007-2025 Apple Inc. All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//  notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//  notice, this list of conditions and the following disclaimer in the
//  documentation and/or other materials provided with the distribution.

// THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.

load("utils/shell-config.js");
load("utils/params.js");
load("utils/StartupBenchmark.js");
load("JetStreamDriver.js");

function assertTrue(condition, message) {
  if (!condition) {
    throw new Error(message || "Assertion failed");
  }
}

function assertFalse(condition, message) {
  if (condition) {
    throw new Error(message || "Assertion failed");
  }
}

function assertEquals(actual, expected, message) {
  if (actual !== expected) {
    throw new Error(message || `Expected ${expected}, but got ${actual}`);
  }
}

function assertThrows(message, func) {
  let didThrow = false;
  try {
    func();
  } catch (e) {
    didThrow = true;
  }
  assertTrue(didThrow, `Test did not throw: ${message}`);
}

(function testTagsAreLowerCaseStrings() {
  for (const benchmark of BENCHMARKS) {
    benchmark.tags.forEach((tag) => {
      assertTrue(typeof tag == "string");
      assertTrue(tag == tag.toLowerCase());
    });
  }
})();

(function testTagsAll() {
  for (const benchmark of BENCHMARKS) {
    const tags = benchmark.tags;
    assertTrue(tags instanceof Set);
    assertTrue(tags.size > 0);
    assertTrue(tags.has("all"));
    assertFalse(tags.has("All"));
    assertTrue(tags.has("default") ^ tags.has("disabled"));
  }
})();


(function tagsAreNotBenchmarkNames() {
  const benchmarkNames = new Set(BENCHMARKS.map(e => e.name));
  for (const benchmark of benchmarks) {
    for (const tag of benchmark.tags) {
      assertFalse(benchmarkNames.has(tag), `'${tag}' is also a benchmark name`);
    }
  }
})();

(function tagsHasWasmOrJS() {
  for (const benchmark of benchmarks) {
    const tags = benchmark.tags;
    assertTrue(tags.has("wasm") || tags.has("js"), `'${benchmark.name}' has no 'js' or 'wasm' tag`);
  }
})();

(function testDriverBenchmarksOrder() {
  const benchmarks = findBenchmarksByTag("all");
  const driver = new Driver(benchmarks);
  assertEquals(driver.benchmarks.length, BENCHMARKS.length);
  const names = driver.benchmarks
    .map((b) => b.name.toLowerCase())
    .sort()
    .reverse();
  for (let i = 0; i < names.length; i++) {
    assertEquals(driver.benchmarks[i].name.toLowerCase(), names[i]);
  }
})();

(function testEnableByTag() {
  const driverA = new Driver(findBenchmarksByTag("Default"));
  const driverB = new Driver(findBenchmarksByTag("default"));
  assertTrue(driverA.benchmarks.length > 0);
  assertEquals(driverA.benchmarks.length, driverB.benchmarks.length);
  const enabledBenchmarkNames = new Set(
    Array.from(driverA.benchmarks).map((b) => b.name)
  );
  for (const benchmark of BENCHMARKS) {
    if (benchmark.tags.has("default"))
      assertTrue(enabledBenchmarkNames.has(benchmark.name));
  }
})();

(function testDriverEnableDuplicateAndSort() {
  const benchmarks = [
    ...findBenchmarksByTag("wasm"),
    ...findBenchmarksByTag("wasm"),
  ];
  assertTrue(benchmarks.length > 0);
  const uniqueBenchmarks = new Set(benchmarks);
  assertFalse(uniqueBenchmarks.size == benchmarks.length);
  const driver = new Driver(benchmarks);
  assertEquals(driver.benchmarks.length, uniqueBenchmarks.size);
})();

(function testBenchmarkSubScores() {
  for (const benchmark of BENCHMARKS) {
    const subScores = benchmark.subScores();
    assertTrue(subScores instanceof Object);
    assertTrue(Object.keys(subScores).length > 0);
    for (const [name, value] of Object.entries(subScores)) {
      assertTrue(typeof name == "string");
      // "Score" can only be part of allScores().
      assertFalse(name == "Score");
      // Without running values should be either null (or 0 for GroupedBenchmark)
      assertFalse(value);
    }
  }
})();

(function testBenchmarkAllScores() {
  for (const benchmark of BENCHMARKS) {
    const subScores = benchmark.subScores();
    const allScores = benchmark.allScores();
    assertTrue("Score" in allScores);
    // All subScore items are part of allScores.
    for (const name of Object.keys(subScores)) assertTrue(name in allScores);
  }
})();

(function checkUtf16Sources() {
  // Test that only explicitly UTF16-enabled benchmarks can have sources
  // with non-8-byte characters.
  const twoByteCharsRegex = /[^\x00-\xFF]/g;
  const jsFileRegex = /\.(js|mjs)$/;

  function checkFile(benchmarkName, file, type) {
      if (!jsFileRegex.test(file))
          return;
      const content = read(file);
      const match = content.match(twoByteCharsRegex);
      if (!match)
          return;
      const uniqueMatches = Array.from(new Set(match));
      const offendingChars = uniqueMatches.map(char => {
          const hex = char.charCodeAt(0).toString(16).padStart(4, "0");
          return `\n        - \\u${hex}: '${char}'`;
      }).join("");
      throw new Error(
        `Benchmark '${benchmarkName}' has two-byte characters in ${type} '${file}':\n` +
        `    Offending characters: ${offendingChars}`);
  }

  for (const benchmark of BENCHMARKS) {
    if (benchmark.allowUtf16)
        continue;

    for (const file of benchmark.files) {
        checkFile(benchmark.name, file, "file");
    }

    if (benchmark.plan.preload) {
        for (const [name, file] of Object.entries(benchmark.plan.preload)) {
            checkFile(benchmark.name, file, `preload.${name}`);
        }
    }
  }
})();

function validateIterationSources(sources) {
  for (const source of sources) {
    assertTrue(typeof source == "string");
    assertFalse(source.includes(CACHE_BUST_COMMENT));
  }
}

(async function testStartupBenchmark() {
  try {
    JetStream.preload = { BUNDLE: "test-bundle.js" };
    JetStream.getString = (file) => {
      assertEquals(file, "test-bundle.js");
      return `function test() { 
${CACHE_BUST_COMMENT}
        return 1;
        }`;
    };
    await testStartupBenchmarkInnerTests();
  } finally {
    JetStream.preload = undefined;
    JetStream.getString = undefined;
  }
})();

async function testStartupBenchmarkInnerTests() {
  const benchmark = new StartupBenchmark({
    iterationCount: 12,
    expectedCacheCommentCount: 1,
  });
  assertEquals(benchmark.iterationCount, 12);
  assertEquals(benchmark.expectedCacheCommentCount, 1);
  assertEquals(benchmark.iterationSourceCodes.length, 0);
  assertEquals(benchmark.sourceCode, undefined);
  assertEquals(benchmark.sourceHash, 0);
  await benchmark.init();
  assertEquals(benchmark.sourceHash, 177573);
  assertEquals(benchmark.sourceCode.length, 68);
  assertEquals(benchmark.iterationSourceCodes.length, 12);
  assertEquals(new Set(benchmark.iterationSourceCodes).size, 12);
  validateIterationSources(benchmark.iterationSourceCodes);

  const noReuseBenchmark = new StartupBenchmark({
    iterationCount: 12,
    expectedCacheCommentCount: 1,
    sourceCodeReuseCount: 0,
  });
  assertEquals(noReuseBenchmark.iterationSourceCodes.length, 0);
  await noReuseBenchmark.init();
  assertEquals(noReuseBenchmark.iterationSourceCodes.length, 12);
  assertEquals(new Set(noReuseBenchmark.iterationSourceCodes).size, 1);
  validateIterationSources(noReuseBenchmark.iterationSourceCodes);

  const reuseBenchmark = new StartupBenchmark({
    iterationCount: 12,
    expectedCacheCommentCount: 1,
    sourceCodeReuseCount: 3,
  });
  assertEquals(reuseBenchmark.iterationSourceCodes.length, 0);
  await reuseBenchmark.init();
  assertEquals(reuseBenchmark.iterationSourceCodes.length, 12);
  assertEquals(new Set(reuseBenchmark.iterationSourceCodes).size, 4);
  validateIterationSources(reuseBenchmark.iterationSourceCodes);

  const reuseBenchmark2 = new StartupBenchmark({
    iterationCount: 12,
    expectedCacheCommentCount: 1,
    sourceCodeReuseCount: 5,
  });
  assertEquals(reuseBenchmark2.iterationSourceCodes.length, 0);
  await reuseBenchmark2.init();
  assertEquals(reuseBenchmark2.iterationSourceCodes.length, 12);
  assertEquals(new Set(reuseBenchmark2.iterationSourceCodes).size, 3);
  validateIterationSources(reuseBenchmark2.iterationSourceCodes);
}

(function testStartupBenchmarkThrow() {
  assertThrows(
    "StartupBenchmark constructor should throw with no arguments.",
    () => new StartupBenchmark()
  );

  assertThrows(
    "StartupBenchmark constructor should throw with missing expectedCacheCommentCount.",
    () => new StartupBenchmark({ iterationCount: 1 })
  );

  assertThrows(
    "StartupBenchmark constructor should throw with missing iterationCount.",
    () => new StartupBenchmark({ expectedCacheCommentCount: 1 })
  );

  assertThrows(
    "StartupBenchmark constructor should throw with iterationCount=0.",
    () => {
      new StartupBenchmark({ iterationCount: 0, expectedCacheCommentCount: 1 });
    }
  );

  assertThrows(
    "StartupBenchmark constructor should throw with expectedCacheCommentCount=0.",
    () => {
      new StartupBenchmark({ iterationCount: 1, expectedCacheCommentCount: 0 });
    }
  );
})();

(function testDefaultParams() {
  assertTrue(DefaultJetStreamParams.isDefault);
  assertTrue(Object.isFrozen(DefaultJetStreamParams));
  assertEquals(Object.entries(DefaultJetStreamParams.nonDefaultParams).length, 0);
})();

(function testCustomParamsSingle() {
  const sourceParams = new Map(Object.entries({ developerMode: "true" }));
  const params = new Params(sourceParams);
  assertFalse(params.isDefault);
  const nonDefaults = params.nonDefaultParams;
  assertEquals(Object.entries(nonDefaults).length, 1);
  assertEquals(nonDefaults.developerMode, true);
})();


(function testCustomParamsMultiple() {
  const sourceParams = new Map(Object.entries({ iterationCount: 123, test: "wasm,js"}));
  const params = new Params(sourceParams);
  assertFalse(params.isDefault);
  const nonDefaults = params.nonDefaultParams;
  assertEquals(Object.entries(nonDefaults).length, 2);
  assertEquals(nonDefaults.testIterationCount, 123);
  assertEquals(JSON.stringify(nonDefaults.testList), JSON.stringify(["wasm", "js"]));
})();


(function testParseIterationCount() {
  assertThrows("Cannot parse negative iterationCounts", 
    () => {
      const sourceParams = new Map(Object.entries({ iterationCount: -123, }));
      new Params(sourceParams);
    });
  assertThrows("Cannot parse multiple iterationCounts", 
    () => {
      const sourceParams = new Map(Object.entries({ iterationCount: 123, testIterationCount: 10 }));
      new Params(sourceParams);
    });
  let sourceParams = new Map(Object.entries({ iterationCount: 123 }));
  let params = new Params(sourceParams);
  assertEquals(params.testIterationCount, 123);
})();