Chore: Run tests on docker (#25556)

Co-authored-by: Guilherme Gazzo <guilhermegazzo@gmail.com>
pull/25888/head
Diego Sampaio 4 years ago committed by GitHub
parent 391bb8cc20
commit eedc18b3d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 69
      .github/actions/build-docker-image-service/action.yml
  2. 85
      .github/actions/build-docker-image/action.yml
  3. 841
      .github/workflows/build_and_test.yml
  4. 2
      apps/meteor/.docker/Dockerfile.alpine
  5. 196
      apps/meteor/.scripts/start.js
  6. 8
      apps/meteor/app/api/server/v1/teams.ts
  7. 2
      apps/meteor/package.json
  8. 9
      apps/meteor/server/services/team/service.ts
  9. 3
      apps/meteor/tests/e2e/utils/configs/verifyTestBaseUrl.ts

@ -0,0 +1,69 @@
name: 'Build Micro Services Docker image'
description: 'Build Rocket.Chat Micro Services Docker images'
inputs:
docker-tag:
required: true
service:
required: true
username:
required: false
password:
required: false
outputs:
image-name:
value: ${{ steps.build-image.outputs.image-name }}
runs:
using: "composite"
steps:
# - shell: bash
# name: Free disk space
# run: |
# sudo swapoff -a
# sudo rm -f /swapfile
# sudo apt clean
# docker rmi $(docker image ls -aq)
# df -h
- shell: bash
id: build-image
run: |
LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]")
IMAGE_TAG="${{ inputs.docker-tag }}"
IMAGE_NAME="ghcr.io/${LOWERCASE_REPOSITORY}/${{ inputs.service }}-service:${IMAGE_TAG}"
echo "Building Docker image for service: ${{ inputs.service }}:${IMAGE_TAG}"
if [[ "${{ inputs.service }}" == "ddp-streamer" ]]; then
DOCKERFILE_PATH="./ee/apps/ddp-streamer/Dockerfile"
else
DOCKERFILE_PATH="./apps/meteor/ee/server/services/Dockerfile"
fi
docker build \
--build-arg SERVICE=${{ inputs.service }} \
-t ${IMAGE_NAME} \
-f ${DOCKERFILE_PATH} \
.
echo "::set-output name=image-name::${IMAGE_NAME}"
- name: Login to GitHub Container Registry
if: github.event.pull_request.head.repo.full_name == github.repository || github.ref == 'refs/heads/develop'
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ inputs.username }}
password: ${{ inputs.password }}
- name: Publish image
shell: bash
if: github.event.pull_request.head.repo.full_name == github.repository || github.ref == 'refs/heads/develop'
run: |
echo "Push Docker image: ${{ steps.build-image.outputs.image-name }}"
docker push ${{ steps.build-image.outputs.image-name }}

@ -0,0 +1,85 @@
name: 'Build Docker image'
description: 'Build Rocket.Chat Docker image'
inputs:
root-dir:
required: true
docker-tag:
required: true
release:
required: true
username:
required: false
password:
required: false
outputs:
image-name:
value: ${{ steps.build-image.outputs.image-name }}
runs:
using: composite
steps:
# - shell: bash
# name: Free disk space
# run: |
# sudo swapoff -a
# sudo rm -f /swapfile
# sudo apt clean
# docker rmi $(docker image ls -aq)
# df -h
- shell: bash
id: build-image
run: |
cd ${{ inputs.root-dir }}
LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]")
IMAGE_NAME="rocket.chat"
if [[ '${{ inputs.release }}' = 'preview' ]]; then
IMAGE_NAME="${IMAGE_NAME}.preview"
fi;
IMAGE_NAME="ghcr.io/${LOWERCASE_REPOSITORY}/${IMAGE_NAME}:${{ inputs.docker-tag }}"
if [[ '${{ inputs.release }}' = 'alpine' ]]; then
IMAGE_NAME="${IMAGE_NAME}.${{ inputs.release }}"
fi;
echo "Build Docker image ${IMAGE_NAME}"
DOCKER_PATH="${GITHUB_WORKSPACE}/apps/meteor/.docker"
if [[ '${{ inputs.release }}' = 'preview' ]]; then
DOCKER_PATH="${DOCKER_PATH}-mongo"
fi;
DOCKERFILE_PATH="${DOCKER_PATH}/Dockerfile"
if [[ '${{ inputs.release }}' = 'alpine' ]]; then
DOCKERFILE_PATH="${DOCKERFILE_PATH}.${{ inputs.release }}"
fi;
echo "Copy Dockerfile for release: ${{ inputs.release }}"
cp $DOCKERFILE_PATH ./Dockerfile
if [ -e ${DOCKER_PATH}/entrypoint.sh ]; then
cp ${DOCKER_PATH}/entrypoint.sh .
fi;
echo "Build ${{ inputs.release }} Docker image"
docker build -t $IMAGE_NAME .
echo "::set-output name=image-name::${IMAGE_NAME}"
- name: Login to GitHub Container Registry
if: github.event.pull_request.head.repo.full_name == github.repository && (github.event_name == 'release' || github.ref == 'refs/heads/develop')
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ inputs.username }}
password: ${{ inputs.password }}
- name: Publish image
shell: bash
if: github.event.pull_request.head.repo.full_name == github.repository && (github.event_name == 'release' || github.ref == 'refs/heads/develop')
run: |
echo "Push Docker image: ${{ steps.build-image.outputs.image-name }}"
docker push ${{ steps.build-image.outputs.image-name }}

