1820 lines
51 KiB
JavaScript
1820 lines
51 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('tier-1 date format and test numeric', async (t) => {
|
|
const dir = testCorestoreDir('date-test')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pdt'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/date', b4a.from(await readBuiltBin('date')))
|
|
await drive.put('/bin/test', b4a.from(await readBuiltBin('test')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await runBinCommand(ctx, ['test', '2', '-lt', '5'])
|
|
t.is(ctx.exitCode, 0)
|
|
await runBinCommand(ctx, ['test', '5', '-lt', '2'])
|
|
t.is(ctx.exitCode, 1)
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['date', '+%Y'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(/^\d{4}$/.test(lines[0]))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 find -mindepth skips shallow paths', async (t) => {
|
|
const dir = testCorestoreDir('find-mindepth')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pfindmd'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/find', b4a.from(await readBuiltBin('find')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.mkdir('nest', { recursive: true })
|
|
await ctx.vfs.mkdir('nest/sub', { recursive: true })
|
|
await ctx.vfs.writeFile('nest/a.txt', b4a.from('a'))
|
|
await ctx.vfs.writeFile('nest/sub/b.txt', b4a.from('b'))
|
|
await runBinCommand(ctx, ['find', '.', '-mindepth', '2', '-type', 'f'])
|
|
t.is(ctx.exitCode, 0)
|
|
const norm = lines.map((p) => p.replace(/\\/g, '/')).sort()
|
|
t.ok(norm.some((p) => p.endsWith('/nest/a.txt')))
|
|
t.ok(norm.some((p) => p.endsWith('/nest/sub/b.txt')))
|
|
lines.length = 0
|
|
await runBinCommand(ctx, ['find', 'nest', '-mindepth', '2', '-type', 'f'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(
|
|
lines.some((p) => String(p).replace(/\\/g, '/').endsWith('/nest/sub/b.txt'))
|
|
)
|
|
t.ok(
|
|
!lines.some((p) => String(p).replace(/\\/g, '/').endsWith('/nest/a.txt'))
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs union write deny rejects chmod and symlink targets', async (t) => {
|
|
const dir = testCorestoreDir('union-deny')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pu'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const shellEnv = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest',
|
|
UID: '0',
|
|
GID: '0'
|
|
}
|
|
const vfs = createVfs(sys, personal, shellEnv, null, {
|
|
bareOsIpc: createBareOsIpc(),
|
|
unionReadPrefixes: ['/etc'],
|
|
unionWriteDenyPrefixes: ['/etc']
|
|
})
|
|
let w = false
|
|
try {
|
|
await vfs.writeFile('/etc/union-blocked', b4a.from('x'))
|
|
} catch (e) {
|
|
w = true
|
|
t.ok(String(e.message).includes('union write denied'))
|
|
}
|
|
t.ok(w)
|
|
let c = false
|
|
try {
|
|
await vfs.chmod('/etc/passwd', 0o644)
|
|
} catch (e) {
|
|
c = true
|
|
t.ok(String(e.message).includes('union write denied'))
|
|
}
|
|
t.ok(c)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs symlink relative and absolute targets under personal', async (t) => {
|
|
const dir = testCorestoreDir('symlink-personal')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('slp'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const ctx = testCtx(drive, personal)
|
|
await ctx.vfs.writeFile('~/target.txt', b4a.from('hello'))
|
|
await ctx.vfs.symlink('target.txt', '~/via_rel.txt')
|
|
t.is(await ctx.vfs.readlink('~/via_rel.txt'), 'target.txt')
|
|
const st = await ctx.vfs.lstat('~/via_rel.txt')
|
|
t.is(st.type, 'symlink')
|
|
t.is(b4a.toString(await ctx.vfs.readFile('~/via_rel.txt'), 'utf8'), 'hello')
|
|
|
|
await ctx.vfs.symlink('/home/user/target.txt', '~/via_abs.txt')
|
|
t.is(await ctx.vfs.readlink('~/via_abs.txt'), '/home/user/target.txt')
|
|
t.is(b4a.toString(await ctx.vfs.readFile('~/via_abs.txt'), 'utf8'), 'hello')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs symlink on system drive /var follows within same drive', async (t) => {
|
|
const dir = testCorestoreDir('symlink-system-var')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('slsv'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const dataPath = '/var/bare-os-symlink-test/data.txt'
|
|
const aliasPath = '/var/bare-os-symlink-test/alias.txt'
|
|
await drive.put(dataPath, b4a.from('sysblob'))
|
|
await drive.symlink(aliasPath, dataPath, { metadata: {} })
|
|
const ctx = testCtx(drive, personal)
|
|
t.is(await ctx.vfs.readlink(aliasPath), dataPath)
|
|
t.is(b4a.toString(await ctx.vfs.readFile(aliasPath), 'utf8'), 'sysblob')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('HyperDHT local testnet: bootstrap node and ephemeral peer fullyBootstrapped', async (t) => {
|
|
const createTestnet = require('hyperdht/testnet.js')
|
|
const DHT = require('hyperdht')
|
|
const testnet = await createTestnet(1)
|
|
try {
|
|
t.ok(testnet.bootstrap.length >= 1, 'testnet exposes bootstrap address')
|
|
const addr = testnet.nodes[0].address()
|
|
t.ok(addr && addr.port > 0, 'bootstrap listens on a UDP port')
|
|
const client = new DHT({
|
|
ephemeral: true,
|
|
bootstrap: testnet.bootstrap,
|
|
host: '127.0.0.1'
|
|
})
|
|
try {
|
|
await client.fullyBootstrapped()
|
|
t.pass('ephemeral HyperDHT node reaches fullyBootstrapped against local testnet')
|
|
} finally {
|
|
await client.destroy()
|
|
}
|
|
} finally {
|
|
await testnet.destroy()
|
|
}
|
|
})
|
|
|
|
test('tier-1 mv renames file in home', async (t) => {
|
|
const dir = testCorestoreDir('mv-home')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('mvhm'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/mv', b4a.from(await readBuiltBin('mv')))
|
|
const ctx = testCtx(drive, personal)
|
|
await ctx.vfs.writeFile('a.txt', b4a.from('ok'))
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['mv', 'a.txt', 'b.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(b4a.toString(await ctx.vfs.readFile('b.txt'), 'utf8'), 'ok')
|
|
t.ok(
|
|
(await ctx.vfs.readFile('a.txt')) == null,
|
|
'mv removed source path in home'
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 cmp silent and kernel-boot-diff line set', async (t) => {
|
|
const dir = testCorestoreDir('cmp-kbd')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('cmpkbd'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const cmpSrc = await readFile(
|
|
path.join(__dirname, '../../kernel/bin/cmp'),
|
|
'utf8'
|
|
)
|
|
const kbdSrc = await readFile(
|
|
path.join(__dirname, '../../kernel/bin/kernel-boot-diff'),
|
|
'utf8'
|
|
)
|
|
await drive.put('/bin/cmp', b4a.from(cmpSrc))
|
|
await drive.put('/bin/kernel-boot-diff', b4a.from(kbdSrc))
|
|
const ctx = testCtx(drive, personal)
|
|
await ctx.vfs.writeFile('same1.txt', b4a.from('x'))
|
|
await ctx.vfs.writeFile('same2.txt', b4a.from('x'))
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['cmp', '-s', 'same1.txt', 'same2.txt'])
|
|
t.is(ctx.exitCode, 0, 'cmp -s identical')
|
|
await ctx.vfs.writeFile('d2.txt', b4a.from('y'))
|
|
ctx.exitCode = 0
|
|
const errs = []
|
|
ctx.console = {
|
|
log() {},
|
|
error(s) {
|
|
errs.push(String(s))
|
|
}
|
|
}
|
|
await runBinCommand(ctx, ['cmp', '-s', 'same1.txt', 'd2.txt'])
|
|
t.is(ctx.exitCode, 1, 'cmp -s differs')
|
|
await ctx.vfs.writeFile('boot-a.txt', b4a.from('line1\nline2\n'))
|
|
await ctx.vfs.writeFile('boot-b.txt', b4a.from('line1\nline3\n'))
|
|
const lines = []
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
errs.push(String(s))
|
|
}
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['kernel-boot-diff', 'boot-a.txt', 'boot-b.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.some((l) => l.startsWith('+ ') && l.includes('line3')))
|
|
t.ok(lines.some((l) => l.startsWith('- ') && l.includes('line2')))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 diff -u and patch apply stdin hunk', async (t) => {
|
|
const dir = testCorestoreDir('diffpatch')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('dp'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/diff', b4a.from(await readBuiltBin('diff')))
|
|
await drive.put('/bin/patch', b4a.from(await readBuiltBin('patch')))
|
|
const ctx = testCtx(drive, personal)
|
|
await ctx.vfs.writeFile('a.txt', b4a.from('alpha\n'))
|
|
await ctx.vfs.writeFile('b.txt', b4a.from('beta\n'))
|
|
const out = []
|
|
ctx.console = {
|
|
log(s) {
|
|
out.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['diff', '-u', 'a.txt', 'b.txt'])
|
|
t.is(ctx.exitCode, 1)
|
|
t.ok(out.join('\n').includes('+++ b.txt'))
|
|
await ctx.vfs.writeFile('fix.txt', b4a.from('alpha\n'))
|
|
ctx.shellStdin = out.join('\n') + '\n'
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['patch', '-p0', 'fix.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(ctx.b4a.toString(await ctx.vfs.readFile('fix.txt')), 'beta\n')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('bareInitdReadinessSnapshot exposes unit table', async (t) => {
|
|
const s = bareInitdReadinessSnapshot()
|
|
t.is(s.schema, 2)
|
|
t.ok(Array.isArray(s.units))
|
|
t.ok(s.supervisionTelemetry && s.supervisionTelemetry.schema === 1)
|
|
})
|
|
|
|
test('tier-1 test -r -w -x -s predicates', async (t) => {
|
|
const dir = testCorestoreDir('test-pred')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('tpred'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/test', b4a.from(await readBuiltBin('test')))
|
|
const ctx = testCtx(drive, personal)
|
|
await ctx.vfs.writeFile('ro.txt', b4a.from('data'))
|
|
await ctx.vfs.chmod('ro.txt', 0o400)
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['test', '-r', 'ro.txt'])
|
|
t.is(ctx.exitCode, 0, '-r read-only file')
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['test', '-w', 'ro.txt'])
|
|
t.is(ctx.exitCode, 1, '-w false when not writable')
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['test', '-s', 'ro.txt'])
|
|
t.is(ctx.exitCode, 0, '-s nonempty file')
|
|
await ctx.vfs.writeFile('empty.txt', b4a.from(''))
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['test', '-s', 'empty.txt'])
|
|
t.is(ctx.exitCode, 1, '-s empty file')
|
|
await ctx.vfs.writeFile('run.sh', b4a.from('#!'))
|
|
await ctx.vfs.chmod('run.sh', 0o700)
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['test', '-x', 'run.sh'])
|
|
t.is(ctx.exitCode, 0, '-x executable')
|
|
await ctx.vfs.chmod('run.sh', 0o600)
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['test', '-x', 'run.sh'])
|
|
t.is(ctx.exitCode, 1, '-x false without exec bit')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 find -perm filters by mode', async (t) => {
|
|
const dir = testCorestoreDir('find-perm')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pfp'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/find', b4a.from(await readBuiltBin('find')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('rw.txt', b4a.from(''))
|
|
await ctx.vfs.chmod('rw.txt', 0o644)
|
|
await ctx.vfs.writeFile('x.txt', b4a.from(''))
|
|
await ctx.vfs.chmod('x.txt', 0o600)
|
|
await runBinCommand(ctx, ['find', '.', '-perm', '600', '-type', 'f'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(
|
|
lines.some((p) => String(p).replace(/\\/g, '/').endsWith('/x.txt'))
|
|
)
|
|
t.ok(
|
|
!lines.some((p) => String(p).replace(/\\/g, '/').endsWith('/rw.txt'))
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 find -mtime -1 matches recent files', async (t) => {
|
|
const dir = testCorestoreDir('find-mtime')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('fmt'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/find', b4a.from(await readBuiltBin('find')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('recent.txt', b4a.from('x'))
|
|
await runBinCommand(ctx, ['find', '.', '-type', 'f', '-mtime', '-1'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(
|
|
lines.some((p) => String(p).replace(/\\/g, '/').endsWith('/recent.txt'))
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 find -xdev skips other volume under /', async (t) => {
|
|
const dir = testCorestoreDir('find-xdev')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('fxd'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/onlyroot.txt', b4a.from('sys'))
|
|
await drive.put('/bin/find', b4a.from(await readBuiltBin('find')))
|
|
const ctx = testCtx(drive, personal, { PWD: '/', HOME: '/home/user' })
|
|
ctx.exitCode = 0
|
|
const lines = []
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('/home/user/only_in_home.txt', b4a.from('p'))
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['find', '/', '-xdev', '-name', 'only_in_home.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.length, 0, '-xdev from / must not descend into /home')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['find', '/', '-name', 'only_in_home.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(
|
|
lines.some((p) =>
|
|
String(p).replace(/\\/g, '/').endsWith('/only_in_home.txt')
|
|
),
|
|
'without -xdev, file under /home is visible from /'
|
|
)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['find', '/', '-xdev', '-name', 'onlyroot.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(
|
|
lines.some((p) =>
|
|
String(p).replace(/\\/g, '/').endsWith('/onlyroot.txt')
|
|
),
|
|
'-xdev still searches system tree under /'
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tar-cli hard link extract copies unless BARE_OS_VFS_STRICT_HARDLINK', async (t) => {
|
|
const dir = testCorestoreDir('tar-hardlink')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('tarhl'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const body = b4a.from('hi', 'utf8')
|
|
const hdrA = encodeUstarHeader({
|
|
name: 'a.txt',
|
|
size: body.length,
|
|
mode: 0o644,
|
|
mtime: 1,
|
|
typeflag: '0'
|
|
})
|
|
const padA = new Uint8Array((TAR_BLK - (body.length % TAR_BLK)) % TAR_BLK)
|
|
const hdrB = encodeUstarHeader({
|
|
name: 'b.txt',
|
|
size: 0,
|
|
mode: 0o644,
|
|
mtime: 1,
|
|
typeflag: '1',
|
|
linkname: 'a.txt'
|
|
})
|
|
const archive = concatTarParts([
|
|
hdrA,
|
|
body,
|
|
padA,
|
|
hdrB,
|
|
new Uint8Array(TAR_BLK * 2)
|
|
])
|
|
|
|
const errs = []
|
|
const ctx = testCtx(drive, personal)
|
|
await ctx.vfs.writeFile('hl.tar', b4a.from(archive))
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log() {},
|
|
error(s) {
|
|
errs.push(String(s))
|
|
}
|
|
}
|
|
await runTarCli(ctx, ['tar', '-xf', 'hl.tar'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(b4a.toString(await ctx.vfs.readFile('b.txt'), 'utf8'), 'hi')
|
|
|
|
await ctx.vfs.rm('a.txt', { recursive: true, force: true })
|
|
await ctx.vfs.rm('b.txt', { recursive: true, force: true })
|
|
|
|
errs.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile('hl.tar', b4a.from(archive))
|
|
const ctxStrict = testCtx(drive, personal, {
|
|
BARE_OS_VFS_STRICT_HARDLINK: '1'
|
|
})
|
|
await ctxStrict.vfs.writeFile('hl.tar', b4a.from(archive))
|
|
ctxStrict.exitCode = 0
|
|
ctxStrict.console = {
|
|
log() {},
|
|
error(s) {
|
|
errs.push(String(s))
|
|
}
|
|
}
|
|
await runTarCli(ctxStrict, ['tar', '-xf', 'hl.tar'])
|
|
t.is(ctxStrict.exitCode, 1)
|
|
t.ok(
|
|
errs.some((e) => /hard link entries not supported/i.test(e)),
|
|
'strict mode rejects hard link members'
|
|
)
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 jq from system drive', async (t) => {
|
|
const dir = testCorestoreDir('jq')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pjq'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/jq', b4a.from(await readBuiltBin('jq')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.writeFile('data.json', b4a.from('{"x":42,"name":"hi"}'))
|
|
await runBinCommand(ctx, ['jq', '.x', 'data.json'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], '42')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['jq', '-c', '.', 'data.json'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], '{"x":42,"name":"hi"}')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = '{"a":1}'
|
|
await runBinCommand(ctx, ['jq', '.a'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], '1')
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 getconf and xargs from system drive', async (t) => {
|
|
const dir = testCorestoreDir('gxc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pgx'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/getconf', b4a.from(await readBuiltBin('getconf')))
|
|
await drive.put(
|
|
'/bin/echolog',
|
|
b4a.from(`
|
|
async function run(ctx, argv) {
|
|
ctx.console.log(argv.slice(1).join(' '))
|
|
}
|
|
`)
|
|
)
|
|
await drive.put('/bin/xargs', b4a.from(await readBuiltBin('xargs')))
|
|
await drive.put('/bin/false', b4a.from(await readBuiltBin('false')))
|
|
await drive.put('/bin/printf', b4a.from(await readBuiltBin('printf')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.runBinCommand = function (argv, ro) {
|
|
return runBinCommand(this, argv, ro)
|
|
}
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push(String(s))
|
|
}
|
|
}
|
|
await runBinCommand(ctx, ['getconf', 'PATH_MAX'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.pop(), '4096')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['getconf', '_SC_NPROCESSORS_ONLN'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.pop(), '4')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['getconf', 'BARE_OS_YES_MAX_LINES'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.pop(), '100000')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.bareOsPathconf = (p, n) => {
|
|
void p
|
|
if (n === '_PC_NAME_MAX') return 255
|
|
throw new Error('getconf pathconf test: unknown name')
|
|
}
|
|
await runBinCommand(ctx, ['getconf', '_PC_NAME_MAX', '/home/user'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.pop(), '255')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['getconf', 'NOT_A_REAL_CONF_NAME'])
|
|
t.is(ctx.exitCode, 1)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = 'hello\tworld\n'
|
|
await runBinCommand(ctx, ['xargs', 'echolog'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), 'hello world')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = 'a\0b\0'
|
|
await runBinCommand(ctx, ['xargs', '-0', '-n1', 'echolog'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), 'a\nb')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = 'one\ntwo\n'
|
|
await runBinCommand(ctx, ['xargs', '-I', '{}', 'echolog', 'x', '{}', 'y'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), 'x one y\nx two y')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = 'a\nb\n'
|
|
await runBinCommand(ctx, ['xargs', '-P2', '-n1', 'echolog'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(new Set(lines).size, 2)
|
|
t.ok(lines.includes('a'))
|
|
t.ok(lines.includes('b'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.vfs.env.BARE_OS_XARGS_MAX_PROCS = '2'
|
|
ctx.shellStdin = 'x\ny\n'
|
|
await runBinCommand(ctx, ['xargs', '-P8', '-n1', 'echolog'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.some((s) => String(s).includes('exceeds cap 2')))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.shellStdin = ''
|
|
await execShellLine(ctx, 'false || printf recovered')
|
|
t.is(lines.pop(), 'recovered')
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 sh shebang strip and symlink script path', async (t) => {
|
|
const dir = testCorestoreDir('shshe')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('psh'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/sh', b4a.from(await readBuiltBin('sh')))
|
|
await drive.put(
|
|
'/bin/echo',
|
|
b4a.from(`async function run(ctx, argv) {
|
|
ctx.console.log(argv.slice(1).join(' '))
|
|
}
|
|
`)
|
|
)
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.runBinCommand = function (argv, ro) {
|
|
return runBinCommand(this, argv, ro)
|
|
}
|
|
ctx.execLine = (line, opts) => execShellLine(ctx, line)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push(String(s))
|
|
}
|
|
}
|
|
await ctx.vfs.chdir('/home/user')
|
|
await ctx.vfs.writeFile(
|
|
'real.sh',
|
|
b4a.from('#!/bin/sh\necho shebang-ok\n')
|
|
)
|
|
await ctx.vfs.symlink('real.sh', 'via.sh')
|
|
await runBinCommand(ctx, ['sh', 'via.sh'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.some((l) => String(l).includes('shebang-ok')))
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 sh script mode handles multiline compound blocks', async (t) => {
|
|
const dir = testCorestoreDir('shmulti')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pshm'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/sh', b4a.from(await readBuiltBin('sh')))
|
|
await drive.put(
|
|
'/bin/echo',
|
|
b4a.from(`async function run(ctx, argv) {
|
|
ctx.console.log(argv.slice(1).join(' '))
|
|
}
|
|
`)
|
|
)
|
|
await drive.put(
|
|
'/bin/true',
|
|
b4a.from(`async function run(ctx) {
|
|
ctx.exitCode = 0
|
|
}
|
|
`)
|
|
)
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.runBinCommand = function (argv, ro) {
|
|
return runBinCommand(this, argv, ro)
|
|
}
|
|
ctx.execLine = (line) => execShellLine(ctx, line)
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push('e:' + String(s))
|
|
}
|
|
}
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.chdir('/home/user')
|
|
await ctx.vfs.writeFile(
|
|
'm.sh',
|
|
b4a.from(
|
|
[
|
|
'#!/bin/sh',
|
|
'n=0',
|
|
'for x in a b',
|
|
'do',
|
|
' if true',
|
|
' then',
|
|
' n=$((n+1))',
|
|
' fi',
|
|
'done',
|
|
'echo $n'
|
|
].join('\n')
|
|
)
|
|
)
|
|
await runBinCommand(ctx, ['sh', 'm.sh'])
|
|
t.ok(typeof ctx.exitCode === 'number')
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 direct .sh command runs via /bin/sh', async (t) => {
|
|
const dir = testCorestoreDir('shdirect')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pshd'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/sh', b4a.from(await readBuiltBin('sh')))
|
|
await drive.put(
|
|
'/bin/echo',
|
|
b4a.from(`async function run(ctx, argv) {
|
|
ctx.console.log(argv.slice(1).join(' '))
|
|
}
|
|
`)
|
|
)
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.runBinCommand = function (argv, ro) {
|
|
return runBinCommand(this, argv, ro)
|
|
}
|
|
ctx.execLine = (line) => execShellLine(ctx, line)
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push('e:' + String(s))
|
|
}
|
|
}
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.chdir('/home/user')
|
|
await ctx.vfs.writeFile('./test.sh', b4a.from('#!/bin/sh\necho via-sh\n'))
|
|
await runBinCommand(ctx, ['./test.sh'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.includes('via-sh'))
|
|
t.ok(!lines.some((l) => l.startsWith('e:Unexpected string')))
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 sh -c executes command and sets positional args', async (t) => {
|
|
const dir = testCorestoreDir('shdashc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pshc'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/sh', b4a.from(await readBuiltBin('sh')))
|
|
await drive.put(
|
|
'/bin/echo',
|
|
b4a.from(`async function run(ctx, argv) {
|
|
ctx.console.log(argv.slice(1).join(' '))
|
|
}
|
|
`)
|
|
)
|
|
await drive.put(
|
|
'/bin/false',
|
|
b4a.from(`async function run(ctx) {
|
|
ctx.exitCode = 1
|
|
}
|
|
`)
|
|
)
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.runBinCommand = function (argv, ro) {
|
|
return runBinCommand(this, argv, ro)
|
|
}
|
|
ctx.execLine = (line) => execShellLine(ctx, line)
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push('e:' + String(s))
|
|
}
|
|
}
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sh', '-c', 'echo $0 $1 $2 $#', 'myshell', 'aa', 'bb'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(!lines.some((l) => l.startsWith('e:')))
|
|
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sh', '-c', 'false'])
|
|
t.is(ctx.exitCode, 1)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, [
|
|
'sh',
|
|
'-c',
|
|
'n=0; if true; then n=$((n+1)); fi; echo $n'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(!lines.some((l) => l.startsWith('e:')))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['sh', '-c', 'false; echo $?'])
|
|
t.ok(lines.some((l) => String(l).trim() === '1'), lines.join('|'))
|
|
t.is(ctx.exitCode, 0)
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('execShellLine supports shell functions, export NAME, and until by default', async (t) => {
|
|
const dir = testCorestoreDir('shfunc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pshf'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put(
|
|
'/bin/echo',
|
|
b4a.from(`async function run(ctx, argv) {
|
|
ctx.console.log(argv.slice(1).join(' '))
|
|
}
|
|
`)
|
|
)
|
|
await drive.put(
|
|
'/bin/true',
|
|
b4a.from(`async function run(ctx) {
|
|
ctx.exitCode = 0
|
|
}
|
|
`)
|
|
)
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push('e:' + String(s))
|
|
}
|
|
}
|
|
ctx.exitCode = 0
|
|
|
|
await execShellLine(ctx, 'hello() { echo $1; }; hello world')
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.includes('world'))
|
|
|
|
ctx.exitCode = 0
|
|
await execShellLine(ctx, 'export DEMO')
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(ctx.vfs.env.DEMO, '')
|
|
|
|
ctx.exitCode = 0
|
|
await execShellLine(ctx, 'export BAD-NAME=1')
|
|
t.is(ctx.exitCode, 1)
|
|
|
|
ctx.exitCode = 0
|
|
await execShellLine(ctx, 'until false; do break; done')
|
|
t.is(ctx.exitCode, 0)
|
|
|
|
ctx.exitCode = 0
|
|
await execShellLine(
|
|
ctx,
|
|
'n=0; for x in a b; do if true; then n=$((n+1)); fi; done; echo $n'
|
|
)
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(lines.includes('2'))
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-2 cat env touch mkdir', async (t) => {
|
|
const dir = testCorestoreDir('tier2tem')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pt2'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
for (const name of ['cat', 'env', 'touch', 'mkdir', 'printf']) {
|
|
await drive.put('/bin/' + name, b4a.from(await readBuiltBin(name)))
|
|
}
|
|
const catOut = []
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal, { MARK: 'parent', HELLO: 'world' })
|
|
ctx.exitCode = 0
|
|
ctx.runBinCommand = function (argv, o) {
|
|
return runBinCommand(this, argv, o)
|
|
}
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push('e:' + String(s))
|
|
}
|
|
}
|
|
await ctx.vfs.chdir('/home/user')
|
|
await ctx.vfs.writeFile('plain.txt', b4a.from('a\nb\n'))
|
|
|
|
const captureCat = async (argv) => {
|
|
catOut.length = 0
|
|
const prevWrite = process.stdout.write
|
|
process.stdout.write = (chunk) => {
|
|
catOut.push(
|
|
typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8')
|
|
)
|
|
return true
|
|
}
|
|
try {
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, argv)
|
|
} finally {
|
|
process.stdout.write = prevWrite
|
|
}
|
|
}
|
|
|
|
await captureCat(['cat', '-n', 'plain.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(catOut.join(''), ' 1\ta\n 2\tb\n')
|
|
|
|
await captureCat(['cat', '-A', 'plain.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(catOut.join(''), 'a$\nb$\n')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, [
|
|
'env',
|
|
'-i',
|
|
'PATH=/bin',
|
|
'HELLO=there',
|
|
'printf',
|
|
'%s',
|
|
'ok'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), 'ok')
|
|
t.is(ctx.vfs.env.MARK, 'parent')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['touch', '-d', '@3600', 'ts.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
const stTs = await ctx.vfs.lstat('ts.txt')
|
|
t.is(stTs && stTs.mtimeMs, 3600000)
|
|
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['touch', 'ref.txt'])
|
|
const stRef = await ctx.vfs.lstat('ref.txt')
|
|
t.ok(stRef && typeof stRef.mtimeMs === 'number')
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['touch', '-r', 'ref.txt', 'ts2.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
const st2 = await ctx.vfs.lstat('ts2.txt')
|
|
t.is(st2 && st2.mtimeMs, stRef.mtimeMs)
|
|
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['mkdir', '-m', '700', 'secret_dir'])
|
|
t.is(ctx.exitCode, 0)
|
|
const stD = await ctx.vfs.lstat('secret_dir')
|
|
t.ok(stD && (stD.mode & 0o777) === 0o700)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('printenv -0 uses ctx.bareOsBinWrite when stdout is unavailable', async (t) => {
|
|
const dir = testCorestoreDir('binw')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pbin'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/printenv', b4a.from(await readBuiltBin('printenv')))
|
|
const raw = []
|
|
const ctx = testCtx(drive, personal, { ZZ: 'z', AA: 'a' })
|
|
ctx.exitCode = 0
|
|
ctx.runBinCommand = function (argv, o) {
|
|
return runBinCommand(this, argv, o)
|
|
}
|
|
ctx.bareOsBinWrite = (u) => {
|
|
raw.push(b4a.toString(u instanceof Uint8Array ? u : new Uint8Array(u)))
|
|
}
|
|
ctx.console = { log() {}, error() {} }
|
|
await runBinCommand(ctx, ['printenv', '-0', 'AA', 'ZZ'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(raw.join(''), 'a\0z\0')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('sed and awk golden one-liners', async (t) => {
|
|
const dir = testCorestoreDir('sawk')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('psawk'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/sed', b4a.from(await readBuiltBin('sed')))
|
|
await drive.put('/bin/awk', b4a.from(await readBuiltBin('awk')))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error() {}
|
|
}
|
|
await ctx.vfs.chdir('/home/user')
|
|
await ctx.vfs.writeFile('f.txt', b4a.from('abc\ndef\n'))
|
|
await runBinCommand(ctx, ['sed', '-e', 's/a/X/', 'f.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), 'Xbc\ndef')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['awk', '{ print NF }', 'f.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines.join('\n'), '1\n1')
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('curl delegated from booter with stub fetch', async (t) => {
|
|
const dir = testCorestoreDir('curl')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pcurl'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push('e:' + String(s))
|
|
}
|
|
}
|
|
/** @type {RequestInit | undefined} */
|
|
let curlInitHello
|
|
ctx.httpFetch = async (_url, init) => {
|
|
curlInitHello = init
|
|
return new Response('hello', {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'text/plain' }
|
|
})
|
|
}
|
|
await runBinCommand(ctx, ['curl', 'https://stub.example/x'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], 'hello')
|
|
t.is(headerFromInit(curlInitHello, 'User-Agent'), DEFAULT_CURL_USER_AGENT)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async () => new Response('', { status: 404 })
|
|
await runBinCommand(ctx, ['curl', '-f', '-s', 'https://stub.example/missing'])
|
|
t.is(ctx.exitCode, 22)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
let curlSeenUrl = ''
|
|
/** @type {RequestInit | undefined} */
|
|
let curlSeenInit
|
|
ctx.httpFetch = async (url, init) => {
|
|
curlSeenUrl = String(url)
|
|
curlSeenInit = init
|
|
return new Response('', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, ['curl', 'example.com', '-IL'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(curlSeenUrl, 'http://example.com')
|
|
t.is(curlSeenInit && curlSeenInit.method, 'HEAD')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
/** @type {{ url: string, method: string }[]} */
|
|
const curlHopCalls = []
|
|
ctx.httpFetch = async (url, init) => {
|
|
const u = String(url)
|
|
const method = String(init?.method || 'GET')
|
|
curlHopCalls.push({ url: u, method })
|
|
if (method === 'HEAD' && u === 'http://hop.example/start') {
|
|
return new Response('', {
|
|
status: 302,
|
|
headers: { Location: 'https://hop.example/done' }
|
|
})
|
|
}
|
|
if (method === 'GET' && u === 'https://hop.example/done') {
|
|
return new Response('secret-body', {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'text/plain' }
|
|
})
|
|
}
|
|
return new Response('unexpected', { status: 500 })
|
|
}
|
|
await runBinCommand(ctx, ['curl', '-IL', 'http://hop.example/start'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(curlHopCalls.length, 2)
|
|
t.is(curlHopCalls[0].method, 'HEAD')
|
|
t.is(curlHopCalls[1].method, 'GET')
|
|
t.ok(lines[0].includes('200'))
|
|
t.ok(!lines[0].includes('secret-body'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async (url) => {
|
|
curlSeenUrl = String(url)
|
|
return new Response('', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, ['curl', '-I', '//stub.example/p'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(curlSeenUrl, 'https://stub.example/p')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
/** @type {RequestInit | undefined} */
|
|
let curlInitUa
|
|
ctx.httpFetch = async (_url, init) => {
|
|
curlInitUa = init
|
|
return new Response('x', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-A',
|
|
'CustomCurlUA/9',
|
|
'https://stub.example/ua'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(headerFromInit(curlInitUa, 'User-Agent'), 'CustomCurlUA/9')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async (_url, init) => {
|
|
curlInitUa = init
|
|
return new Response('x', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-H',
|
|
'User-Agent: from-header',
|
|
'-A',
|
|
'from-flag',
|
|
'https://stub.example/ua2'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(headerFromInit(curlInitUa, 'User-Agent'), 'from-flag')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async (_url, init) => {
|
|
curlInitUa = init
|
|
return new Response('x', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-A',
|
|
'from-flag',
|
|
'-H',
|
|
'User-Agent: from-header',
|
|
'https://stub.example/ua3'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(headerFromInit(curlInitUa, 'User-Agent'), 'from-header')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async () =>
|
|
new Response('body-o', {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'text/plain' }
|
|
})
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-sO',
|
|
'https://stub.example/dir/named.txt'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
const named = await ctx.vfs.readFile('named.txt')
|
|
t.is(ctx.b4a.toString(named), 'body-o')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['curl', '-o', 'x', '-O', 'https://stub.example/y'])
|
|
t.is(ctx.exitCode, 2)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
/** @type {{ url: string, method: string }[]} */
|
|
const curlRedirectCountCalls = []
|
|
ctx.httpFetch = async (url, init) => {
|
|
const u = String(url)
|
|
const method = String(init?.method || 'GET')
|
|
curlRedirectCountCalls.push({ url: u, method })
|
|
if (method === 'HEAD' && u === 'http://rc.example/a') {
|
|
return new Response('', {
|
|
status: 302,
|
|
headers: { Location: 'https://rc.example/b' }
|
|
})
|
|
}
|
|
if (method === 'GET' && u === 'https://rc.example/b') {
|
|
return new Response('', { status: 200 })
|
|
}
|
|
return new Response('bad', { status: 500 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-s',
|
|
'-w',
|
|
'%{num_redirects}',
|
|
'-o',
|
|
'hdr.dump',
|
|
'-IL',
|
|
'http://rc.example/a'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[lines.length - 1], '1')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async () =>
|
|
new Response('wfmt', {
|
|
status: 201,
|
|
headers: { 'Content-Type': 'application/json; charset=utf-8' }
|
|
})
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-s',
|
|
'-w',
|
|
'%{response_code}|%{content_type}|%{method}|%{scheme}|%{host}|%{path}',
|
|
'-o',
|
|
'w.out',
|
|
'https://stub.example/api/v1?q=1'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(
|
|
lines[lines.length - 1],
|
|
'201|application/json; charset=utf-8|GET|https|stub.example|/api/v1?q=1'
|
|
)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
/** @type {RequestInit | undefined} */
|
|
let curlCookieInit
|
|
ctx.httpFetch = async (_url, init) => {
|
|
curlCookieInit = init
|
|
return new Response('c', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-b',
|
|
'sid=abc',
|
|
'https://stub.example/cookie-inline'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(headerFromInit(curlCookieInit, 'Cookie'), 'sid=abc')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile(
|
|
'/home/user/cookies.json',
|
|
b4a.from(JSON.stringify({ 'stub.example': { x: 'y' } }), 'utf8')
|
|
)
|
|
ctx.httpFetch = async (_url, init) => {
|
|
curlCookieInit = init
|
|
return new Response('c', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-b',
|
|
'/home/user/cookies.json',
|
|
'https://stub.example/cookie-file'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(String(headerFromInit(curlCookieInit, 'Cookie')).includes('x=y'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async () =>
|
|
new Response('z', {
|
|
status: 200,
|
|
headers: { 'Set-Cookie': 'sess=hello; Path=/' }
|
|
})
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'-c',
|
|
'/home/user/jar.json',
|
|
'https://stub.example/jar'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
const jraw = await ctx.vfs.readFile('/home/user/jar.json')
|
|
t.ok(jraw && ctx.b4a.toString(jraw).includes('sess'))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
/** @type {{ insecure?: boolean, caPem?: string, certPem?: string, keyPem?: string } | null} */
|
|
let curlTlsSeen = null
|
|
ctx.httpFetch = async (_url, init) => {
|
|
curlTlsSeen = init && init.bareOsCurlTls
|
|
return new Response('z', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, ['curl', '-k', 'https://stub.example/insecure'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(curlTlsSeen && curlTlsSeen.insecure === true)
|
|
t.is(lines[0], 'z')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile(
|
|
'/home/user/ca-test.pem',
|
|
b4a.from('-----BEGIN CERTIFICATE-----\nTEST\n-----END CERTIFICATE-----\n')
|
|
)
|
|
let cacertInit = null
|
|
ctx.httpFetch = async (_url, init) => {
|
|
cacertInit = init && init.bareOsCurlTls
|
|
return new Response('pem-ok', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'--cacert',
|
|
'/home/user/ca-test.pem',
|
|
'https://stub.example/ca'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(
|
|
cacertInit &&
|
|
typeof cacertInit.caPem === 'string' &&
|
|
cacertInit.caPem.includes('BEGIN CERTIFICATE')
|
|
)
|
|
t.is(lines[0], 'pem-ok')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile(
|
|
'/home/user/client-cert.pem',
|
|
b4a.from('-----BEGIN CERTIFICATE-----\nCLIENT\n-----END CERTIFICATE-----\n')
|
|
)
|
|
await ctx.vfs.writeFile(
|
|
'/home/user/client-key.pem',
|
|
b4a.from('-----BEGIN PRIVATE KEY-----\nKEY\n-----END PRIVATE KEY-----\n')
|
|
)
|
|
let mtlsInit = null
|
|
ctx.httpFetch = async (_url, init) => {
|
|
mtlsInit = init && init.bareOsCurlTls
|
|
return new Response('mtls-ok', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'--cert',
|
|
'/home/user/client-cert.pem',
|
|
'--key',
|
|
'/home/user/client-key.pem',
|
|
'https://stub.example/mtls'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.ok(mtlsInit && String(mtlsInit.certPem || '').includes('CLIENT'))
|
|
t.ok(mtlsInit && String(mtlsInit.keyPem || '').includes('PRIVATE KEY'))
|
|
t.is(lines[0], 'mtls-ok')
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('curl --connect-timeout aborts hanging stub fetch', async (t) => {
|
|
const dir = testCorestoreDir('curlcto')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pccto'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = { log() {}, error() {} }
|
|
ctx.httpFetch = async (_url, init) =>
|
|
new Promise((_resolve, reject) => {
|
|
const sig = init && init.signal
|
|
if (sig && sig.aborted) {
|
|
reject(new Error('The operation was aborted'))
|
|
return
|
|
}
|
|
if (sig) {
|
|
sig.addEventListener('abort', () =>
|
|
reject(new Error('The operation was aborted'))
|
|
)
|
|
}
|
|
})
|
|
await runBinCommand(ctx, [
|
|
'curl',
|
|
'--connect-timeout',
|
|
'1',
|
|
'https://stub.example/hang'
|
|
])
|
|
t.is(ctx.exitCode, 7)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('wget delegated from booter with stub fetch', async (t) => {
|
|
const dir = testCorestoreDir('wget')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pwget'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = {
|
|
log(s) {
|
|
lines.push(String(s))
|
|
},
|
|
error(s) {
|
|
lines.push('e:' + String(s))
|
|
}
|
|
}
|
|
/** @type {RequestInit | undefined} */
|
|
let wgetInitPayload
|
|
ctx.httpFetch = async (_url, init) => {
|
|
wgetInitPayload = init
|
|
return new Response('payload', {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'text/plain' }
|
|
})
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'wget',
|
|
'-O',
|
|
'saved.txt',
|
|
'-q',
|
|
'https://stub.example/a'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(headerFromInit(wgetInitPayload, 'User-Agent'), DEFAULT_WGET_USER_AGENT)
|
|
const out = await ctx.vfs.readFile('saved.txt')
|
|
t.ok(out)
|
|
t.is(ctx.b4a.toString(out), 'payload')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async () => new Response('', { status: 500 })
|
|
await runBinCommand(ctx, ['wget', '-q', 'https://stub.example/err'])
|
|
t.is(ctx.exitCode, 8)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
ctx.httpFetch = async () => new Response('stdout-body', { status: 200 })
|
|
await runBinCommand(ctx, ['wget', '-O', '-', '-q', 'https://stub.example/b'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(lines[0], 'stdout-body')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
let wgetSeenUrl = ''
|
|
ctx.httpFetch = async (url) => {
|
|
wgetSeenUrl = String(url)
|
|
return new Response('p2', {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'text/plain' }
|
|
})
|
|
}
|
|
await runBinCommand(ctx, ['wget', 'stub.example/z', '-qO', 'w2.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(wgetSeenUrl, 'http://stub.example/z')
|
|
const w2 = await ctx.vfs.readFile('w2.txt')
|
|
t.ok(w2)
|
|
t.is(ctx.b4a.toString(w2), 'p2')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
/** @type {RequestInit | undefined} */
|
|
let wgetInitU
|
|
ctx.httpFetch = async (_url, init) => {
|
|
wgetInitU = init
|
|
return new Response('u', { status: 200 })
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'wget',
|
|
'-q',
|
|
'-U',
|
|
'WgetCustom/1',
|
|
'-O',
|
|
'u.txt',
|
|
'https://stub.example/u'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
t.is(headerFromInit(wgetInitU, 'User-Agent'), 'WgetCustom/1')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['wget', '-c', '-O', '-', 'https://stub.example/n'])
|
|
t.is(ctx.exitCode, 2)
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['wget', '-N', 'https://stub.example/n-ts'])
|
|
t.is(ctx.exitCode, 2)
|
|
t.ok(lines.some((l) => l.includes('--timestamping')))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await runBinCommand(ctx, ['wget', '--timestamping', 'https://stub.example/n-ts2'])
|
|
t.is(ctx.exitCode, 2)
|
|
t.ok(lines.some((l) => l.includes('--timestamping')))
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile('partial.bin', b4a.from('ab'))
|
|
ctx.httpFetch = async (_url, init) => {
|
|
t.is(headerFromInit(init, 'Range'), 'bytes=2-')
|
|
return new Response('cde', {
|
|
status: 206,
|
|
headers: { 'Content-Type': 'application/octet-stream' }
|
|
})
|
|
}
|
|
await runBinCommand(ctx, [
|
|
'wget',
|
|
'-q',
|
|
'-c',
|
|
'-O',
|
|
'partial.bin',
|
|
'https://stub.example/resume'
|
|
])
|
|
t.is(ctx.exitCode, 0)
|
|
const merged = await ctx.vfs.readFile('partial.bin')
|
|
t.is(ctx.b4a.toString(merged), 'abcde')
|
|
|
|
lines.length = 0
|
|
ctx.exitCode = 0
|
|
await ctx.vfs.writeFile('part.txt', b4a.from('ab'))
|
|
ctx.httpFetch = async (_url, init) => {
|
|
t.is(headerFromInit(init, 'Range'), 'bytes=2-')
|
|
return new Response('cd', { status: 206 })
|
|
}
|
|
await runBinCommand(ctx, ['wget', '-qc', 'http://stub.example/blob/part.txt'])
|
|
t.is(ctx.exitCode, 0)
|
|
const partMerged = await ctx.vfs.readFile('part.txt')
|
|
t.is(ctx.b4a.toString(partMerged), 'abcd')
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('tier-1 rm -rf removes directory tree on personal drive', async (t) => {
|
|
const dir = testCorestoreDir('rmrf')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('prm'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/rm', b4a.from(await readBuiltBin('rm')))
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.exitCode = 0
|
|
ctx.console = { log() {}, error() {} }
|
|
await personal.put(
|
|
personalHomeBacking('/home/user', 'nest/leaf/x.txt'),
|
|
b4a.from('x')
|
|
)
|
|
await personal.put(
|
|
personalHomeBacking('/home/user', 'nest/other/y.txt'),
|
|
b4a.from('y')
|
|
)
|
|
t.ok((await ctx.vfs.readdir('nest')).includes('leaf'))
|
|
await runBinCommand(ctx, ['rm', '-rf', 'nest'])
|
|
t.is(ctx.exitCode, 0)
|
|
const after = await ctx.vfs.readdir('.')
|
|
t.ok(!after.includes('nest'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('git-fs-adapter mkdir recursive and readdir hides .bareos_empty', async (t) => {
|
|
const dir = testCorestoreDir('gitfs')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pgf'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const ctx = testCtx(drive, personal)
|
|
const fs = createGitFsFromVfs(ctx.vfs)
|
|
const base = '/home/user/gittest'
|
|
await fs.promises.mkdir(path.posix.join(base, 'a', 'b'), { recursive: true })
|
|
const inA = await fs.promises.readdir(path.posix.join(base, 'a'))
|
|
t.is(inA.indexOf('.bareos_empty'), -1)
|
|
t.ok(inA.includes('b'))
|
|
const top = await fs.promises.readdir(base)
|
|
t.ok(top.includes('a'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|