docker based tests
This commit is contained in:
@@ -49,5 +49,5 @@ if [[ $# -gt 0 ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "=> Run tests"
|
echo "=> Run tests"
|
||||||
docker run -e BOX_ENV=test -e DATABASE_HOSTNAME=${MYSQL_IP} -v `pwd`:/home/yellowtent/box:ro -v `which node`:/usr/bin/node:ro -t cloudron/boxtest node_modules/.bin/mocha --bail --no-timeouts --colors --exit -R spec src/test
|
docker run -e BOX_ENV=test -e DATABASE_HOSTNAME=${MYSQL_IP} -v `pwd`:/home/yellowtent/box:ro -v `which node`:/usr/bin/node:ro -v /var/run/docker.sock:/var/run/docker.sock -t cloudron/boxtest node_modules/.bin/mocha --bail --no-timeouts --colors --exit -R spec src/test
|
||||||
|
|
||||||
|
|||||||
@@ -46,11 +46,18 @@ fi
|
|||||||
# DEBUG has to be hardcoded because it is not set in the tests. --setenv is required for ubuntu 16 (-E does not work)
|
# DEBUG has to be hardcoded because it is not set in the tests. --setenv is required for ubuntu 16 (-E does not work)
|
||||||
# NODE_OPTIONS is used because env -S does not work in ubuntu 16/18.
|
# NODE_OPTIONS is used because env -S does not work in ubuntu 16/18.
|
||||||
# it seems systemd-run does not return the exit status of the process despite --wait
|
# it seems systemd-run does not return the exit status of the process despite --wait
|
||||||
if ! systemd-run --unit "${service_name}" --nice "${nice}" --uid=${id} --gid=${id} ${options} --setenv HOME=${HOME} --setenv USER=${SUDO_USER} --setenv DEBUG=box:* --setenv BOX_ENV=${BOX_ENV} --setenv NODE_ENV=production --setenv NODE_OPTIONS=--unhandled-rejections=strict --setenv AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE=1 "${task_worker}" "${task_id}" "${logfile}"; then
|
if [[ "$CI" == "1" ]]; then
|
||||||
echo "Service ${service_name} failed to run" # this only happens if the path to task worker itself is wrong
|
if ! DEBUG=box:* NODE_ENV=production NODE_OPTIONS=--unhandled-rejections=strict gosu $id:$id "${task_worker}" "${task_id}" "${logfile}"; then
|
||||||
fi
|
echo "Service ${service_name} failed to run" # this only happens if the path to task worker itself is wrong
|
||||||
|
fi
|
||||||
|
exit_code=$?
|
||||||
|
else
|
||||||
|
if ! systemd-run --unit "${service_name}" --nice "${nice}" --uid=${id} --gid=${id} ${options} --setenv HOME=${HOME} --setenv USER=${SUDO_USER} --setenv DEBUG=box:* --setenv BOX_ENV=${BOX_ENV} --setenv NODE_ENV=production --setenv NODE_OPTIONS=--unhandled-rejections=strict --setenv AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE=1 "${task_worker}" "${task_id}" "${logfile}"; then
|
||||||
|
echo "Service ${service_name} failed to run" # this only happens if the path to task worker itself is wrong
|
||||||
|
fi
|
||||||
|
|
||||||
exit_code=$(systemctl show "${service_name}" -p ExecMainCode | sed 's/ExecMainCode=//g')
|
exit_code=$(systemctl show "${service_name}" -p ExecMainCode | sed 's/ExecMainCode=//g')
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Service ${service_name} finished with exit code ${exit_code}"
|
echo "Service ${service_name} finished with exit code ${exit_code}"
|
||||||
exit "${exit_code}"
|
exit "${exit_code}"
|
||||||
|
|||||||
@@ -111,10 +111,10 @@ function sudo(tag, args, options, callback) {
|
|||||||
|
|
||||||
cp.stdout.on('data', (data) => {
|
cp.stdout.on('data', (data) => {
|
||||||
if (options.captureStdout) stdoutResult += data.toString('utf8');
|
if (options.captureStdout) stdoutResult += data.toString('utf8');
|
||||||
if (!options.quiet) process.stdout.write(data); // do not use debug to avoid double timestamps when calling backupupload.js
|
if (!options.quiet) process.stdout.write(data + '\r'); // do not use debug to avoid double timestamps when calling backupupload.js
|
||||||
});
|
});
|
||||||
cp.stderr.on('data', (data) => {
|
cp.stderr.on('data', (data) => {
|
||||||
process.stderr.write(data); // do not use debug to avoid double timestamps when calling backupupload.js
|
process.stderr.write(data + '\r'); // do not use debug to avoid double timestamps when calling backupupload.js
|
||||||
});
|
});
|
||||||
|
|
||||||
cp.on('exit', function (code, signal) {
|
cp.on('exit', function (code, signal) {
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ async function upload(apiConfig, backupFilePath) {
|
|||||||
return {
|
return {
|
||||||
stream: fs.createWriteStream(backupFilePath, { autoClose: true }),
|
stream: fs.createWriteStream(backupFilePath, { autoClose: true }),
|
||||||
async finish() {
|
async finish() {
|
||||||
|
console.log('OK CHOWNNIG!!!!!', process.env.SUDO_UID, process.getuid());
|
||||||
const backupUid = parseInt(process.env.SUDO_UID, 10) || process.getuid(); // in test, upload() may or may not be called via sudo script
|
const backupUid = parseInt(process.env.SUDO_UID, 10) || process.getuid(); // in test, upload() may or may not be called via sudo script
|
||||||
if (hasChownSupportSync(apiConfig)) {
|
if (hasChownSupportSync(apiConfig)) {
|
||||||
if (!safe.fs.chownSync(backupFilePath, backupUid, backupUid)) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unable to chown ${backupFilePath}: ${safe.error.message}`);
|
if (!safe.fs.chownSync(backupFilePath, backupUid, backupUid)) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unable to chown ${backupFilePath}: ${safe.error.message}`);
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ async function getDisks() {
|
|||||||
const DISK_TYPES = [ 'ext4', 'xfs', 'cifs', 'nfs', 'fuse.sshfs' ]; // we don't show size of contents in untracked disk types
|
const DISK_TYPES = [ 'ext4', 'xfs', 'cifs', 'nfs', 'fuse.sshfs' ]; // we don't show size of contents in untracked disk types
|
||||||
|
|
||||||
for (const disk of dfEntries) {
|
for (const disk of dfEntries) {
|
||||||
if (!DISK_TYPES.includes(disk.type)) continue;
|
if (!DISK_TYPES.includes(disk.type) && disk.mountpoint !== '/') continue;
|
||||||
if (disk.mountpoint === '/') rootDisk = disk;
|
if (disk.mountpoint === '/') rootDisk = disk;
|
||||||
disks[disk.filesystem] = {
|
disks[disk.filesystem] = {
|
||||||
filesystem: disk.filesystem,
|
filesystem: disk.filesystem,
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ function startTask(id, options, onTaskFinished) {
|
|||||||
let killTimerId = null, timedOut = false;
|
let killTimerId = null, timedOut = false;
|
||||||
|
|
||||||
const sudoOptions = { preserveEnv: true, logStream: null };
|
const sudoOptions = { preserveEnv: true, logStream: null };
|
||||||
if (constants.TEST) sudoOptions.logStream = fs.createWriteStream('/dev/null'); // without this output is messed up, not sure why
|
//if (constants.TEST) sudoOptions.logStream = fs.createWriteStream('/dev/null'); // without this output is messed up, not sure why
|
||||||
gTasks[id] = shell.sudo('startTask', [ START_TASK_CMD, id, logFile, options.nice || 0, options.memoryLimit || 400, options.oomScoreAdjust || 0 ], sudoOptions, async function (sudoError) {
|
gTasks[id] = shell.sudo('startTask', [ START_TASK_CMD, id, logFile, options.nice || 0, options.memoryLimit || 400, options.oomScoreAdjust || 0 ], sudoOptions, async function (sudoError) {
|
||||||
if (!gTasks[id]) return; // ignore task exit since we are shutting down. see stopAllTasks
|
if (!gTasks[id]) return; // ignore task exit since we are shutting down. see stopAllTasks
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const BoxError = require('../boxerror.js'),
|
|||||||
expect = require('expect.js'),
|
expect = require('expect.js'),
|
||||||
safe = require('safetydance');
|
safe = require('safetydance');
|
||||||
|
|
||||||
describe('Settings', function () {
|
describe('Cloudron', function () {
|
||||||
const { setup, cleanup } = common;
|
const { setup, cleanup } = common;
|
||||||
|
|
||||||
before(setup);
|
before(setup);
|
||||||
|
|||||||
@@ -17,27 +17,18 @@ describe('System', function () {
|
|||||||
after(cleanup);
|
after(cleanup);
|
||||||
|
|
||||||
it('can get disks', async function () {
|
it('can get disks', async function () {
|
||||||
// does not work on archlinux 8!
|
|
||||||
if (require('child_process').execSync('uname -a').toString().indexOf('-arch') !== -1) return;
|
|
||||||
|
|
||||||
const disks = await system.getDisks();
|
const disks = await system.getDisks();
|
||||||
expect(disks).to.be.ok();
|
expect(disks).to.be.ok();
|
||||||
expect(Object.keys(disks).some(fs => disks[fs].mountpoint === '/')).to.be.ok();
|
expect(Object.keys(disks).some(fs => disks[fs].mountpoint === '/')).to.be.ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can get swaps', async function () {
|
it('can get swaps', async function () {
|
||||||
// does not work on archlinux 8!
|
|
||||||
if (require('child_process').execSync('uname -a').toString().indexOf('-arch') !== -1) return;
|
|
||||||
|
|
||||||
const swaps = await system.getSwaps();
|
const swaps = await system.getSwaps();
|
||||||
expect(swaps).to.be.ok();
|
expect(swaps).to.be.ok();
|
||||||
expect(Object.keys(swaps).some(n => swaps[n].type === 'partition' || swaps[n].type === 'file')).to.be.ok();
|
expect(Object.keys(swaps).some(n => swaps[n].type === 'partition' || swaps[n].type === 'file')).to.be.ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can check for disk space', async function () {
|
it('can check for disk space', async function () {
|
||||||
// does not work on archlinux 8!
|
|
||||||
if (require('child_process').execSync('uname -a').toString().indexOf('-arch') !== -1) return;
|
|
||||||
|
|
||||||
await system.checkDiskSpace();
|
await system.checkDiskSpace();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
FROM ubuntu:jammy-20230816@sha256:b492494d8e0113c4ad3fe4528a4b5ff89faa5331f7d52c5c138196f69ce176a6
|
FROM ubuntu:jammy-20230816@sha256:b492494d8e0113c4ad3fe4528a4b5ff89faa5331f7d52c5c138196f69ce176a6
|
||||||
|
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
apt install -y openssl mysql-client-8.0 sudo lsb-release vim
|
apt install -y openssl mysql-client-8.0 sudo lsb-release vim gosu curl
|
||||||
|
|
||||||
RUN useradd --system --uid 808 --comment "Cloudron Box" --create-home --shell /usr/sbin/nologin yellowtent
|
RUN useradd --system --uid 808 --comment "Cloudron Box" --create-home --shell /usr/bin/bash yellowtent
|
||||||
|
|
||||||
RUN mkdir -p /mnt/cloudron-test-music /media/cloudron-test-music # volume test
|
RUN mkdir -p /mnt/cloudron-test-music /media/cloudron-test-music # volume test
|
||||||
|
|
||||||
|
# https://download.docker.com/linux/static/stable/x86_64/
|
||||||
|
RUN cd /usr/bin && curl -L https://download.docker.com/linux/static/stable/x86_64/docker-25.0.5.tgz | tar -zxvf - --strip-components=1 docker/docker
|
||||||
|
|
||||||
COPY setup/start/sudoers /etc/sudoers.d/cloudron
|
COPY setup/start/sudoers /etc/sudoers.d/cloudron
|
||||||
|
|
||||||
COPY test/cloak /usr/bin/cloak
|
COPY test/cloak /usr/bin/cloak
|
||||||
RUN ln -s /usr/bin/cloak /usr/bin/systemd-run && \
|
RUN ln -s /usr/bin/cloak /usr/bin/systemd-run && \
|
||||||
ln -s /usr/bin/cloak /usr/bin/systemctl
|
ln -s /usr/bin/cloak /usr/bin/systemctl
|
||||||
|
|
||||||
|
COPY test/entrypoint.sh /usr/bin/entrypoint.sh
|
||||||
|
|
||||||
WORKDIR /home/yellowtent
|
WORKDIR /home/yellowtent
|
||||||
USER yellowtent
|
USER yellowtent
|
||||||
|
|
||||||
@@ -24,3 +29,5 @@ RUN bash -c 'openssl req -x509 -newkey rsa:2048 -keyout platformdata/nginx/cert/
|
|||||||
|
|
||||||
WORKDIR /home/yellowtent/box
|
WORKDIR /home/yellowtent/box
|
||||||
|
|
||||||
|
USER root
|
||||||
|
ENTRYPOINT [ "/usr/bin/entrypoint.sh" ]
|
||||||
|
|||||||
10
test/entrypoint.sh
Executable file
10
test/entrypoint.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
docker_gid=$(stat -c "%g" /run/docker.sock)
|
||||||
|
addgroup --gid ${docker_gid} --system docker
|
||||||
|
usermod -aG docker yellowtent
|
||||||
|
|
||||||
|
exec su yellowtent --command "$@"
|
||||||
|
|
||||||
Reference in New Issue
Block a user