Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tests): improve test suite #27

Merged
merged 8 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
env:
DENO_VERSION: "1.38.5"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GHJK_LOG_PANIC_LEVEL: error

jobs:
changes:
Expand Down
32 changes: 32 additions & 0 deletions deno.lock

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

3 changes: 2 additions & 1 deletion deps/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

export { z as zod } from "https://deno.land/x/[email protected]/mod.ts";
export * as semver from "https://deno.land/[email protected]/semver/mod.ts";
export * as log from "https://deno.land/[email protected]/log/mod.ts";
export * as std_log from "https://deno.land/[email protected]/log/mod.ts";
export * as std_log_levels from "https://deno.land/[email protected]/log/levels.ts";
export * as std_fmt_colors from "https://deno.land/[email protected]/fmt/colors.ts";
export * as std_url from "https://deno.land/[email protected]/url/mod.ts";
export * as std_path from "https://deno.land/[email protected]/path/mod.ts";
Expand Down
2 changes: 1 addition & 1 deletion deps/dev.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! dependencies used by tests

export * from "./common.ts";
export * as std_assert from "https://deno.land/std@0.205.0/assert/mod.ts";
export * as std_assert from "https://deno.land/std@0.210.0/assert/mod.ts";
6 changes: 3 additions & 3 deletions ghjk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ ghjk.install(
// protoc(),
// ruff(),
// whiz(),
// jco()[0],
...jco(),
// cpython(),
);

// these are used for developing ghjk
ghjk.install(
act(),
...pipi({ packageName: "pre-commit" }),
// act(),
// ...pipi({ packageName: "pre-commit" }),
);

