bf315258c5
format is part of the backup target in the future, if we want per-app format or schedule, we can add this separately to the apps table itself. the full box backup can ignore apps with a set backup target and use the latest backup (like an errored app). the nice thing is restore will work correctly.
268 lines
7.1 KiB
JavaScript
268 lines
7.1 KiB
JavaScript
'use strict';
|
|
|
|
const apps = require('../apps.js'),
|
|
appstore = require('../appstore.js'),
|
|
backups = require('../backups.js'),
|
|
constants = require('../constants.js'),
|
|
cron = require('../cron.js'),
|
|
dashboard = require('../dashboard.js'),
|
|
database = require('../database.js'),
|
|
domains = require('../domains.js'),
|
|
expect = require('expect.js'),
|
|
fs = require('fs'),
|
|
locks = require('../locks.js'),
|
|
mailer = require('../mailer.js'),
|
|
mailServer = require('../mailserver.js'),
|
|
nock = require('nock'),
|
|
path = require('path'),
|
|
settings = require('../settings.js'),
|
|
tasks = require('../tasks.js'),
|
|
timers = require('timers/promises'),
|
|
users = require('../users.js');
|
|
|
|
const manifest = {
|
|
'id': 'io.cloudron.test',
|
|
'author': 'The Presidents Of the United States Of America',
|
|
'title': 'test title',
|
|
'description': 'test description',
|
|
'tagline': 'test rocks',
|
|
'website': 'http://test.cloudron.io',
|
|
'contactEmail': 'test@cloudron.io',
|
|
'version': '0.1.0',
|
|
'manifestVersion': 2,
|
|
'dockerImage': 'cloudron/test:25.2.0',
|
|
'healthCheckPath': '/',
|
|
'httpPort': 7777,
|
|
'tcpPorts': {
|
|
'ECHO_SERVER_PORT': {
|
|
'title': 'Echo Server Port',
|
|
'description': 'Echo server',
|
|
'containerPort': 7778
|
|
}
|
|
},
|
|
'addons': {
|
|
'oauth': { },
|
|
'redis': { },
|
|
'mysql': { },
|
|
'postgresql': { }
|
|
}
|
|
};
|
|
|
|
// copied from the proxy app CloudronManifest.json
|
|
const proxyAppManifest = {
|
|
'id': 'io.cloudron.builtin.appproxy',
|
|
'title': 'App Proxy',
|
|
'author': 'Cloudron Team',
|
|
'version': '1.0.0',
|
|
'upstreamVersion': '1.0.0',
|
|
'description': 'file://DESCRIPTION.md',
|
|
'tagline': 'Proxy an app through Cloudron',
|
|
'tags': [ 'proxy', 'external' ],
|
|
'healthCheckPath': '/',
|
|
'httpPort': 3000,
|
|
'minBoxVersion': '7.3.0',
|
|
'dockerImage': 'istobeignored',
|
|
'manifestVersion': 2,
|
|
'multiDomain': true,
|
|
'website': 'https://cloudron.io',
|
|
'documentationUrl': 'https://docs.cloudron.io/dashboard/#app-proxy',
|
|
'forumUrl': 'https://forum.cloudron.io',
|
|
'contactEmail': 'support@cloudron.io',
|
|
'icon': 'file://logo.png',
|
|
'addons': {},
|
|
'mediaLinks': [
|
|
'https://screenshots.cloudron.io/io.cloudron.builtin.appproxy/diagram.png'
|
|
],
|
|
'changelog': 'file://CHANGELOG.md'
|
|
};
|
|
|
|
const domain = {
|
|
domain: 'example.com',
|
|
zoneName: 'example.com',
|
|
provider: 'noop',
|
|
config: {},
|
|
fallbackCertificate: null,
|
|
tlsConfig: { provider: 'fallback' },
|
|
wellKnown: null
|
|
};
|
|
Object.freeze(domain);
|
|
|
|
const auditSource = { ip: '1.2.3.4' };
|
|
|
|
const admin = {
|
|
id: null,
|
|
username: 'testadmin',
|
|
password: 'secret123',
|
|
email: 'admin@me.com',
|
|
fallbackEmail: 'admin@external.com',
|
|
salt: 'morton',
|
|
createdAt: 'sometime back',
|
|
resetToken: '',
|
|
displayName: 'Administrator',
|
|
groupIds: [],
|
|
role: 'owner',
|
|
source: '',
|
|
avatar: null,
|
|
active: true,
|
|
};
|
|
|
|
const user = {
|
|
id: null,
|
|
username: 'user',
|
|
password: '123secret',
|
|
email: 'user@me.com',
|
|
fallbackEmail: 'user@external.com',
|
|
role: 'user',
|
|
salt: 'morton',
|
|
createdAt: 'sometime back',
|
|
resetToken: '',
|
|
groupIds: [],
|
|
displayName: 'Normal User',
|
|
source: '',
|
|
avatar: null,
|
|
active: true,
|
|
};
|
|
|
|
const app = {
|
|
id: 'appid',
|
|
appStoreId: 'appStoreId',
|
|
installationState: apps.ISTATE_PENDING_INSTALL,
|
|
runState: 'running',
|
|
subdomain: 'applocation',
|
|
domain: domain.domain,
|
|
fqdn: domain.domain + '.' + 'applocation',
|
|
manifest,
|
|
containerId: 'someid',
|
|
portBindings: {},
|
|
accessRestriction: null,
|
|
memoryLimit: 0,
|
|
mailboxDomain: domain.domain,
|
|
secondaryDomains: [],
|
|
redirectDomains: [],
|
|
aliasDomains: []
|
|
};
|
|
Object.freeze(app);
|
|
|
|
const proxyApp = {
|
|
id: 'proxyapptestid',
|
|
appStoreId: proxyAppManifest.id,
|
|
installationState: apps.ISTATE_PENDING_INSTALL,
|
|
runState: 'running',
|
|
subdomain: 'proxylocation',
|
|
upstreamUri: 'http://1.2.3.4:80',
|
|
domain: domain.domain,
|
|
fqdn: domain.domain + '.' + 'proxylocation',
|
|
manifest: proxyAppManifest,
|
|
containerId: '',
|
|
portBindings: {},
|
|
accessRestriction: null,
|
|
memoryLimit: 0,
|
|
mailboxDomain: domain.domain,
|
|
secondaryDomains: [],
|
|
redirectDomains: [],
|
|
aliasDomains: []
|
|
};
|
|
Object.freeze(proxyApp);
|
|
|
|
exports = module.exports = {
|
|
createTree,
|
|
domainSetup,
|
|
databaseSetup,
|
|
setup,
|
|
cleanup,
|
|
checkMails,
|
|
clearMailQueue,
|
|
|
|
mockApiServerOrigin: 'http://localhost:6060',
|
|
dashboardDomain: domain.domain,
|
|
dashboardFqdn: `my.${domain.domain}`,
|
|
|
|
app,
|
|
proxyApp,
|
|
admin,
|
|
auditSource,
|
|
domain, // the domain object
|
|
manifest,
|
|
user,
|
|
appstoreToken: 'atoken',
|
|
|
|
defaultBackupTarget: { id: null },
|
|
|
|
serverUrl: `http://localhost:${constants.PORT}`,
|
|
};
|
|
|
|
function createTree(root, obj) {
|
|
fs.rmSync(root, { recursive: true, force: true });
|
|
fs.mkdirSync(root, { recursive: true });
|
|
|
|
function createSubTree(tree, curpath) {
|
|
for (const key in tree) {
|
|
if (typeof tree[key] === 'string') {
|
|
if (key.startsWith('link:')) {
|
|
fs.symlinkSync(tree[key], path.join(curpath, key.slice(5)));
|
|
} else {
|
|
fs.writeFileSync(path.join(curpath, key), tree[key], 'utf8');
|
|
}
|
|
} else {
|
|
fs.mkdirSync(path.join(curpath, key));
|
|
createSubTree(tree[key], path.join(curpath, key));
|
|
}
|
|
}
|
|
}
|
|
|
|
createSubTree(obj, root);
|
|
}
|
|
|
|
async function databaseSetup() {
|
|
nock.cleanAll();
|
|
|
|
await database.initialize();
|
|
await database._clear();
|
|
await appstore._setApiServerOrigin(exports.mockApiServerOrigin);
|
|
await dashboard._setLocation(constants.DASHBOARD_SUBDOMAIN, exports.dashboardDomain);
|
|
exports.defaultBackupTarget.id = await backups._addDefaultTarget();
|
|
}
|
|
|
|
async function domainSetup() {
|
|
nock.cleanAll();
|
|
|
|
await databaseSetup();
|
|
await mailServer.setLocation(constants.DASHBOARD_SUBDOMAIN, domain.domain); // default mail location. do this before we add the domain for upserting mail DNS
|
|
await domains.add(domain.domain, domain, auditSource);
|
|
}
|
|
|
|
async function setup() {
|
|
await domainSetup();
|
|
const ownerId = await users.createOwner(admin.email, admin.username, admin.password, admin.displayName, auditSource);
|
|
admin.id = ownerId;
|
|
await apps.add(app.id, app.appStoreId, app.manifest, app.subdomain, app.domain, app.portBindings, app);
|
|
await settings._set(settings.APPSTORE_API_TOKEN_KEY, exports.appstoreToken); // appstore token
|
|
const userId = await users.add(user.email, user, auditSource);
|
|
user.id = userId;
|
|
await tasks.stopAllTasks();
|
|
await locks.releaseAll();
|
|
}
|
|
|
|
async function cleanup() {
|
|
nock.cleanAll();
|
|
mailer._mailQueue = [];
|
|
|
|
await cron.stopJobs();
|
|
await database._clear();
|
|
await database.uninitialize();
|
|
}
|
|
|
|
function clearMailQueue() {
|
|
mailer._mailQueue = [];
|
|
}
|
|
|
|
async function checkMails(number) {
|
|
await timers.setTimeout(1000);
|
|
expect(mailer._mailQueue.length).to.equal(number);
|
|
const emails = mailer._mailQueue;
|
|
clearMailQueue();
|
|
|
|
// return for further investigation
|
|
return emails;
|
|
}
|