1246 lines
34 KiB
JavaScript
1246 lines
34 KiB
JavaScript
import {
|
|
test,
|
|
b4a,
|
|
Hyperdrive,
|
|
Corestore,
|
|
mkdirSync,
|
|
rmSync,
|
|
readFile,
|
|
readdir,
|
|
path,
|
|
fileURLToPath,
|
|
PassThrough,
|
|
XTERM_CLEAR_SCROLLBACK_AND_VIEWPORT,
|
|
runKernelFromSource,
|
|
runBinCommand,
|
|
createGitFsFromVfs,
|
|
runGitCli,
|
|
createStreamLineReader,
|
|
sanitizeInteractiveShellLine,
|
|
createVfs,
|
|
BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE,
|
|
parseHdmsPairArgv,
|
|
hcCrypto,
|
|
idEnc,
|
|
decodeRwShareOffer,
|
|
decodeShareOffer,
|
|
HDMS_AUTOPASS_SHARE_KEY,
|
|
HDMS_AUTOPASS_SHARE_RW_KEY,
|
|
normalizeWriterSecretHex,
|
|
buildBareOsHypercorePackHrpcLifecycleProcJson,
|
|
buildBareOsPearCorestoreHrpcProcJson,
|
|
buildBareOsPearInspectLoggerTlsProcJson,
|
|
buildBareOsBareRuntimeProtoMuxProcJson,
|
|
buildBareOsBootGraphProcJson,
|
|
pathnameExpandShellWord,
|
|
createBareOsIpc,
|
|
BareOsSwarmConnectionManager,
|
|
createBareOsLifecycleStateMachine,
|
|
runTransactionalLifecycleHooks,
|
|
bareOsRegisterCorestoreSuspendResumeHooks,
|
|
bareOsInstallCorestoreSuspendResumeHooks,
|
|
bareOsFindOrphanProcessRows,
|
|
topologicalOrderKernelExtensions,
|
|
resolveKernelExtensionsFull,
|
|
createBareOsProtomuxAliasRegistry,
|
|
bareOsHttpUrlAllowed,
|
|
bareOsParseBareAclText,
|
|
bareOsAclDeniesSubject,
|
|
raceWithAbortAndTimeout,
|
|
tokenize,
|
|
expandWord,
|
|
execShellLine,
|
|
expandArgvAliases,
|
|
defaultShellAliases,
|
|
loadBarerc,
|
|
BARERC_SKELETON,
|
|
splitTokensBySemicolon,
|
|
splitTokensByAndOr,
|
|
bareOsShellAstSnapshot,
|
|
planShellRedirections,
|
|
buildShellExecutionGraph,
|
|
dispatchShellTrapSignal,
|
|
BARE_OS_EXIT_STATUS_ENV,
|
|
syncBareOsExitStatusEnv,
|
|
getBareOsPipelineLimits,
|
|
DEFAULT_PIPELINE_MAX_STAGES,
|
|
tokenizeBareShellLineDetailed,
|
|
decodeBareOsDollarQuote,
|
|
applyBareOsThemeFromEnv,
|
|
bareOsListThemeNames,
|
|
bareParseLsColors,
|
|
bareSerializeLsColors,
|
|
bareLsColorOpenSgrFromMap,
|
|
bareDefaultDircolorsDatabase,
|
|
bareParseDircolorsDatabase,
|
|
BARE_OS_CTX_API_VERSION,
|
|
buildBareOsRuntimeCaps,
|
|
bareOsBareModulesEnabled,
|
|
bareOsBareModuleManifestEmbeddedRef,
|
|
buildBareCtxObjectFromHost,
|
|
buildPearCtxObjectFromHost,
|
|
loadBareModuleManifest,
|
|
maybeMergeBareFromDrive,
|
|
maybeBareOsBuildBinManifest,
|
|
createFishReadLine,
|
|
fuzzyMatch,
|
|
stripAnsi,
|
|
parseHistoryFile,
|
|
formatHistoryFile,
|
|
dedupeConsecutiveHistory,
|
|
searchHistoryEntries,
|
|
shouldPersistShellHistoryCommand,
|
|
scrubShellHistoryEntries,
|
|
SHELL_BUILTINS,
|
|
resolveShellPromptHookSegment,
|
|
parseCompletionContext,
|
|
rankCompletionItems,
|
|
suggestGhostFromHistory,
|
|
suggestGhostFromFs,
|
|
ghostReplaceCurrentWord,
|
|
longestCommonCompletionPrefix,
|
|
completeLine,
|
|
levenshtein,
|
|
fieldMatches,
|
|
dowFieldMatches,
|
|
parseCronLine,
|
|
jobMatchesDate,
|
|
bareInitdReadinessSnapshot,
|
|
bareInitdShutdownActiveUnitsReverse,
|
|
getBareServiceRuntime,
|
|
registerBareInitdDisposer,
|
|
registerKernelShutdownHook,
|
|
runKernelShutdownHooks,
|
|
startBareInitd,
|
|
stopBareInitd,
|
|
getLastBareInitdDagSnapshotJson,
|
|
appendVarLog,
|
|
ensureBareOsVarLogTree,
|
|
KERNEL_CONSOLE_LOG,
|
|
BOOT_LOG,
|
|
bareOsKernelMetricsReset,
|
|
bareOsKernelMetricsSnapshot,
|
|
parseUnitDropInText,
|
|
bareOsHyperswarmOptsFromEnv,
|
|
bareOsBootJoinPeerHexFromEnv,
|
|
bareOsBootInitPrefetchEnabled,
|
|
bareOsBootWarmBinDownloadDiffEnabled,
|
|
bareOsProcessTableSnapshot,
|
|
buildBareOsSyscallsProcJson,
|
|
bareOsParseSendmsgScmRights,
|
|
wantPosixSocketScmRights,
|
|
parseBareOsHrpcAllowlistJson,
|
|
bareOsHrpcAllowlistDeniesRoute,
|
|
buildBareOsProtomuxExtensionsProcJson,
|
|
createBareOsDiskOsBridge,
|
|
buildBareOsReplicationLiveSketch,
|
|
evaluateBareOsPeerAdmission,
|
|
bareOsFormatPeerAdmissionAuditEvent,
|
|
bareOsPeerAdmissionAuditRateAllow,
|
|
parseDelegateAllowSet,
|
|
isDelegateKindAllowed,
|
|
bareOsAuditAppend,
|
|
bareOsAuditVerifyRows,
|
|
bareOsDrainFcntlLockWaiters,
|
|
buildBareOsReplicationOperatorSurfaceProcJson,
|
|
DEFAULT_CURL_USER_AGENT,
|
|
DEFAULT_WGET_USER_AGENT,
|
|
filenameFromContentDisposition,
|
|
encodeUstarHeader,
|
|
runTarCli,
|
|
require,
|
|
__dirname,
|
|
TAR_BLK,
|
|
concatTarParts,
|
|
headerFromInit,
|
|
testCorestoreDir,
|
|
testCtx,
|
|
personalHomeBacking,
|
|
readBuiltBin
|
|
} from './test/_helpers.js'
|
|
|
|
test('systemctl list-units delegates to same backend', async (t) => {
|
|
const dir = testCorestoreDir('initctlsys')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pics'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const logs = []
|
|
const ctx = testCtx(sys, personal)
|
|
ctx.execLine = async () => {}
|
|
await startBareInitd(ctx)
|
|
ctx.console = {
|
|
log: (...a) => logs.push(a.join(' ')),
|
|
error: (...a) => logs.push(a.join(' '))
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['systemctl', 'list-units'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(logs.join('\n').includes('bare-cron'))
|
|
stopBareInitd()
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('systemctl is-active matches bare-initd runtime', async (t) => {
|
|
const dir = testCorestoreDir('initctlactive')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pica'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const logs = []
|
|
const ctx = testCtx(sys, personal)
|
|
ctx.execLine = async () => {}
|
|
await startBareInitd(ctx)
|
|
ctx.console = {
|
|
log: (...a) => logs.push(a.join(' ')),
|
|
error: (...a) => logs.push(a.join(' '))
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['systemctl', 'is-active', 'kernel-logger'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(logs.join('\n').includes('active'))
|
|
logs.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['systemctl', 'is-active', 'nonexistent-unit'])
|
|
t.is(ctx.exitCode, 3)
|
|
stopBareInitd()
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('systemctl status bare-openssh.service accepts .service suffix', async (t) => {
|
|
const dir = testCorestoreDir('initctlsvc')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('picsvc'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const logs = []
|
|
const ctx = testCtx(sys, personal)
|
|
ctx.execLine = async () => {}
|
|
await startBareInitd(ctx)
|
|
ctx.console = {
|
|
log: (...a) => logs.push(a.join(' ')),
|
|
error: (...a) => logs.push(a.join(' '))
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['systemctl', 'status', 'bare-openssh.service'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(logs.join('\n').includes('bare-openssh'))
|
|
stopBareInitd()
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('systemctl restart bare-cron succeeds', async (t) => {
|
|
const dir = testCorestoreDir('initctlrst')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('picr'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const logs = []
|
|
const ctx = testCtx(sys, personal)
|
|
ctx.execLine = async () => {}
|
|
await startBareInitd(ctx)
|
|
ctx.console = {
|
|
log: (...a) => logs.push(a.join(' ')),
|
|
error: (...a) => logs.push(a.join(' '))
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['systemctl', 'restart', 'bare-cron'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(logs.some((l) => /restarted bare-cron/i.test(l)))
|
|
stopBareInitd()
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('systemctl restart unknown unit is explicit nonzero', async (t) => {
|
|
const dir = testCorestoreDir('initctlunknown')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('punknown'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const logs = []
|
|
const ctx = testCtx(sys, personal)
|
|
ctx.execLine = async () => {}
|
|
await startBareInitd(ctx)
|
|
ctx.console = {
|
|
log: (...a) => logs.push(a.join(' ')),
|
|
error: (...a) => logs.push(a.join(' '))
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['systemctl', 'restart', 'nonunit'])
|
|
t.is(ctx.exitCode, 1)
|
|
t.ok(logs.some((l) => /unknown unit/i.test(l)))
|
|
stopBareInitd()
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('initd disabled.txt skips unit on boot; systemctl enable undoes', async (t) => {
|
|
const dir = testCorestoreDir('initdis')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pdis'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const ctx = testCtx(sys, personal)
|
|
ctx.execLine = async () => {}
|
|
await ctx.vfs.mkdir('/home/user/.config/bare-os/initd', { recursive: true })
|
|
await ctx.vfs.writeFile(
|
|
'/home/user/.config/bare-os/initd/disabled.txt',
|
|
b4a.from('bare-cron\n')
|
|
)
|
|
await startBareInitd(ctx)
|
|
t.is(getBareServiceRuntime('bare-cron'), undefined)
|
|
t.is(getBareServiceRuntime('kernel-logger')?.phase, 'active')
|
|
stopBareInitd()
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log: () => {},
|
|
error: () => {}
|
|
}
|
|
await runBinCommand(ctx, ['systemctl', 'enable', 'bare-cron'])
|
|
t.is(ctx.exitCode, 0)
|
|
await startBareInitd(ctx)
|
|
t.is(getBareServiceRuntime('bare-cron')?.phase, 'active')
|
|
stopBareInitd()
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('stopBareInitd runs registered disposers', async (t) => {
|
|
let n = 0
|
|
registerBareInitdDisposer(() => {
|
|
n++
|
|
})
|
|
stopBareInitd()
|
|
t.is(n, 1)
|
|
stopBareInitd()
|
|
t.is(n, 2)
|
|
})
|
|
|
|
test('runKernelShutdownHooks runs LIFO once', async (t) => {
|
|
const o = []
|
|
registerKernelShutdownHook(async () => {
|
|
o.push('a')
|
|
})
|
|
registerKernelShutdownHook(async () => {
|
|
o.push('b')
|
|
})
|
|
await runKernelShutdownHooks()
|
|
t.is(o.join(','), 'b,a')
|
|
await runKernelShutdownHooks()
|
|
t.is(o.join(','), 'b,a')
|
|
})
|
|
|
|
test('bareInitdShutdownActiveUnitsReverse is safe when nothing is active', async (t) => {
|
|
stopBareInitd()
|
|
await bareInitdShutdownActiveUnitsReverse({ vfs: null, console, env: {} })
|
|
t.pass()
|
|
})
|
|
|
|
test('/proc/bare_os/clock.json is readable pseudo JSON', async (t) => {
|
|
const dir = testCorestoreDir('clock-proc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pc'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const bootStartedMs = Date.now() - 50
|
|
const shellEnv = {
|
|
HOME: '/home/user',
|
|
PATH: '/bin',
|
|
USER: 'user',
|
|
UID: '1000',
|
|
GID: '1000',
|
|
PWD: '/home/user',
|
|
BARE_OS_EXIT_STATUS: '0'
|
|
}
|
|
const vfs = createVfs(drive, personal, shellEnv, null, {
|
|
bareOsIpc: createBareOsIpc(),
|
|
procBareOsClockText() {
|
|
const wallMs = Date.now()
|
|
return `${JSON.stringify({
|
|
schema: 1,
|
|
CLOCK_REALTIME_MS: wallMs,
|
|
CLOCK_BOOTTIME_RELATIVE_MS: wallMs - bootStartedMs,
|
|
CLOCK_MONOTONIC_NS_FROM_PERF: null
|
|
})}\n`
|
|
}
|
|
})
|
|
const raw = b4a.toString(await vfs.readFile('/proc/bare_os/clock.json'))
|
|
const j = JSON.parse(raw)
|
|
t.is(j.schema, 1)
|
|
t.ok(typeof j.CLOCK_REALTIME_MS === 'number')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('/proc/self/fd lists extras from getProcSelfExtraFds', async (t) => {
|
|
const dir = testCorestoreDir('self-fd-extra')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pc'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const shellEnv = {
|
|
HOME: '/home/user',
|
|
PATH: '/bin',
|
|
USER: 'user',
|
|
UID: '1000',
|
|
GID: '1000',
|
|
PWD: '/home/user',
|
|
BARE_OS_EXIT_STATUS: '0'
|
|
}
|
|
const vfs = createVfs(drive, personal, shellEnv, null, {
|
|
bareOsIpc: createBareOsIpc(),
|
|
getProcSelfExtraFds: () => [{ fdNum: '7', target: 'pipe:[bare-test]' }]
|
|
})
|
|
const names = await vfs.readdir('/proc/self/fd')
|
|
t.ok(names.includes('7'))
|
|
const txt = b4a.toString(await vfs.readFile('/proc/self/fd/7'))
|
|
t.ok(txt.includes('pipe:[bare-test]'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('fish-readline stripAnsi and fuzzyMatch', async (t) => {
|
|
t.is(stripAnsi('\x1b[32mhi\x1b[0m'), 'hi')
|
|
t.is(stripAnsi('\x1b[38;5;12mhi\x1b[0m'), 'hi')
|
|
t.ok(fuzzyMatch('hello', 'hlo'))
|
|
t.ok(!fuzzyMatch('hello', 'hxo'))
|
|
})
|
|
|
|
test('terminal-escapes xterm clear scrollback and viewport', async (t) => {
|
|
t.is(
|
|
XTERM_CLEAR_SCROLLBACK_AND_VIEWPORT,
|
|
'\x1b[H\x1b[3J\x1b[2J\x1b[0m'
|
|
)
|
|
})
|
|
|
|
test('fish-readline bracketed paste keeps embedded CSI as literal text', async (t) => {
|
|
const stdin = new PassThrough()
|
|
stdin.isTTY = true
|
|
stdin.setRawMode = () => {}
|
|
const out = []
|
|
const stdout = {
|
|
columns: 120,
|
|
rows: 40,
|
|
write(s) {
|
|
out.push(String(s))
|
|
},
|
|
cursorTo() {},
|
|
clearLine() {}
|
|
}
|
|
const ctx = {
|
|
vfs: {
|
|
getcwd: () => '/home/guest',
|
|
async readdir() {
|
|
return []
|
|
}
|
|
},
|
|
env: {},
|
|
b4a: null,
|
|
personalDrive: null
|
|
}
|
|
const rl = await createFishReadLine(ctx, { stdin, stdout })
|
|
t.ok(typeof rl === 'function')
|
|
const p = rl('> ')
|
|
stdin.write('\x1b[200~touch \x1b[Afile\x1b[201~\n')
|
|
const line = await p
|
|
t.is(line, 'touch \x1b[Afile')
|
|
stdin.end()
|
|
})
|
|
|
|
test('fish-readline ignores xterm focus in out CSI', async (t) => {
|
|
const stdin = new PassThrough()
|
|
stdin.isTTY = true
|
|
stdin.setRawMode = () => {}
|
|
const stdout = {
|
|
columns: 120,
|
|
rows: 40,
|
|
write() {},
|
|
cursorTo() {},
|
|
clearLine() {}
|
|
}
|
|
const ctx = {
|
|
vfs: {
|
|
getcwd: () => '/',
|
|
async readdir() {
|
|
return []
|
|
}
|
|
},
|
|
env: {},
|
|
b4a: null,
|
|
personalDrive: null
|
|
}
|
|
const rl = await createFishReadLine(ctx, { stdin, stdout })
|
|
const p = rl('> ')
|
|
stdin.write('\x1b[I\x1b[Oecho x\n')
|
|
t.is(await p, 'echo x')
|
|
stdin.end()
|
|
})
|
|
|
|
test('fish-readline clears ghost hint before submit newline', async (t) => {
|
|
const stdin = new PassThrough()
|
|
stdin.isTTY = true
|
|
stdin.setRawMode = () => {}
|
|
const out = []
|
|
const stdout = {
|
|
columns: 120,
|
|
rows: 40,
|
|
write(s) {
|
|
out.push(String(s))
|
|
},
|
|
cursorTo() {},
|
|
clearLine() {}
|
|
}
|
|
const ctx = {
|
|
vfs: {
|
|
env: { USER: 'guest' },
|
|
getcwd: () => '/mnt/myPeers',
|
|
async readdir() {
|
|
return []
|
|
}
|
|
},
|
|
env: {},
|
|
b4a,
|
|
personalDrive: {
|
|
async get() {
|
|
return b4a.from('#1:ls /bin\n')
|
|
},
|
|
async put() {}
|
|
}
|
|
}
|
|
const rl = await createFishReadLine(ctx, { stdin, stdout })
|
|
const p = rl('> ')
|
|
stdin.write('ls\n')
|
|
t.is(await p, 'ls')
|
|
|
|
const newlineIndex = out.findIndex((s) => s === '\n')
|
|
t.ok(newlineIndex > 0)
|
|
const beforeSubmitNewline = out
|
|
.slice(0, newlineIndex)
|
|
.map(stripAnsi)
|
|
.filter(Boolean)
|
|
.at(-1)
|
|
t.is(beforeSubmitNewline.endsWith('> ls'), true)
|
|
t.absent(beforeSubmitNewline.includes('/bin'))
|
|
stdin.end()
|
|
})
|
|
|
|
test('fish-readline ^L emits xterm clear sequence', async (t) => {
|
|
const stdin = new PassThrough()
|
|
stdin.isTTY = true
|
|
stdin.setRawMode = () => {}
|
|
const out = []
|
|
const stdout = {
|
|
columns: 120,
|
|
rows: 40,
|
|
write(s) {
|
|
out.push(String(s))
|
|
},
|
|
cursorTo() {},
|
|
clearLine() {}
|
|
}
|
|
const ctx = {
|
|
vfs: {
|
|
getcwd: () => '/',
|
|
async readdir() {
|
|
return []
|
|
}
|
|
},
|
|
env: {},
|
|
b4a: null,
|
|
personalDrive: null
|
|
}
|
|
const rl = await createFishReadLine(ctx, { stdin, stdout })
|
|
const p = rl('> ')
|
|
stdin.write('\x0c')
|
|
stdin.write('y\n')
|
|
await p
|
|
const joined = out.join('')
|
|
t.ok(joined.includes('\x1b[3J'))
|
|
t.ok(joined.includes('\x1b[2J'))
|
|
t.ok(joined.includes('\x1b[0m'))
|
|
stdin.end()
|
|
})
|
|
|
|
test('fish-readline history parse format dedupe search', async (t) => {
|
|
const parsed = parseHistoryFile('#1:a\n#2:b\n')
|
|
t.is(parsed.length, 2)
|
|
t.is(parsed[0].command, 'a')
|
|
const round = parseHistoryFile(formatHistoryFile(parsed))
|
|
t.is(round[1].command, 'b')
|
|
const deduped = dedupeConsecutiveHistory([
|
|
{ timestamp: 1, command: 'x' },
|
|
{ timestamp: 2, command: 'x' },
|
|
{ timestamp: 3, command: 'y' }
|
|
])
|
|
t.is(deduped.length, 2)
|
|
t.is(deduped[1].command, 'y')
|
|
const hist = [{ command: 'aa' }, { command: 'ba' }]
|
|
const found = searchHistoryEntries(hist, 'a')
|
|
t.ok(found.includes('ba'))
|
|
t.ok(found.includes('aa'))
|
|
})
|
|
|
|
test('fish-readline history excludes login commands', async (t) => {
|
|
t.absent(shouldPersistShellHistoryCommand('login hunter2'))
|
|
t.absent(shouldPersistShellHistoryCommand('login --new hunter2'))
|
|
t.absent(shouldPersistShellHistoryCommand('echo ok; login hunter2'))
|
|
t.ok(shouldPersistShellHistoryCommand('echo login hunter2'))
|
|
|
|
const scrubbed = scrubShellHistoryEntries([
|
|
{ timestamp: 1, command: 'login old-password' },
|
|
{ timestamp: 2, command: 'ls' }
|
|
])
|
|
t.is(scrubbed.removed, 1)
|
|
t.alike(scrubbed.entries, [{ timestamp: 2, command: 'ls' }])
|
|
})
|
|
|
|
test('resolveShellPromptHookSegment enforces timeout and fallback', async (t) => {
|
|
const fast = await resolveShellPromptHookSegment(
|
|
{ shellPromptHook: () => ' [fast]' },
|
|
{ BARE_OS_SHELL_PROMPT_HOOK_TIMEOUT_MS: '10' }
|
|
)
|
|
t.is(fast, ' [fast]')
|
|
const slow = await resolveShellPromptHookSegment(
|
|
{
|
|
shellPromptHook: async () => {
|
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
return ' [slow]'
|
|
}
|
|
},
|
|
{ BARE_OS_SHELL_PROMPT_HOOK_TIMEOUT_MS: '5' }
|
|
)
|
|
t.is(slow, '')
|
|
})
|
|
|
|
test('fish-readline scrubs and skips persisted login history', async (t) => {
|
|
const stdin = new PassThrough()
|
|
stdin.isTTY = true
|
|
stdin.setRawMode = () => {}
|
|
const stdout = {
|
|
columns: 120,
|
|
rows: 40,
|
|
write() {},
|
|
cursorTo() {},
|
|
clearLine() {}
|
|
}
|
|
let stored = b4a.from('#1:login old-password\n#2:ls\n')
|
|
const writes = []
|
|
const ctx = {
|
|
vfs: {
|
|
env: { USER: 'guest' },
|
|
getcwd: () => '/home/guest',
|
|
async readdir() {
|
|
return []
|
|
}
|
|
},
|
|
env: {},
|
|
b4a,
|
|
personalDrive: {
|
|
async get() {
|
|
return stored
|
|
},
|
|
async put(_path, buf) {
|
|
stored = buf
|
|
writes.push(b4a.toString(buf))
|
|
}
|
|
}
|
|
}
|
|
const rl = await createFishReadLine(ctx, { stdin, stdout })
|
|
t.ok(writes[writes.length - 1].includes('ls'))
|
|
t.absent(writes[writes.length - 1].includes('old-password'))
|
|
|
|
const p = rl('> ')
|
|
stdin.write('login current-password\n')
|
|
t.is(await p, 'login current-password')
|
|
t.absent(b4a.toString(stored).includes('current-password'))
|
|
t.absent(b4a.toString(stored).includes('old-password'))
|
|
stdin.end()
|
|
})
|
|
|
|
test('fish-readline SHELL_BUILTINS tracks shell list', async (t) => {
|
|
t.ok(SHELL_BUILTINS.includes('cd'))
|
|
t.ok(SHELL_BUILTINS.includes('export'))
|
|
t.ok(SHELL_BUILTINS.includes('trap'))
|
|
})
|
|
|
|
test('completion-engine parseCompletionContext pipeline segment', async (t) => {
|
|
const line = 'echo a | grep '
|
|
const cx = parseCompletionContext(line, line.length)
|
|
t.is(cx.firstWord, 'grep')
|
|
t.is(cx.argIndex, 1)
|
|
const cx2 = parseCompletionContext('ls -', 4)
|
|
t.is(cx2.firstWord, 'ls')
|
|
t.is(cx2.argIndex, 1)
|
|
})
|
|
|
|
test('completion-engine rankCompletionItems prefix and levenshtein', async (t) => {
|
|
const items = [
|
|
{ value: 'abc', scoreBase: 0 },
|
|
{ value: 'axyz', scoreBase: 0 },
|
|
{ value: 'ab', scoreBase: 0 }
|
|
]
|
|
const r = rankCompletionItems(items, 'ab', {})
|
|
t.is(r[0].value, 'ab')
|
|
t.ok(levenshtein('ab', 'abc', 32) <= 2)
|
|
})
|
|
|
|
test('completion-engine suggestGhostFromHistory', async (t) => {
|
|
const h = [{ command: 'ls -la' }, { command: 'ls -l' }]
|
|
const g = suggestGhostFromHistory(h, 'ls')
|
|
t.ok(g.includes('ls'))
|
|
})
|
|
|
|
test('completion-engine ghostReplaceCurrentWord', async (t) => {
|
|
t.is(ghostReplaceCurrentWord('ls t', 4, 'test'), 'ls test')
|
|
t.is(ghostReplaceCurrentWord('t', 1, 'test'), 'test')
|
|
})
|
|
|
|
test('completion-engine suggestGhostFromFs cwd first token', async (t) => {
|
|
const vfs = {
|
|
getcwd: () => '/home/guest',
|
|
async readdir(d) {
|
|
if (d === '.') return ['test', 'testing', 'other']
|
|
return []
|
|
},
|
|
async stat(p) {
|
|
const s = String(p)
|
|
if (s === 'test' || s.endsWith('/test')) return { type: 'file', mode: 0o644 }
|
|
return { type: 'directory', mode: 0o755 }
|
|
}
|
|
}
|
|
const ctx = { vfs, shellAliases: {} }
|
|
const g = await suggestGhostFromFs(ctx, { HOME: '/home/guest' }, 't', 1)
|
|
t.is(g, 'test')
|
|
const g2 = await suggestGhostFromFs(ctx, { HOME: '/home/guest' }, 'ls t', 4)
|
|
t.is(g2, 'ls test')
|
|
})
|
|
|
|
test('completion-engine longestCommonCompletionPrefix', async (t) => {
|
|
const cx = parseCompletionContext('ls te', 5)
|
|
const p = longestCommonCompletionPrefix(
|
|
[{ value: 'test' }, { value: 'testing' }],
|
|
cx
|
|
)
|
|
t.is(p, 'test')
|
|
})
|
|
|
|
test('completion-engine completeLine for-in uses path candidates after in', async (t) => {
|
|
const vfs = {
|
|
getcwd: () => '/home/guest',
|
|
async readdir(d) {
|
|
const s = String(d)
|
|
if (s === '.' || s === '/home/guest') return ['apple', 'apricot']
|
|
return []
|
|
},
|
|
async readFile() {
|
|
return ''
|
|
},
|
|
async stat(p) {
|
|
const s = String(p)
|
|
if (s.includes('apple') || s.includes('apricot')) return { type: 'file', mode: 0o644 }
|
|
return { type: 'directory', mode: 0o755 }
|
|
}
|
|
}
|
|
const ctx = { vfs, shellAliases: {} }
|
|
const line = 'for z in ap'
|
|
const r = await completeLine(
|
|
ctx,
|
|
{ PATH: '/bin', HOME: '/home/guest', apple: '1' },
|
|
line,
|
|
line.length,
|
|
[],
|
|
{}
|
|
)
|
|
t.ok(
|
|
r.items.some(
|
|
(i) => i.value === 'apple' || i.value.endsWith('/apple') || i.value === './apple'
|
|
)
|
|
)
|
|
})
|
|
|
|
test('completion-engine completeLine for suggests in keyword', async (t) => {
|
|
const vfs = {
|
|
getcwd: () => '/',
|
|
async readdir() {
|
|
return []
|
|
},
|
|
async readFile() {
|
|
return ''
|
|
},
|
|
async stat() {
|
|
return { type: 'file', mode: 0o644 }
|
|
}
|
|
}
|
|
const ctx = { vfs, shellAliases: {} }
|
|
const line = 'for z i'
|
|
const r = await completeLine(ctx, { PATH: '/bin', HOME: '/home/guest' }, line, line.length, [], {})
|
|
t.ok(r.items.some((i) => i.value === 'in'))
|
|
})
|
|
|
|
test('completion-engine completeLine kill uses process_table.json', async (t) => {
|
|
const vfs = {
|
|
getcwd: () => '/',
|
|
async readdir(d) {
|
|
if (d === '/bin') return ['grep.js', 'kill.js']
|
|
return []
|
|
},
|
|
async readFile(p) {
|
|
const s = String(p)
|
|
if (s.includes('process_table')) {
|
|
return JSON.stringify({
|
|
processes: [{ pid: 3, name: 'bare-os-shell' }]
|
|
})
|
|
}
|
|
return ''
|
|
},
|
|
async stat() {
|
|
return { type: 'file', mode: 0o644 }
|
|
}
|
|
}
|
|
const ctx = { vfs, b4a, shellAliases: {} }
|
|
const kl = 'kill '
|
|
const r = await completeLine(ctx, { PATH: '/bin' }, kl, kl.length, [], {})
|
|
t.ok(r.items.some((i) => i.value === '3'))
|
|
})
|
|
|
|
test('completion-engine rankCompletionItems large list budget', async (t) => {
|
|
const items = []
|
|
for (let i = 0; i < 2000; i++) items.push({ value: 'f' + i, scoreBase: 0 })
|
|
const t0 = Date.now()
|
|
rankCompletionItems(items, 'f1', {})
|
|
t.ok(Date.now() - t0 < 800, 'rank under 800ms')
|
|
})
|
|
|
|
test('tier-1 cat from system drive', async (t) => {
|
|
const dir = testCorestoreDir('cat')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pc'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/cat', b4a.from(await readBuiltBin('cat')))
|
|
await drive.put('/etc/x', b4a.from('hello'))
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.console = {
|
|
log() {},
|
|
error() {}
|
|
}
|
|
const catOut = []
|
|
const prevCatWrite = process.stdout.write
|
|
process.stdout.write = (chunk) => {
|
|
catOut.push(
|
|
typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8')
|
|
)
|
|
return true
|
|
}
|
|
try {
|
|
await runBinCommand(ctx, ['cat', '/etc/x'])
|
|
} finally {
|
|
process.stdout.write = prevCatWrite
|
|
}
|
|
t.is(catOut.join(''), 'hello')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 tail head options and tail -f poll', async (t) => {
|
|
const dir = testCorestoreDir('tail-head')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pth'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/tail', b4a.from(await readBuiltBin('tail')))
|
|
await drive.put('/bin/head', b4a.from(await readBuiltBin('head')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal, {
|
|
BARE_OS_TAIL_F_POLL_MS: '25',
|
|
BARE_OS_TAIL_F_MAX_ROUNDS: '8'
|
|
})
|
|
ctx.exitCode = 0
|
|
ctx.bareOsRuntimeCaps = buildBareOsRuntimeCaps(ctx.env)
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('t.txt', b4a.from('one\ntwo\nthree\n'))
|
|
await runBinCommand(ctx, ['tail', '-n', '2', 't.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), 'two\nthree')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['tail', '-n', '+2', 't.txt'])
|
|
t.is(lines.join('\n'), 'two\nthree')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['head', '-c', '4', 't.txt'])
|
|
t.is(lines[0], 'one\n')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile('f.log', b4a.from('a\n'))
|
|
const tailP = runBinCommand(ctx, ['tail', '-f', 'f.log'])
|
|
await new Promise((r) => setTimeout(r, 15))
|
|
const cur = b4a.toString(await ctx.vfs.readFile('f.log'))
|
|
await ctx.vfs.writeFile('f.log', b4a.from(cur + 'b\n'))
|
|
await tailP
|
|
t.ok(lines.includes('a'))
|
|
t.ok(lines.includes('b'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = 'x\ny\n'
|
|
await runBinCommand(ctx, ['tail', '-f'])
|
|
t.is(ctx.exitCode, 1)
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 grep and mkfifo from system drive', async (t) => {
|
|
const dir = testCorestoreDir('grep')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pg'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/grep', b4a.from(await readBuiltBin('grep')))
|
|
await drive.put('/bin/mkfifo', b4a.from(await readBuiltBin('mkfifo')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile(
|
|
'w.txt',
|
|
b4a.from('aaa\nneedle line\nbbb\nneedle line two')
|
|
)
|
|
await runBinCommand(ctx, ['grep', '-F', 'needle', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.length, 2)
|
|
t.ok(lines[0].includes('needle line'))
|
|
t.ok(lines[1].includes('needle line two'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-F', 'nomatch', 'w.txt'])
|
|
t.is(ctx.exitCode, 1)
|
|
t.is(lines.length, 0)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-v', '-F', 'needle', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), 'aaa\nbbb')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-c', '-F', 'needle', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], '2')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-n', '-F', 'bbb', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], '3:bbb')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = 'alpha\nbeta\n'
|
|
await runBinCommand(ctx, ['grep', '-F', 'beta'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], 'beta')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-x', '-F', 'aaa', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], 'aaa')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-m', '1', '-F', 'needle', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.length, 1)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-o', 'ee', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.includes('ee'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-E', 'needle\\s+line$', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.some((l) => l.includes('needle line')))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-G', 'needle', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.some((l) => l.includes('needle line')))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['mkfifo', '/run/bare-os/ipc/t1'])
|
|
t.is(ctx.exitCode, 0)
|
|
const readP = ctx.vfs.readFile('/run/bare-os/ipc/t1')
|
|
await ctx.vfs.writeFile('/run/bare-os/ipc/t1', b4a.from('ok'))
|
|
t.is(b4a.toString(await readP), 'ok')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['grep', '-F', '-C', '1', 'needle', 'w.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.some((l) => l === 'aaa'))
|
|
t.ok(lines.some((l) => l.includes('needle line')))
|
|
t.ok(lines.some((l) => l === 'bbb'))
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 sort and wc flags', async (t) => {
|
|
const dir = testCorestoreDir('sort-wc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('psw'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/sort', b4a.from(await readBuiltBin('sort')))
|
|
await drive.put('/bin/wc', b4a.from(await readBuiltBin('wc')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('nums.txt', b4a.from('10\n2\n1\n'))
|
|
await runBinCommand(ctx, ['sort', '-n', 'nums.txt'])
|
|
t.is(lines.join('\n'), '1\n2\n10')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sort', '-nru', 'nums.txt'])
|
|
t.is(lines.join('\n'), '10\n2\n1')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['wc', '-l', 'nums.txt'])
|
|
t.is(lines[0].trim(), '3 nums.txt')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['wc', '-c', 'nums.txt'])
|
|
t.is(lines[0], ' 7 nums.txt')
|
|
|
|
const errs = []
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(...a) {
|
|
errs.push(a.join(' '))
|
|
}
|
|
}
|
|
await ctx.vfs.writeFile('ord.txt', b4a.from('a\nb\nc\n'))
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sort', '-c', 'ord.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(errs.length, 0)
|
|
|
|
await ctx.vfs.writeFile('bad.txt', b4a.from('b\na\n'))
|
|
lines.length = 0
|
|
errs.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sort', '-c', 'bad.txt'])
|
|
t.is(ctx.exitCode, 1)
|
|
t.ok(errs.some((e) => e.includes('disorder')))
|
|
|
|
errs.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sort', '-C', 'bad.txt'])
|
|
t.is(ctx.exitCode, 1)
|
|
t.is(errs.length, 0)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sort', '-o', 'sorted.txt', '-n', 'nums.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
const sortedBuf = await ctx.vfs.readFile('sorted.txt')
|
|
t.is(ctx.b4a.toString(sortedBuf), '1\n2\n10\n')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sort', '-s', 'ord.txt'])
|
|
t.is(lines.join('\n'), 'a\nb\nc')
|
|
|
|
lines.length = 0
|
|
errs.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sort', '-M', 'ord.txt'])
|
|
t.is(ctx.exitCode, 1)
|
|
t.ok(errs.length > 0)
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 find du basename options', async (t) => {
|
|
const dir = testCorestoreDir('fdu-base')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pfdb'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/find', b4a.from(await readBuiltBin('find')))
|
|
await drive.put('/bin/du', b4a.from(await readBuiltBin('du')))
|
|
await drive.put('/bin/basename', b4a.from(await readBuiltBin('basename')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('Lo.txt', b4a.from('ab'))
|
|
await runBinCommand(ctx, ['find', '.', '-iname', 'lo.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.some((p) => /Lo\.txt$/.test(String(p).replace(/\\/g, '/'))))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['du', '-h', 'Lo.txt'])
|
|
t.ok(/^2\tLo\.txt$/.test(lines[0]) || /^3\tLo\.txt$/.test(lines[0]))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['basename', '-a', '/x/a', '/y/b'])
|
|
t.is(lines.join('\n'), 'a\nb')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['basename', 'z.h', '.h'])
|
|
t.is(lines[0], 'z')
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 shuf deterministic seed option', async (t) => {
|
|
const dir = testCorestoreDir('shuf-seed')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pshufseed'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/shuf', b4a.from(await readBuiltBin('shuf')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.console = { log: (s) => lines.push(String(s)), error() {} }
|
|
await ctx.vfs.writeFile('s.txt', b4a.from('a\nb\nc\nd\n'))
|
|
ctx.vfs.env.BARE_OS_SHUF_SEED = 'seed-1'
|
|
await runBinCommand(ctx, ['shuf', 's.txt'])
|
|
const first = lines.join('\n')
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['shuf', 's.txt'])
|
|
const second = lines.join('\n')
|
|
t.is(first, second)
|
|
ctx.vfs.env.BARE_OS_SHUF_SEED = 'seed-2'
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['shuf', 's.txt'])
|
|
t.unlike(lines.join('\n'), first)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 env -S and --env-file under Bare runtime', async (t) => {
|
|
const dir = testCorestoreDir('env-dashs')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('penvds'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/env', b4a.from(await readBuiltBin('env')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.console = { log: (s) => lines.push(String(s)), error: (s) => lines.push(String(s)) }
|
|
ctx.vfs.env.BARE_OS_ENV_DASH_S = '1'
|
|
|
|
await runBinCommand(ctx, ['env', '-S', 'A=1 B=2'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.includes('A=1'))
|
|
t.ok(lines.includes('B=2'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile(
|
|
'/home/user/.env.test',
|
|
b4a.from('X=left\nY=right\n', 'utf8')
|
|
)
|
|
await runBinCommand(ctx, ['env', '--env-file', '/home/user/.env.test'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.includes('X=left'))
|
|
t.ok(lines.includes('Y=right'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('execShellLine find pipes to wc -l', async (t) => {
|
|
const dir = testCorestoreDir('findpipewc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('fpwc'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/find', b4a.from(await readBuiltBin('find')))
|
|
await drive.put('/bin/wc', b4a.from(await readBuiltBin('wc')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('p.txt', b4a.from(''))
|
|
await execShellLine(ctx, 'find . -maxdepth 1 | wc -l')
|
|
t.is(ctx.exitCode, 0)
|
|
const n = Number.parseInt(String(lines[0] || '').trim(), 10)
|
|
t.ok(Number.isFinite(n) && n >= 1)
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|