diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..43d51c6 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,11 @@ +{ + "env": { + "node": true + }, + "extends": [ + "@supercharge" + ], + "parserOptions": { + "ecmaVersion": 2018 + } +} diff --git a/.github/workflows/actions_release.yml b/.github/workflows/actions_release.yml new file mode 100644 index 0000000..6082ace --- /dev/null +++ b/.github/workflows/actions_release.yml @@ -0,0 +1,21 @@ +name: Release GitHub Actions + +on: + workflow_dispatch: + inputs: + tag: + description: "Tag for the release" + required: true + +permissions: + contents: read + +jobs: + release: + permissions: + actions: read + id-token: write + contents: write + uses: step-security/reusable-workflows/.github/workflows/actions_release.yaml@v1 + with: + tag: "${{ github.event.inputs.tag }}" \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..6d039fe --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,21 @@ +name: Start MongoDB Server + +on: [push, pull_request] + +jobs: + mongodb-action: + name: Start MongoDB Server v${{ matrix.mongodb-version }} + + runs-on: ubuntu-latest + strategy: + matrix: + mongodb-version: ['4.0', '4.2', '4.4', '5.0', '6.0'] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Start MongoDB Server + uses: ./ + with: + mongodb-version: ${{ matrix.mongodb-version }} diff --git a/.github/workflows/test-auth.yml b/.github/workflows/test-auth.yml new file mode 100644 index 0000000..2423c28 --- /dev/null +++ b/.github/workflows/test-auth.yml @@ -0,0 +1,44 @@ +name: Single Instance With Auth + +on: [push, pull_request] + +jobs: + single-instance-with-auth: + name: Mongo v${{ matrix.mongodb-version }} - Node v${{ matrix.node-version }} + + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18, 20] + mongodb-version: ['4.4', '5.0', '6.0'] + mongodb-db: ['ci'] + mongodb-username: ['ci'] + mongodb-password: ['ci'] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Start MongoDB Server v${{ matrix.mongodb-version }} + uses: ./ + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-db: ${{ matrix.mongodb-db }} + mongodb-username: ${{ matrix.mongodb-username }} + mongodb-password: ${{ matrix.mongodb-password }} + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test ./test/single-instance + env: + CI: true + MONGODB_DB: ${{ matrix.mongodb-db }} + MONGODB_USERNAME: ${{ matrix.mongodb-username }} + MONGODB_PASSWORD: ${{ matrix.mongodb-password }} diff --git a/.github/workflows/test-replica-set.yml b/.github/workflows/test-replica-set.yml new file mode 100644 index 0000000..87c6c35 --- /dev/null +++ b/.github/workflows/test-replica-set.yml @@ -0,0 +1,72 @@ +name: Replica Set Tests + +on: [push, pull_request] + +jobs: + single-node-replica-set-on-default-port: + name: MongoDB v${{ matrix.mongodb-version }} RS — Node.js v${{ matrix.node-version }} + + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18, 20] + mongodb-version: ['4.4', '5.0', '6.0'] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Start MongoDB Server v${{ matrix.mongodb-version }} + uses: ./ + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-replica-set: mongodb-test-rs + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test ./test/replica-set + env: + CI: true + MONGODB_REPLICA_SET: mongodb-test-rs + + single-node-replica-set-on-custom-port: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18, 20] + mongodb-port: [23456] + mongodb-version: ['4.4', '5.0', '6.0'] + + name: MongoDB v${{ matrix.mongodb-version }} RS, Port ${{ matrix.mongodb-port }} — Node.js v${{ matrix.node-version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Start MongoDB Server v${{ matrix.mongodb-version }} + uses: ./ + with: + mongodb-port: ${{ matrix.mongodb-port }} + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-replica-set: mongodb-test-rs + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test ./test/replica-set + env: + CI: true + MONGODB_PORT: ${{ matrix.mongodb-port }} + MONGODB_REPLICA_SET: mongodb-test-rs diff --git a/.github/workflows/test-single-instance.yml b/.github/workflows/test-single-instance.yml new file mode 100644 index 0000000..56adff3 --- /dev/null +++ b/.github/workflows/test-single-instance.yml @@ -0,0 +1,69 @@ +name: Single Instance Tests + +on: [push, pull_request] + +jobs: + single-instance-on-default-port: + name: MongoDB v${{ matrix.mongodb-version }} — Node.js v${{ matrix.node-version }} + + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18, 20] + mongodb-version: ['4.4', '5.0', '6.0'] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Start MongoDB Server v${{ matrix.mongodb-version }} + uses: ./ + with: + mongodb-version: ${{ matrix.mongodb-version }} + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test ./test/single-instance + env: + CI: true + MONGODB_DB: ${{ matrix.mongodb-db }} + + + single-instance-on-custom-port: + runs-on: ubuntu-latest + strategy: + matrix: + mongodb-port: [12345] + mongodb-version: ['4.4', '5.0', '6.0'] + node-version: [18, 20] + + name: MongoDB v${{ matrix.mongodb-version }}, Port ${{ matrix.mongodb-port }} — Node.js v${{ matrix.node-version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Start MongoDB Server v${{ matrix.mongodb-version }} + uses: ./ + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-port: ${{ matrix.mongodb-port }} + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test ./test/custom-port + env: + CI: true diff --git a/.github/workflows/validate-action-typings.yml b/.github/workflows/validate-action-typings.yml new file mode 100644 index 0000000..c984f93 --- /dev/null +++ b/.github/workflows/validate-action-typings.yml @@ -0,0 +1,14 @@ +name: Validate action typings + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + validate-typings: + runs-on: "ubuntu-latest" + steps: + - uses: actions/checkout@v4 + - uses: krzema12/github-actions-typing@v1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e5386f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +haters + +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +.github-todos + +pids +results + +node_modules +npm-debug.log +package-lock.json + +# code coverage folder +coverage +.nyc_output + +# Secrets +.env +.env.** + +# IDEs and editors +.idea +.vscode + +.vagrant diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6ec69d1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM docker:stable +COPY start-mongodb.sh /start-mongodb.sh +RUN chmod +x /start-mongodb.sh +ENTRYPOINT ["/start-mongodb.sh"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..45153da --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2023 StepSecurity +Copyright (c) 2019 The Supercharge Node.js Framework + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index c7a1b5e..40bbad4 100644 --- a/README.md +++ b/README.md @@ -1 +1,222 @@ -# mongodb-github-action \ No newline at end of file + +## Introduction +This GitHub Action starts a MongoDB server or MongoDB replica set. By default, the MongoDB server is available on the default port `27017`. You can configure a custom port using the `mongodb-port` input. The examples show how to use a custom port. + +The MongoDB version must be specified using the `mongodb-version` input. The used version must exist in the published [`mongo` Docker hub tags](https://hub.docker.com/_/mongo?tab=tags). Default value is `latest`, other popular choices are `6.0`, `7.0` or even release candidates `8.0.0-rc4`. + +This is useful when running tests against a MongoDB database. + + +## Usage +A code example says more than a 1000 words. Here’s an exemplary GitHub Action using a MongoDB server in different versions to test a Node.js app: + +```yaml +name: Run tests + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x, 22.x] + mongodb-version: ['6.0', '7.0', '8.0'] + + steps: + - name: Git checkout + uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Start MongoDB + uses: step-security/mongodb-github-action@1.11.0 + with: + mongodb-version: ${{ matrix.mongodb-version }} + + - run: npm install + + - run: npm test + env: + CI: true +``` + + +### Using a Custom MongoDB Port +You can start the MongoDB instance on a custom port. Use the `mongodb-port: 12345` input to configure port `12345` for MongoDB. Replace `12345` with the port you want to use in your test runs. + +The following example starts a MongoDB server on port `42069`: + +```yaml +name: Run tests + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x, 22.x] + mongodb-version: ['6.0', '7.0', '8.0'] + + steps: + - name: Git checkout + uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Start MongoDB + uses: step-security/mongodb-github-action@1.11.0 + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-replica-set: test-rs + mongodb-port: 42069 + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test + env: + CI: true +``` + + +### With a Replica Set (MongoDB `--replSet` Flag) +You can run your tests against a MongoDB replica set by adding the `mongodb-replica-set: your-replicate-set-name` input in your action’s workflow. The value for `mongodb-replica-set` defines the name of your replica set. Replace `your-replicate-set-name` with the replica set name you want to use in your tests. + +The following example uses the replica set name `test-rs`: + +```yaml +name: Run tests + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x, 22.x] + mongodb-version: ['6.0', '7.0', '8.0'] + + steps: + - name: Git checkout + uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Start MongoDB + uses: step-security/mongodb-github-action@1.11.0 + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-replica-set: test-rs + mongodb-port: 42069 + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test + env: + CI: true +``` + + +### With Authentication (MongoDB `--auth` Flag) +Setting the `mongodb-username` and `mongodb-password` inputs. As per the [Dockerhub documentation](https://hub.docker.com/_/mongo), this automatically creates an admin user and enables `--auth` mode. + +The following example uses the username `supercharge`, password `secret` and also sets an initial `supercharge` database: + +```yaml +name: Run tests with authentication + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x, 22.x] + mongodb-version: ['6.0', '7.0', '8.0'] + + steps: + - name: Git checkout + uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Start MongoDB + uses: step-security/mongodb-github-action@1.11.0 + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-username: supercharge + mongodb-password: secret + mongodb-db: supercharge + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test + env: + CI: true +``` + +### With Custom Container Name +The container name of the created MongoDB instance can be configured using the `mongodb-container-name` input + +The following example will parameterize the MongoDB container name based on the `node-version` and `mongodb-version` being used from the matrix: + +```yaml +name: Run with Custom Container Names + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x, 22.x] + mongodb-version: ['6.0', '7.0', '8.0'] + + steps: + - name: Git checkout + uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Start MongoDB + uses: step-security/mongodb-github-action@1.11.0 + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-container-name: mongodb-${{ matrix.node-version }}-${{ matrix.mongodb-version }} + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test + env: + CI: true +``` + +**Caveat:** due to [this issue](https://github.com/docker-library/mongo/issues/211), you **cannot enable user creation AND replica sets** initially. Therefore, if you use this action to setup a replica set, please create your users through a separate script. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..77568b2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +Please report security vulnerabilities to security@stepsecurity.io diff --git a/action-types.yml b/action-types.yml new file mode 100644 index 0000000..467fe41 --- /dev/null +++ b/action-types.yml @@ -0,0 +1,16 @@ +# See https://github.com/krzema12/github-actions-typing +inputs: + mongodb-version: + type: string + mongodb-replica-set: + type: string + mongodb-port: + type: integer + mongodb-db: + type: string + mongodb-username: + type: string + mongodb-password: + type: string + mongodb-container-name: + type: string diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..170e6a9 --- /dev/null +++ b/action.yml @@ -0,0 +1,54 @@ +name: 'MongoDB in GitHub Actions' +description: 'Start a MongoDB server (on default port 27017 or a custom port)' + +branding: + icon: 'database' + color: 'green' + +inputs: + mongodb-version: + description: 'MongoDB version to use (default "latest")' + required: false + default: 'latest' + + mongodb-replica-set: + description: 'MongoDB replica set name (no replica set by default)' + required: false + default: '' + + mongodb-port: + description: 'MongoDB port to use (default 27017)' + required: false + default: 27017 + + mongodb-db: + description: 'MongoDB db to create (default: none)' + required: false + default: '' + + mongodb-username: + description: 'MongoDB root username (default: none)' + required: false + default: '' + + mongodb-password: + description: 'MongoDB root password (default: none)' + required: false + default: '' + + mongodb-container-name: + description: 'MongoDB container name (default: "mongodb")' + required: false + default: 'mongodb' + +runs: + using: 'docker' + image: 'Dockerfile' + args: + - ${{ inputs.mongodb-version }} + - ${{ inputs.mongodb-replica-set }} + - ${{ inputs.mongodb-port }} + - ${{ inputs.mongodb-db }} + - ${{ inputs.mongodb-username }} + - ${{ inputs.mongodb-password }} + - ${{ inputs.mongodb-container-name }} diff --git a/package.json b/package.json new file mode 100644 index 0000000..437b997 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "@step-security/mongodb-github-action", + "description": "MongoDB GitHub Action", + "version": "1.10.0", + "bugs": { + "url": "https://github.com/step-security/mongodb-github-action/issues" + }, + "devDependencies": { + "@supercharge/eslint-config": "~3.0.1", + "c8": "~9.1.0", + "eslint": "~8.57.0", + "expect": "~29.7.0", + "mongoose": "~8.4.0", + "uvu": "~0.5.6" + }, + "engines": { + "node": ">=8" + }, + "homepage": "https://github.com/step-security/mongodb-github-action", + "keywords": [ + "github", + "github-action" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/step-security/mongodb-github-action.git" + }, + "scripts": { + "lint": "eslint test --ext .js", + "test": "c8 --include=dist uvu --ignore fixtures", + "posttest": "c8 report --reporter=html" + } +} diff --git a/start-mongodb.sh b/start-mongodb.sh new file mode 100644 index 0000000..311e63c --- /dev/null +++ b/start-mongodb.sh @@ -0,0 +1,152 @@ +#!/bin/sh + +# Map input values from the GitHub Actions workflow to shell variables +MONGODB_VERSION=$1 +MONGODB_REPLICA_SET=$2 +MONGODB_PORT=$3 +MONGODB_DB=$4 +MONGODB_USERNAME=$5 +MONGODB_PASSWORD=$6 +MONGODB_CONTAINER_NAME=$7 + +# validate subscription status +API_URL="https://agent.api.stepsecurity.io/v1/github/$GITHUB_REPOSITORY/actions/subscription" + +# Set a timeout for the curl command (3 seconds) +RESPONSE=$(curl --max-time 3 -s -w "%{http_code}" "$API_URL" -o /dev/null) || true +CURL_EXIT_CODE=${?} + +# Check if the response code is not 200 +if [ $CURL_EXIT_CODE -ne 0 ] || [ "$RESPONSE" != "200" ]; then + if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "000" ] || [ $CURL_EXIT_CODE -ne 0 ]; then + echo "Timeout or API not reachable. Continuing to next step." + else + echo "Subscription is not valid. Reach out to support@stepsecurity.io" + exit 1 + fi +fi + +# `mongosh` is used starting from MongoDB 5.x +MONGODB_CLIENT="mongosh --quiet" + + +if [ -z "$MONGODB_VERSION" ]; then + echo "" + echo "Missing MongoDB version in the [mongodb-version] input. Received value: $MONGODB_VERSION" + echo "" + + exit 2 +fi + + +echo "::group::Selecting correct MongoDB client" +if [ "`echo $MONGODB_VERSION | cut -c 1`" -le "4" ]; then + MONGODB_CLIENT="mongo" +fi +echo " - Using MongoDB client: [$MONGODB_CLIENT]" +echo "" +echo "::endgroup::" + + +# Helper function to wait for MongoDB to be started before moving on +wait_for_mongodb () { + echo "::group::Waiting for MongoDB to accept connections" + sleep 1 + TIMER=0 + + MONGODB_ARGS="" + + if [ -z "$MONGODB_REPLICA_SET" ] + then + if [ -z "$MONGODB_USERNAME" ] + then + MONGODB_ARGS="" + else + # no replica set, but username given: use them as args + MONGODB_ARGS="--username $MONGODB_USERNAME --password $MONGODB_PASSWORD" + fi + fi + + # until ${WAIT_FOR_MONGODB_COMMAND} + until docker exec --tty $MONGODB_CONTAINER_NAME $MONGODB_CLIENT --port $MONGODB_PORT $MONGODB_ARGS --eval "db.serverStatus()" + do + echo "." + sleep 1 + TIMER=$((TIMER + 1)) + + if [[ $TIMER -eq 20 ]]; then + echo "MongoDB did not initialize within 20 seconds. Exiting." + exit 2 + fi + done + echo "::endgroup::" +} + + +# check if the container already exists and remove it +## TODO: put this behind an option flag +# if [ "$(docker ps -q -f name=$MONGODB_CONTAINER_NAME)" ]; then +# echo "Removing existing container [$MONGODB_CONTAINER_NAME]" +# docker rm -f $MONGODB_CONTAINER_NAME +# fi + + +if [ -z "$MONGODB_REPLICA_SET" ]; then + echo "::group::Starting single-node instance, no replica set" + echo " - port [$MONGODB_PORT]" + echo " - version [$MONGODB_VERSION]" + echo " - database [$MONGODB_DB]" + echo " - credentials [$MONGODB_USERNAME:$MONGODB_PASSWORD]" + echo " - container-name [$MONGODB_CONTAINER_NAME]" + echo "" + + docker run --name $MONGODB_CONTAINER_NAME --publish $MONGODB_PORT:$MONGODB_PORT -e MONGO_INITDB_DATABASE=$MONGODB_DB -e MONGO_INITDB_ROOT_USERNAME=$MONGODB_USERNAME -e MONGO_INITDB_ROOT_PASSWORD=$MONGODB_PASSWORD --detach mongo:$MONGODB_VERSION --port $MONGODB_PORT + + if [ $? -ne 0 ]; then + echo "Error starting MongoDB Docker container" + exit 2 + fi + echo "::endgroup::" + + wait_for_mongodb + + exit 0 +fi + + +echo "::group::Starting MongoDB as single-node replica set" +echo " - port [$MONGODB_PORT]" +echo " - version [$MONGODB_VERSION]" +echo " - replica set [$MONGODB_REPLICA_SET]" +echo "" + + +docker run --name $MONGODB_CONTAINER_NAME --publish $MONGODB_PORT:$MONGODB_PORT --detach mongo:$MONGODB_VERSION --port $MONGODB_PORT --replSet $MONGODB_REPLICA_SET + +if [ $? -ne 0 ]; then + echo "Error starting MongoDB Docker container" + exit 2 +fi +echo "::endgroup::" + +wait_for_mongodb + +echo "::group::Initiating replica set [$MONGODB_REPLICA_SET]" + +docker exec --tty $MONGODB_CONTAINER_NAME $MONGODB_CLIENT --port $MONGODB_PORT --eval " + rs.initiate({ + \"_id\": \"$MONGODB_REPLICA_SET\", + \"members\": [ { + \"_id\": 0, + \"host\": \"localhost:$MONGODB_PORT\" + } ] + }) +" + +echo "Success! Initiated replica set [$MONGODB_REPLICA_SET]" +echo "::endgroup::" + + +echo "::group::Checking replica set status [$MONGODB_REPLICA_SET]" +docker exec --tty $MONGODB_CONTAINER_NAME $MONGODB_CLIENT --port $MONGODB_PORT --eval "rs.status()" +echo "::endgroup::" diff --git a/test/custom-port/custom-port.js b/test/custom-port/custom-port.js new file mode 100644 index 0000000..0872acd --- /dev/null +++ b/test/custom-port/custom-port.js @@ -0,0 +1,11 @@ +'use strict' + +const { test } = require('uvu') +const Mongoose = require('mongoose') + +test('connects to MongoDB on custom port 12345', async () => { + const connection = await Mongoose.createConnection('mongodb://localhost:12345') + await connection.close() +}) + +test.run() diff --git a/test/replica-set/replica-set.js b/test/replica-set/replica-set.js new file mode 100644 index 0000000..60d8dd8 --- /dev/null +++ b/test/replica-set/replica-set.js @@ -0,0 +1,64 @@ +'use strict' + +const { test } = require('uvu') +const { expect } = require('expect') +const Mongoose = require('mongoose') + +const { MONGODB_PORT = 27017, MONGODB_REPLICA_SET = 'mongodb-test-rs' } = process.env + +test.before(async () => { + const connectionString = `mongodb://localhost:${MONGODB_PORT}/test?replicaSet=${MONGODB_REPLICA_SET}` + + console.log('---------------------------------------------------------------------') + console.log('connecting to MongoDB using connection string -> ' + connectionString) + console.log('---------------------------------------------------------------------') + + await Mongoose.connect(connectionString, { + serverSelectionTimeoutMS: 1500 + }) +}) + +test.after(async () => { + await Mongoose.connection.db.dropDatabase() + await Mongoose.disconnect() +}) + +test('queries the replica set status', async () => { + const db = Mongoose.connection.db.admin() + const { ok, set } = await db.command({ replSetGetStatus: 1 }) + + expect(ok).toBe(1) + expect(set).toEqual(MONGODB_REPLICA_SET) +}) + +test('saves a document', async () => { + const Dog = Mongoose.model('Dog', { name: String }) + const albert = await new Dog({ name: 'Albert' }).save() + expect(albert.name).toEqual('Albert') +}) + +test('uses transactions', async () => { + const Customer = Mongoose.model('Customer', new Mongoose.Schema({ name: String })) + await Customer.createCollection() + + const session = await Mongoose.startSession() + session.startTransaction() + + await Customer.create([{ name: 'test-customer' }], { session }) + + expect( + await Customer.findOne({ name: 'test-customer' }) + ).toBeNull() + + expect( + await Customer.findOne({ name: 'test-customer' }).session(session) + ).not.toBeNull() + + await session.commitTransaction() + + expect( + await Customer.findOne({ name: 'test-customer' }) + ).not.toBeNull() +}) + +test.run() diff --git a/test/single-instance/single-instance.js b/test/single-instance/single-instance.js new file mode 100644 index 0000000..430c66c --- /dev/null +++ b/test/single-instance/single-instance.js @@ -0,0 +1,29 @@ +'use strict' + +const { test } = require('uvu') +const { expect } = require('expect') +const Mongoose = require('mongoose') + +const { MONGODB_USERNAME, MONGODB_PASSWORD, MONGODB_DB } = process.env + +test('connects to MongoDB', async () => { + const connection = await Mongoose.createConnection('mongodb://localhost', { + user: MONGODB_USERNAME, + pass: MONGODB_PASSWORD, + dbName: MONGODB_DB, + authSource: MONGODB_USERNAME && MONGODB_PASSWORD ? 'admin' : undefined + }) + + await connection.close() +}) + +test('fails to connect to non-existent MongoDB instance', async () => { + await expect( + Mongoose.connect('mongodb://localhost:27018', { + connectTimeoutMS: 1000, + serverSelectionTimeoutMS: 1000 + }) + ).rejects.toThrow() +}) + +test.run()