Skip to content

Commit

Permalink
Introduce node.js test runner
Browse files Browse the repository at this point in the history
  • Loading branch information
fasterthanlime committed Jul 23, 2024
1 parent ce4e44e commit 327500d
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 8 deletions.
54 changes: 48 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,85 @@ jobs:
toolchain: stable
profile: minimal
override: true
- name: Set dynamic linker paths
run: |
export DYLD_LIBRARY_PATH=$(rustc --print sysroot)/lib
export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib
export PATH=$(rustc --print sysroot)/lib:$PATH
export DYLD_LIBRARY_PATH_NIGHTLY=$(rustc +nightly --print sysroot)/lib
export LD_LIBRARY_PATH_NIGHTLY=$(rustc +nightly --print sysroot)/lib
export PATH_NIGHTLY=$(rustc +nightly --print sysroot)/lib:$PATH
shell: bash
- name: Tests pass (debug)
run: |
cargo run --manifest-path test-crates/samplebin/Cargo.toml
continue-on-error: ${{ matrix.os == 'windows-latest' }}
shell: bash
- name: Tests pass (release)
run: |
cargo run --manifest-path test-crates/samplebin/Cargo.toml --release
continue-on-error: ${{ matrix.os == 'windows-latest' }}
shell: bash
- name: Add nightly
run: rustup toolchain add nightly
- name: Bin stable, mod_a nightly (should fail)
run: |
! cargo +stable run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=nightly
output=$(cargo +stable run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=nightly 2>&1)
if [[ $output != *"feature mismatch for crate"* ]]; then
echo "Expected feature mismatch error, but got:"
echo "$output"
exit 1
fi
shell: bash
- name: Bin nightly, mod_a stable (should fail)
run: |
! cargo +nightly run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=stable
output=$(cargo +nightly run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=stable 2>&1)
if [[ $output != *"feature mismatch for crate"* ]]; then
echo "Expected feature mismatch error, but got:"
echo "$output"
exit 1
fi
shell: bash
- name: All nightly (should work)
run: |
cargo +nightly run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=nightly --channel:mod_b=nightly
shell: bash
- name: Bin has mokio-timer feature (should fail)
run: |
! cargo run --features=exports/mokio-timer --manifest-path test-crates/samplebin/Cargo.toml
output=$(cargo run --features=exports/mokio-timer --manifest-path test-crates/samplebin/Cargo.toml 2>&1)
if [[ $output != *"feature mismatch for crate"* ]]; then
echo "Expected feature mismatch error, but got:"
echo "$output"
exit 1
fi
shell: bash
- name: mod_a has mokio-timer feature (should fail)
run: |
! cargo run --manifest-path test-crates/mod_a/Cargo.toml -- --features:mod_a=mokio/timer
output=$(cargo run --manifest-path test-crates/mod_a/Cargo.toml -- --features:mod_a=mokio/timer 2>&1)
if [[ $output != *"feature mismatch for crate"* ]]; then
echo "Expected feature mismatch error, but got:"
echo "$output"
exit 1
fi
shell: bash
- name: mod_b has mokio-timer feature (should fail)
run: |
! cargo run --manifest-path test-crates/mod_b/Cargo.toml -- --features:mod_b=mokio/timer
output=$(cargo run --manifest-path test-crates/mod_b/Cargo.toml -- --features:mod_b=mokio/timer 2>&1)
if [[ $output != *"feature mismatch for crate"* ]]; then
echo "Expected feature mismatch error, but got:"
echo "$output"
exit 1
fi
shell: bash
- name: all mods have mokio-timer feature (should fail)
run: |
! cargo run --manifest-path test-crates/samplebin/Cargo.toml -- --features:mod_a=mokio/timer --features:mod_b=mokio/timer
output=$(cargo run --manifest-path test-crates/samplebin/Cargo.toml -- --features:mod_a=mokio/timer --features:mod_b=mokio/timer 2>&1)
if [[ $output != *"feature mismatch for crate"* ]]; then
echo "Expected feature mismatch error, but got:"
echo "$output"
exit 1
fi
shell: bash
- name: bin and mods have mokio-timer feature (should work)
run: |
cargo run --features=exports/mokio-timer --manifest-path test-crates/samplebin/Cargo.toml -- --features:mod_a=mokio/timer --features:mod_b=mokio/timer
Expand Down
2 changes: 0 additions & 2 deletions rubicon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,6 @@ macro_rules! compatibility_check {

let binary_label = format!("Binary {}", blue(&exe_name));
let module_label = format!("Module {}", blue(so_name));
println!("visible_len(binary_label) = {}", visible_len(&binary_label));
println!("visible_len(module_label) = {}", visible_len(&module_label));

let binary_label_width = visible_len(&binary_label);
let module_label_width = visible_len(&module_label);
Expand Down
10 changes: 10 additions & 0 deletions test-crates/samplebin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ fn main() {
)
}