File diff suppressed because it is too large Load Diff

@ -12,7 +12,7 @@ RUN set -x \
&& npm install --production \
# Start hack for sharp...
&& rm -rf npm/node_modules/sharp \
&& npm install sharp@0.29.3 \
&& npm install sharp@0.30.4 \
&& mv node_modules/sharp npm/node_modules/sharp \
# End hack for sharp
&& cd npm \

@ -1,196 +0,0 @@
#!/usr/bin/env node
const path = require('path');
const fs = require('fs');
const { spawn } = require('child_process');
const net = require('net');
const processes = [];
const baseDir = path.resolve(__dirname, '..');
const srcDir = path.resolve(baseDir);
const isPortTaken = (port) =>
new Promise((resolve, reject) => {
const tester = net
.createServer()
.once('error', (err) => (err.code === 'EADDRINUSE' ? resolve(true) : reject(err)))
.once('listening', () => tester.once('close', () => resolve(false)).close())
.listen(port);
});
const waitPortRelease = (port, count = 0) =>
new Promise((resolve, reject) => {
isPortTaken(port).then((taken) => {
if (!taken) {
return resolve();
}
if (count > 60) {
return reject();
}
console.log('Port', port, 'not released, waiting 1s...');
setTimeout(() => {
waitPortRelease(port, ++count)
.then(resolve)
.catch(reject);
}, 1000);
});
});
const appOptions = {
env: {
PORT: 3000,
ROOT_URL: 'http://localhost:3000',
},
};
let killingAllProcess = false;
function killAllProcesses(mainExitCode) {
if (killingAllProcess) {
return;
}
killingAllProcess = true;
processes.forEach((p) => {
console.log('Killing process', p.pid);
p.kill();
});
waitPortRelease(appOptions.env.PORT)
.then(() => {
console.log(`Port ${appOptions.env.PORT} was released, exiting with code ${mainExitCode}`);
process.exit(mainExitCode);
})
.catch((error) => {
console.error(`Error waiting port ${appOptions.env.PORT} to be released, exiting with code ${mainExitCode}`);
console.error(error);
process.exit(mainExitCode);
});
}
function startProcess(opts) {
console.log('Starting process', opts.name, opts.command, opts.params, opts.options.cwd);
const proc = spawn(opts.command, opts.params, opts.options);
processes.push(proc);
if (opts.onData) {
proc.stdout.on('data', opts.onData);
}
if (!opts.silent) {
proc.stdout.pipe(process.stdout);
proc.stderr.pipe(process.stderr);
}
if (opts.logFile) {
const logStream = fs.createWriteStream(opts.logFile, { flags: 'a' });
proc.stdout.pipe(logStream);
proc.stderr.pipe(logStream);
}
proc.on('exit', function (code, signal) {
processes.splice(processes.indexOf(proc), 1);
if (code != null) {
console.log(opts.name, `exited with code ${code}`);
} else {
console.log(opts.name, `exited with signal ${signal}`);
}
killAllProcesses(code);
});
}
function startRocketChat() {
return new Promise((resolve) => {
const waitServerRunning = (message) => {
if (message.toString().match('SERVER RUNNING')) {
return resolve();
}
};
startProcess({
name: 'Meteor App',
command: 'node',
params: ['/tmp/build-test/bundle/main.js'],
onData: waitServerRunning,
options: {
cwd: srcDir,
env: {
...appOptions.env,
...process.env,
},
},
});
});
}
async function startMicroservices() {
const waitStart = (resolve) => (message) => {
if (message.toString().match('NetworkBroker started successfully')) {
return resolve();
}
};
const startService = (name) => {
return new Promise((resolve) => {
const cwd =
name === 'ddp-streamer'
? path.resolve(srcDir, '..', '..', 'ee', 'apps', name, 'dist', 'ee', 'apps', name)
: path.resolve(srcDir, 'ee', 'server', 'services', 'dist', 'ee', 'server', 'services', name);
startProcess({
name: `${name} service`,
command: 'node',
params: [name === 'ddp-streamer' ? 'src/service.js' : 'service.js'],
onData: waitStart(resolve),
options: {
cwd,
env: {
...appOptions.env,
...process.env,
PORT: 4000,
},
},
});
});
};
await Promise.all([
startService('account'),
startService('authorization'),
startService('ddp-streamer'),
startService('presence'),
startService('stream-hub'),
]);
}
function startTests(options = []) {
const testOption = options.find((i) => i.startsWith('--test='));
const testParam = testOption ? testOption.replace('--test=', '') : 'test';
console.log(`Running test "npm run ${testParam}"`);
startProcess({
name: 'Tests',
command: 'npm',
params: ['run', testParam],
options: {
env: {
...process.env,
NODE_PATH: `${process.env.NODE_PATH + path.delimiter + srcDir + path.delimiter + srcDir}/node_modules`,
},
},
});
}
(async () => {
const [, , ...options] = process.argv;
await startRocketChat();
if (options.includes('--enterprise')) {
await startMicroservices();
}
startTests(options);
})();

