/* * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter. * * Puter is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/putility"); const useapi = require("useapi"); const { BaseService } = require("../exports"); const CoreModule = require("../src/CoreModule"); const { Context } = require("../src/util/context"); const { Kernel } = require("../src/Kernel"); const { HTTPThumbnailService } = require("../src/services/thumbnails/HTTPThumbnailService"); class TestLogger { constructor () { console.log( `\x1B[36;1mBoot logger started :)\x1B[0m`, ); } info (...args) { console.log( '\x1B[36;1m[TESTKERNEL/INFO]\x1B[0m', ...args, ); } error (...args) { console.log( '\x1B[31;1m[TESTKERNEL/ERROR]\x1B[0m', ...args, ); } } class TestKernel extends AdvancedBase { constructor () { super(); this.modules = []; this.useapi = useapi(); this.useapi.withuse(() => { def('Module', AdvancedBase) def('Service', BaseService) }); this.logfn_ = (...a) => a; } add_module (module) { this.modules.push(module); } boot () { const { consoleLogManager } = require('../src/util/consolelog'); consoleLogManager.initialize_proxy_methods(); consoleLogManager.decorate_all(({ manager, replace }, ...a) => { replace(...this.logfn_(...a)); }); const { Container } = require('../src/services/Container'); this.testLogger = new TestLogger(); const services = new Container({ logger: this.testLogger }); this.services = services; // app.set('services', services); const root_context = Context.create({ services, useapi: this.useapi, }, 'app'); globalThis.root_context = root_context; root_context.arun(async () => { await this._install_modules(); // await this._boot_services(); }); // Error.stackTraceLimit = Infinity; Error.stackTraceLimit = 200; } async _install_modules () { const { services } = this; const mod_install_root_context = Context.get(); for ( const module of this.modules ) { console.log('module?"???', module) const mod_context = this._create_mod_context( mod_install_root_context, { name: module.constructor.name, ['module']: module, external: false, }, ); await module.install(mod_context); } // Real kernel initializes services here, but in this test kernel // we don't initialize any services. // Real kernel adds legacy services here but these will break // the test kernel. services.ready.resolve(); // provide services to helpers // const { tmp_provide_services } = require('../src/helpers'); // tmp_provide_services(services); } } TestKernel.prototype._create_mod_context = Kernel.prototype._create_mod_context; const k = new TestKernel(); k.add_module(new CoreModule()); k.add_module({ install: async (context) => { const services = context.get('services'); services.registerService('thumbs-http', HTTPThumbnailService); } }); k.boot(); const do_after_tests_ = []; // const do_after_tests = (fn) => { // do_after_tests_.push(fn); // }; const repeat_after = (fn) => { fn(); do_after_tests_.push(fn); }; let total_passed = 0; let total_failed = 0; const main = async () => { console.log('awaiting services readty'); await k.services.ready; console.log('services have become ready'); const service_names = process.argv.length > 2 ? process.argv.slice(2) : Object.keys(k.services.instances_); for ( const name of service_names) { if ( ! k.services.instances_[name] ) { console.log(`\x1B[31;1mService not found: ${name}\x1B[0m`); process.exit(1); } const ins = k.services.instances_[name]; ins.construct(); if ( ! ins._test || typeof ins._test !== 'function' ) { continue; } let passed = 0; let failed = 0; repeat_after(() => { console.log(`\x1B[33;1m=== [ Service :: ${name} ] ===\x1B[0m`); }); const testapi = { assert: (condition, name) => { name = name || condition.toString(); if ( condition() ) { passed++; repeat_after(() => console.log(`\x1B[32;1m ✔ ${name}\x1B[0m`)); } else { failed++; repeat_after(() => console.log(`\x1B[31;1m ✘ ${name}\x1B[0m`)); } } }; testapi.assert.equal = (a, b, name) => { name = name || `${a} === ${b}`; if ( a === b ) { passed++; repeat_after(() => console.log(`\x1B[32;1m ✔ ${name}\x1B[0m`)); } else { failed++; repeat_after(() => { console.log(`\x1B[31;1m ✘ ${name}\x1B[0m`); console.log(`\x1B[31;1m Expected: ${b}\x1B[0m`); console.log(`\x1B[31;1m Got: ${a}\x1B[0m`); }); } }; await ins._test(testapi); total_passed += passed; total_failed += failed; } console.log(`\x1B[36;1m<===\x1B[0m ` + 'ASSERTION OUTPUTS ARE REPEATED BELOW' + ` \x1B[36;1m===>\x1B[0m`); for ( const fn of do_after_tests_ ) { fn(); } console.log(`\x1B[36;1m=== [ Summary ] ===\x1B[0m`); console.log(`Passed: ${total_passed}`); console.log(`Failed: ${total_failed}`); process.exit(total_failed ? 1 : 0); } main();