soprintln!(
"DYLD_LIBRARY_PATH = {}",
std::env::var("DYLD_LIBRARY_PATH").unwrap_or_default()
);
soprintln!(
"LD_LIBRARY_PATH = {}",
std::env::var("LD_LIBRARY_PATH").unwrap_or_default()
);
soprintln!("PATH = {}", std::env::var("PATH").unwrap_or_default());

soprintln!("loading modules...");
let lib_a = unsafe { libloading::Library::new(module_path("a")).unwrap() };
let lib_a = Box::leak(Box::new(lib_a));
Expand Down
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
215 changes: 215 additions & 0 deletions tests/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import { spawn, execSync } from "child_process";
import chalk from "chalk";
import os from "os";
import { existsSync } from "fs";
import { dirname } from "path";

let ENV_VARS = {};

// Helper function to set environment variables
function setEnvVariables() {
const rustSysroot = execSync("rustc --print sysroot").toString().trim();
const rustNightlySysroot = execSync("rustc +nightly --print sysroot")
.toString()
.trim();

const platform = os.platform();
if (platform === "darwin") {
console.log("🍎 Detected macOS");
ENV_VARS.DYLD_LIBRARY_PATH = `${rustSysroot}/lib:${rustNightlySysroot}/lib`;
} else if (platform === "win32") {
console.log("🪟 Detected Windows");
ENV_VARS.PATH += `;${process.env.PATH};${rustSysroot}/lib;${rustNightlySysroot}/lib`;
} else if (platform === "linux") {
console.log("🐧 Detected Linux");
ENV_VARS.LD_LIBRARY_PATH = `${rustSysroot}/lib:${rustNightlySysroot}/lib`;
} else {
console.log(`❌ Unsupported platform: ${platform}`);
process.exit(1);
}

console.log("\nEnvironment Variables Summary:");
for (const [key, value] of Object.entries(ENV_VARS)) {
console.log(`${key}: ${value}`);
}
}

// Helper function to run a command and capture output
function runCommand(command) {
try {
const child = spawn(command, [], {
shell: true,
stdio: ["inherit", "pipe", "pipe"],
env: {
SOPRINTLN: "1",
PATH: process.env.PATH,
...ENV_VARS,
},
});
console.log("Set ENV_VARS to: ", ENV_VARS);

let output = "";

child.stdout.on("data", (data) => {
process.stdout.write(data);
output += data;
});

child.stderr.on("data", (data) => {
process.stderr.write(data);
output += data;
});

return new Promise((resolve) => {
child.on("close", (code) => {
resolve({
success: code === 0,
output: output,
});
});
});
} catch (error) {
process.stderr.write(chalk.red(error.toString()));
return Promise.resolve({
success: false,
output: error.toString(),
});
}
}

// Helper function to check for feature mismatch
function checkFeatureMismatch(output) {
return output.includes("feature mismatch for crate");
}