export const secureConfig = ghjk.secureConfig({
Expand Down
2 changes: 2 additions & 0 deletions install/hook.fish
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ function ghjk_reload --on-variable PWD
# load the shim
. $envDir/loader.fish

# FIXME: older versions of fish don't recognize -ot
# those in debian
if test $envDir/loader.fish -ot $cur_dir/ghjk.ts
set_color FF4500
echo "[ghjk] Detected changes, please sync..."
Expand Down
4 changes: 2 additions & 2 deletions modules/ports/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export ${k}='${v}';`
...Object.entries(pathVars).map(([k, v]) =>
// NOTE: double quote the path vars for expansion
// single quote GHJK_CLEANUP additions to avoid expansion/exec before eval
`GHJK_CLEANUP_POSIX=$GHJK_CLEANUP_POSIX'${k}=$(echo "$${k}" | tr ":" "\\n" | grep -vE "^${envDir}" | tr "\\n" ":");${k}="\${${k}%:}"';
`GHJK_CLEANUP_POSIX=$GHJK_CLEANUP_POSIX'${k}=$(echo "$${k}" | tr ":" "\\n" | grep -vE "^${envDir}" | tr "\\n" ":");${k}="\${${k}%:}";';
export ${k}="${v}:$${k}";
`
),
Expand Down Expand Up @@ -65,7 +65,7 @@ set --global --prepend ${k} ${v};
/// or just pointing to targetDir/tmp
/// This is handy for making moves atomics from
/// tmp dirs to to locations within targetDir
async function movebleTmpPath(targetDir: string, targetTmpDirName = "dir") {
async function movebleTmpPath(targetDir: string, targetTmpDirName = "tmp") {
const defaultTmp = Deno.env.get("TMPDIR");
const targetPath = $.path(targetDir);
if (!defaultTmp) {
Expand Down
53 changes: 53 additions & 0 deletions ports/dummy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//! this is a dumb port to be used for testing

import type {
DownloadArgs,
InstallArgs,
InstallConfigSimple,
} from "../port.ts";
import { $, ALL_ARCH, ALL_OS, osXarch, PortBase, std_fs } from "../port.ts";

const manifest = {
ty: "denoWorker@v1" as const,
name: "dummy",
version: "0.1.0",
moduleSpecifier: import.meta.url,
deps: [],
platforms: osXarch([...ALL_OS], [...ALL_ARCH]),
};

export default function conf(config: InstallConfigSimple = {}) {
return {
...config,
port: manifest,
};
}

export class Port extends PortBase {
execEnv() {
return {
DUMMY_ENV: "dummy",
};
}

listAll() {
return ["dummy"];
}

async download(args: DownloadArgs) {
// TODO: windows suport
await $.path(args.downloadPath).join("bin", "dummy").writeText(
`#!/bin/sh
echo 'dummy hey'`,
{
mode: 0o700,
},
);
}

async install(args: InstallArgs) {
const installPath = $.path(args.installPath);
await $.removeIfExists(installPath);
await std_fs.copy(args.downloadPath, args.installPath);
}
}
65 changes: 26 additions & 39 deletions ports/jco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@ import {
ALL_ARCH,
ALL_OS,
depExecShimPath,
downloadFile,
dwnUrlOut,
osXarch,
pathsWithDepArts,
PortBase,
std_fs,
std_path,
unarchive,
} from "../port.ts";
import node from "./node.ts";
import * as std_ports from "../modules/ports/std.ts";
Expand Down Expand Up @@ -58,47 +54,38 @@ export class Port extends PortBase {
return versions;
}

downloadUrls(args: DownloadArgs) {
const { installVersion } = args;
return [
`https://registry.npmjs.org/@bytecodealliance/jco/-/jco-${installVersion}.tgz`,
].map(dwnUrlOut);
}

async download(args: DownloadArgs) {
const urls = this.downloadUrls(args);
await Promise.all(
urls.map((obj) => downloadFile({ ...args, ...obj })),
);
if (await $.path(args.downloadPath).exists()) {
return;
}
await $`${
depExecShimPath(std_ports.node_org, "npm", args.depArts)
} install --no-fund jco@${args.installVersion}`
.cwd(args.tmpDirPath)
.env(pathsWithDepArts(args.depArts, args.platform.os));
std_fs.move(args.tmpDirPath, args.downloadPath);
}

// FIXME: replace shebangs with the runtime dep node path
// default shebangs just use #!/bin/env node
async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);

await unarchive(fileDwnPath, args.tmpDirPath);
await std_fs.copy(
args.downloadPath,
args.tmpDirPath,
{ overwrite: true },
);

const installPath = $.path(args.installPath);
if (await installPath.exists()) {
await installPath.remove({ recursive: true });
}

await std_fs.copy(
std_path.resolve(
args.tmpDirPath,
"package",
),
args.installPath,
);
await $`${
depExecShimPath(std_ports.node_org, "npm", args.depArts)
} install --no-fund`
.cwd(args.installPath)
.env(pathsWithDepArts(args.depArts, args.platform.os));
await installPath.join("bin").ensureDir();
await installPath.join("bin", "jco")
.createSymlinkTo(installPath.join("src", "jco.js").toString(), {
// kind: "relative",
});
const tmpDirPath = $.path(args.tmpDirPath);
await tmpDirPath.join("bin").ensureDir();
await tmpDirPath.join("bin", "jco")
.createSymlinkTo(
installPath
.join("node_modules", ".bin", "jco")
.toString(),
);
await $.removeIfExists(installPath);
await std_fs.move(tmpDirPath.toString(), installPath.toString());
}
}
135 changes: 135 additions & 0 deletions tests/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import "../setup_logger.ts";
import { dockerE2eTest, E2eTestCase, localE2eTest } from "./utils.ts";
import dummy from "../ports/dummy.ts";

// avoid using single quotes in this script
const posixInteractiveScript = `
set -eux
dummy
pushd ../
# it shouldn't be avail here
[ $(set +e; dummy) ] && exit 123
# cd back in
popd
# now it should be avail
dummy
`;

// avoid using single quotes in this script
const posixNonInteractiveScript = `
set -eux
# test that ghjk_reload is avail because BASH_ENV exposed by the suite
ghjk_reload
dummy
pushd ../
# no reload so it's stil avail
dummy
ghjk_reload
# it shouldn't be avail now
[ $(set +e; dummy) ] && exit 123
# cd back in
popd
# not avail yet
[ $(set +e; dummy) ] && exit 123
ghjk_reload
# now it should be avail
dummy
`;

const fishScript = `
dummy; or exit 123
pushd ../
# it shouldn't be avail here
dummy; and exit 123
# cd back in
popd
# now it should be avail
dummy; or exit 123
`;

type CustomE2eTestCase = Omit<E2eTestCase, "ePoints"> & {
ePoint: string;
stdin: string;
};
const cases: CustomE2eTestCase[] = [
{
installConf: dummy(),
name: "hook_test_bash_interactive",
// -s: read from stdin
// -l: login/interactive mode
ePoint: `bash -sl`,
stdin: posixInteractiveScript,
},
{
installConf: dummy(),
name: "hook_test_bash_scripting",
ePoint: `bash -s`,
stdin: posixNonInteractiveScript,
},
{
installConf: dummy(),
name: "hook_test_zsh_interactive",
ePoint: `zsh -sl`,
stdin: posixInteractiveScript,
},
{
installConf: dummy(),
name: "hook_test_zsh_scripting",
ePoint: `zsh -s`,
stdin: posixNonInteractiveScript,
},
{
installConf: dummy(),
name: "hook_test_fish_interactive",
ePoint: `fish -l`,
stdin: fishScript,
},
{
installConf: dummy(),
name: "hook_test_fish_scripting",
ePoint: `fish`,
// the fish implementation triggers changes
// on any pwd changes so it's identical to
// interactive usage
stdin: fishScript,
},
];

function testMany(
testGroup: string,
cases: CustomE2eTestCase[],
testFn: (inp: E2eTestCase) => Promise<void>,
defaultEnvs: Record<string, string> = {},
) {
for (const testCase of cases) {
Deno.test(
`${testGroup} - ${testCase.name}`,
() =>
testFn({
...testCase,
ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }],
envs: {
...defaultEnvs,
...testCase.envs,
},
}),
);
}
}

const e2eType = Deno.env.get("GHJK_TEST_E2E_TYPE");
if (e2eType == "both") {
testMany("hooksDockerE2eTest", cases, dockerE2eTest);
testMany(`hooksLocalE2eTest`, cases, localE2eTest);
} else if (e2eType == "local") {
testMany("hooksLocalE2eTest", cases, localE2eTest);
} else if (
e2eType == "docker" ||
!e2eType
) {
testMany("hooksDockerE2eTest", cases, dockerE2eTest);
} else {
throw new Error(
`unexpected GHJK_TEST_E2E_TYPE: ${e2eType}`,
);
}
6 changes: 3 additions & 3 deletions tests/ports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ function testMany(
() =>
testFn({
...testCase,
ePoints: ["bash -c", "fish -c", "zsh -c"].map((sh) =>
`env ${sh} '${testCase.ePoint}'`
),
ePoints: ["bash -c", "fish -c", "zsh -c"].map((sh) => ({
cmd: `env ${sh} '${testCase.ePoint}'`,
})),
envs: {
...defaultEnvs,
...testCase.envs,
Expand Down
Loading
Loading