@ -141,11 +141,9 @@ API.v1.addRoute(
});
}
await Promise.all([
Team.unsetTeamIdOfRooms(this.userId, team._id),
Team.removeAllMembersFromTeam(team._id),
Team.deleteById(team._id),
]);
await Promise.all([Team.unsetTeamIdOfRooms(this.userId, team._id), Team.removeAllMembersFromTeam(team._id)]);
await Team.deleteById(team._id);
return API.v1.success();
},

@ -31,9 +31,7 @@
"typecheck": "cross-env NODE_OPTIONS=\"--max-old-space-size=8184\" tsc --noEmit --skipLibCheck",
"deploy": "npm run build && pm2 startOrRestart pm2.json",
"coverage": "nyc -r html mocha --config ./.mocharc.js",
"testci": "node .scripts/start.js",
"test:playwright": "playwright test",
"test:playwright:ee": "cross-env ENTERPRISE=true yarn test:playwright",
"testapi": "mocha --config ./.mocharc.api.js",
"testunit": "npm run .testunit:definition && npm run .testunit:client && npm run .testunit:server",
".testunit:server": "mocha --config ./.mocharc.js",

@ -801,13 +801,10 @@ export class TeamService extends ServiceClassInternal implements ITeamService {
}
async removeAllMembersFromTeam(teamId: string): Promise<void> {
const team = await this.TeamModel.findOneById(teamId);
if (!team) {
return;
if (!teamId) {
throw new Error('missing-teamId');
}
await this.TeamMembersModel.deleteByTeamId(team._id);
await this.TeamMembersModel.deleteByTeamId(teamId);
}
async addMember(inviter: Pick<IUser, '_id' | 'username'>, userId: string, teamId: string): Promise<boolean> {

@ -2,9 +2,6 @@ const getBaseUrl = (): string => {
if (process.env.BASE_URL) {
return process.env.BASE_URL;
}
if (process.env.ENTERPRISE) {
return 'http://localhost:4000';
}
return 'http://localhost:3000';
};

Loading…
Cancel
Save