// Test cases
const testCases = [
{
name: "Tests pass (debug)",
command: "cargo run --manifest-path test-crates/samplebin/Cargo.toml",
expectedResult: "success",
},
{
name: "Tests pass (release)",
command:
"cargo run --manifest-path test-crates/samplebin/Cargo.toml --release",
expectedResult: "success",
},
{
name: "Bin stable, mod_a nightly (should fail)",
command:
"cargo +stable run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=nightly",
expectedResult: "fail",
checkFeatureMismatch: true,
},
{
name: "Bin nightly, mod_a stable (should fail)",
command:
"cargo +nightly run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=stable",
expectedResult: "fail",
checkFeatureMismatch: true,
},
{
name: "All nightly (should work)",
command:
"cargo +nightly run --manifest-path test-crates/samplebin/Cargo.toml -- --channel:mod_a=nightly --channel:mod_b=nightly",
expectedResult: "success",
},
{
name: "Bin has mokio-timer feature (should fail)",
command:
"cargo run --features=exports/mokio-timer --manifest-path test-crates/samplebin/Cargo.toml",
expectedResult: "fail",
checkFeatureMismatch: true,
},
{
name: "mod_a has mokio-timer feature (should fail)",
command:
"cargo run --manifest-path test-crates/mod_a/Cargo.toml -- --features:mod_a=mokio/timer",
expectedResult: "fail",
checkFeatureMismatch: true,
},
{
name: "mod_b has mokio-timer feature (should fail)",
command:
"cargo run --manifest-path test-crates/mod_b/Cargo.toml -- --features:mod_b=mokio/timer",
expectedResult: "fail",
checkFeatureMismatch: true,
},
{
name: "all mods have mokio-timer feature (should fail)",
command:
"cargo run --manifest-path test-crates/samplebin/Cargo.toml -- --features:mod_a=mokio/timer --features:mod_b=mokio/timer",
expectedResult: "fail",
checkFeatureMismatch: true,
},
{
name: "bin and mods have mokio-timer feature (should work)",
command:
"cargo run --features=exports/mokio-timer --manifest-path test-crates/samplebin/Cargo.toml -- --features:mod_a=mokio/timer --features:mod_b=mokio/timer",
expectedResult: "success",
},
];

// Main function to run tests
async function runTests() {
console.log(chalk.blue("Changing working directory to Git root..."));
let currentDir = process.cwd();

while (!existsSync(`${currentDir}/.git`)) {
const parentDir = dirname(currentDir);
if (parentDir === currentDir) {
console.log(chalk.red("Git root not found. Exiting."));
process.exit(1);
}
currentDir = parentDir;
}
process.chdir(currentDir);
console.log(chalk.green(`Changed working directory to: ${currentDir}`));
console.log(chalk.blue("Checking Rust version and toolchain..."));
console.log(chalk.yellow("rustc --version:"));
await runCommand("rustc --version");
console.log(chalk.yellow("\nrustup which rustc:"));
await runCommand("rustup which rustc");
console.log("");

console.log(chalk.blue("Setting up environment variables..."));
setEnvVariables();

console.log(chalk.blue("Installing nightly Rust..."));
await runCommand("rustup toolchain add nightly");

console.log(chalk.blue("Running tests..."));
for (const [index, test] of testCases.entries()) {
console.log(chalk.yellow(`\nRunning test ${index + 1}: ${test.name}`));
const { success, output } = await runCommand(test.command);

if (test.expectedResult === "success" && success) {
console.log(chalk.green("Test passed as expected."));
} else if (test.expectedResult === "fail" && !success) {
if (test.checkFeatureMismatch && checkFeatureMismatch(output)) {
console.log(
chalk.green("Test failed with feature mismatch as expected."),
);
} else {
console.log(
chalk.red(
"Test failed, but not with the expected feature mismatch error.",
),
);
}
} else {
console.log(
chalk.red(
`Test result unexpected. Expected ${test.expectedResult}, but got ${success ? "success" : "failure"}.`,
),
);
}
}
}

// Run the tests
runTests().catch((error) => {
console.error(chalk.red(`An error occurred: ${error.message}`));
process.exit(1);
});
28 changes: 28 additions & 0 deletions tests/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "tests",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"chalk": "^5.3.0"
}
}

0 comments on commit 327500d

Please sign in to comment.