local createLibTest = require('/apis/libtest'); local testlib = createLibTest({ ... }); local function parentDir(path) return path:match('^(.*)/[^/]+$'); end local function sandboxPath(root, path) if path:sub(1, 1) == '/' then return root .. path; end return root .. '/' .. path; end local function fakeFs(root) return { exists = function(path) return fs.exists(sandboxPath(root, path)); end, makeDir = function(path) fs.makeDir(sandboxPath(root, path)); end, open = function(path, mode) return fs.open(sandboxPath(root, path), mode); end, delete = function(path) fs.delete(sandboxPath(root, path)); end, }; end local function fakeHttp(routes) return { get = function(url) local body = routes[url]; if not body then return nil; end return { readAll = function() return body; end, close = function() end, }; end, }; end local INSTALL_BASE = 'https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/master/'; local function installRoutes() return { [INSTALL_BASE .. 'manifest.json'] = textutils.serializeJSON({ name = 'TrapOS', version = 'test' }), [INSTALL_BASE .. 'packages/trapos-core/ccpm.json'] = textutils.serializeJSON({ name = 'trapos-core', version = '1', dependencies = {}, files = { 'apis/libccpm.lua', 'programs/ccpm.lua' }, }), [INSTALL_BASE .. 'apis/libccpm.lua'] = 'libccpm-body', [INSTALL_BASE .. 'programs/ccpm.lua'] = 'ccpm-body', }; end -- Run install-trapos.lua inside a sandboxed env. `args` is a list of CLI args. -- Returns { calls, root } for assertions. local function runInstall(root, args) fs.delete(root); fs.makeDir(root); local routes = installRoutes(); local calls = { executes = {}, path = '/rom/programs', dir = '/', rebooted = false, }; local fsApi = fakeFs(root); local env = setmetatable({ fs = fsApi, http = fakeHttp(routes), os = { reboot = function() calls.rebooted = true; calls.executes[#calls.executes + 1] = { program = '__reboot__', args = {} }; end, }, print = function() end, read = function() return 'yes'; end, write = function() end, shell = { dir = function() return calls.dir; end, setDir = function(path) calls.dir = path; end, path = function() return calls.path; end, setPath = function(path) calls.path = path; end, execute = function(program, ...) local rest = { ... }; calls.executes[#calls.executes + 1] = { program = program, args = rest }; if program ~= 'wget' then return true; end local url, target = rest[1], rest[2]; local body = routes[url]; if not body then return false; end local dir = parentDir(target); if dir then fsApi.makeDir(dir); end local f = fsApi.open(target, 'w'); f.write(body); f.close(); return true; end, }, }, { __index = _G }); local chunk, loadErr = loadfile('/trapos/install-trapos.lua', 't', env); if not chunk then error(loadErr, 0); end local ok, err = pcall(chunk, table.unpack(args)); if not ok then error(err, 0); end return calls; end local function findExecute(calls, program, firstArg) for _, call in ipairs(calls.executes) do if call.program == program then if firstArg == nil or call.args[1] == firstArg then return true; end end end return false; end local function findExecuteIndex(calls, program, firstArg) for i, call in ipairs(calls.executes) do if call.program == program then if firstArg == nil or call.args[1] == firstArg then return i; end end end return nil; end testlib.test('programs path resolves the ccpm command', function() local previous = shell.path(); shell.setPath('/rom/programs:/programs'); local resolved = shell.resolveProgram('ccpm'); shell.setPath(previous); testlib.assertEquals(resolved, 'programs/ccpm.lua'); end); testlib.test('fresh bootstrap seeds a gitea master registry and runs ccpm', function() local root = '/install-trapos-test/full'; local calls = runInstall(root, {}); testlib.assertTrue(fs.exists(root .. '/programs/ccpm.lua')); testlib.assertTrue(string.find(calls.path, '/programs', 1, true)); local f = fs.open(root .. '/trapos/ccpm.json', 'r'); local config = textutils.unserializeJSON(f.readAll()); f.close(); testlib.assertEquals(config.registries[1].branch, 'master'); testlib.assertEquals(config.registries[1].type, 'gitea'); f = fs.open(root .. '/trapos/ccpm.lock.json', 'r'); local lock = textutils.unserializeJSON(f.readAll()); f.close(); testlib.assertEquals(lock.packages['trapos-core'].explicit, false); end); testlib.test('default install runs update, install trapos and postinstall', function() local root = '/install-trapos-test/default'; local calls = runInstall(root, {}); testlib.assertTrue(findExecute(calls, 'ccpm', 'update')); testlib.assertTrue(findExecute(calls, 'ccpm', 'install')); testlib.assertTrue(findExecute(calls, 'trapos-postinstall')); end); testlib.test('default install runs postinstall before reboot', function() local root = '/install-trapos-test/order'; local calls = runInstall(root, {}); local postinstallIndex = findExecuteIndex(calls, 'trapos-postinstall'); local rebootIndex = findExecuteIndex(calls, '__reboot__'); testlib.assertTrue(postinstallIndex ~= nil, 'postinstall was not run'); testlib.assertTrue(rebootIndex ~= nil, 'reboot was not run'); testlib.assertTrue(postinstallIndex < rebootIndex, 'postinstall must run before reboot'); testlib.assertEquals(calls.rebooted, true); end); testlib.test('--cpm-only stops after the ccpm bootstrap', function() local root = '/install-trapos-test/cpm-only'; local calls = runInstall(root, { '--cpm-only' }); testlib.assertTrue(fs.exists(root .. '/programs/ccpm.lua')); testlib.assertTrue(not findExecute(calls, 'ccpm', 'update')); testlib.assertTrue(not findExecute(calls, 'ccpm', 'install')); testlib.assertTrue(not findExecute(calls, 'trapos-postinstall')); testlib.assertEquals(calls.rebooted, false); local f = fs.open(root .. '/trapos/ccpm.lock.json', 'r'); local lock = textutils.unserializeJSON(f.readAll()); f.close(); testlib.assertEquals(lock.packages['trapos-core'].explicit, true); end); testlib.run();