diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48c00fe..c275c57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,11 +18,6 @@ jobs: image: mongo:7 ports: - 27017:27017 - options: >- - --health-cmd "mongosh --eval 'db.adminCommand({ ping: 1 })'" - --health-interval 10s - --health-timeout 5s - --health-retries 5 env: MONGODB_URI: mongodb://127.0.0.1:27017/bloglist DEV_MONGODB_URI: mongodb://127.0.0.1:27017/bloglist-dev @@ -42,6 +37,17 @@ jobs: - name: Install dependencies run: npm ci + - name: Wait for MongoDB + run: | + for i in {1..30}; do + if node -e "const net=require('node:net'); const socket=net.createConnection(27017,'127.0.0.1'); socket.on('connect',()=>{socket.end();process.exit(0)}); socket.on('error',()=>process.exit(1));"; then + exit 0 + fi + sleep 2 + done + echo "MongoDB did not become ready in time" + exit 1 + - name: Lint run: npm run lint diff --git a/part4/bloglist/app.js b/part4/bloglist/app.js index e6863cb..f48de4d 100644 --- a/part4/bloglist/app.js +++ b/part4/bloglist/app.js @@ -1,10 +1,10 @@ const express = require("express"); -const mongoose = require("mongoose"); const cors = require("cors"); const path = require("path"); const config = require("./utils/config"); const logger = require("./utils/logger"); +const { connectToMongo } = require("./utils/mongo"); const middleware = require("./utils/middleware"); const blogsRouter = require("./controllers/blogs"); const usersRouter = require("./controllers/users"); @@ -12,18 +12,7 @@ const loginRouter = require("./controllers/login"); const testingRouter = require("./controllers/testing"); const app = express(); - -logger.info("connecting to", config.MONGODB_URI); - -mongoose - .connect(config.MONGODB_URI, { family: 4, serverSelectionTimeoutMS: 5000 }) - .then(() => { - logger.info("connected to MongoDB"); - }) - .catch((error) => { - logger.error("error connecting to MongoDB:", error.message); - process.exit(1); - }); +const mongoConnection = connectToMongo(); app.use(cors()); app.use(express.json()); @@ -50,4 +39,4 @@ app.get("/{*path}", (req, res) => { app.use(middleware.unknownEndpoint); app.use(middleware.errorHandler); -module.exports = app; +module.exports = { app, mongoConnection }; diff --git a/part4/bloglist/index.js b/part4/bloglist/index.js index 00946c8..e25c8b2 100644 --- a/part4/bloglist/index.js +++ b/part4/bloglist/index.js @@ -1,7 +1,14 @@ -const app = require("./app"); +const { app, mongoConnection } = require("./app"); const config = require("./utils/config"); const logger = require("./utils/logger"); -app.listen(config.PORT, () => { - logger.info(`Server running on port ${config.PORT}`); -}); +mongoConnection + .then(() => { + app.listen(config.PORT, () => { + logger.info(`Server running on port ${config.PORT}`); + }); + }) + .catch((error) => { + logger.error("error connecting to MongoDB:", error.message); + process.exit(1); + }); diff --git a/part4/bloglist/tests/blog_api.test.js b/part4/bloglist/tests/blog_api.test.js index 779993c..85427b8 100644 --- a/part4/bloglist/tests/blog_api.test.js +++ b/part4/bloglist/tests/blog_api.test.js @@ -1,10 +1,10 @@ -const { test, describe, after, beforeEach } = require("node:test"); +const { test, describe, before, after, beforeEach } = require("node:test"); const assert = require("node:assert"); const mongoose = require("mongoose"); const supertest = require("supertest"); const bcrypt = require("bcrypt"); -const app = require("../app"); +const { app, mongoConnection } = require("../app"); const Blog = require("../models/blog"); const User = require("../models/user"); const helper = require("./test_helper"); @@ -13,6 +13,10 @@ process.env.SECRET = process.env.SECRET || "testsecret"; const api = supertest(app); +before(async () => { + await mongoConnection; +}); + // Helpers const loginAndGetToken = async (username, password) => { const res = await api @@ -293,6 +297,7 @@ describe("DELETE /api/blogs/:id authorization", () => { }); after(async () => { + await mongoConnection.catch(() => null); await mongoose.connection.close(); }); diff --git a/part4/bloglist/tests/user_api.test.js b/part4/bloglist/tests/user_api.test.js index d7c93cb..6cd3153 100644 --- a/part4/bloglist/tests/user_api.test.js +++ b/part4/bloglist/tests/user_api.test.js @@ -1,15 +1,19 @@ -const { test, describe, beforeEach, after } = require("node:test"); +const { test, describe, before, beforeEach, after } = require("node:test"); const assert = require("node:assert"); const mongoose = require("mongoose"); const supertest = require("supertest"); const bcrypt = require("bcrypt"); -const app = require("../app"); +const { app, mongoConnection } = require("../app"); const User = require("../models/user"); const helper = require("./test_helper"); const api = supertest(app); +before(async () => { + await mongoConnection; +}); + describe("user creation", () => { beforeEach(async () => { await User.deleteMany({}); @@ -139,5 +143,6 @@ describe("users with blogs (4.17)", () => { }); after(async () => { + await mongoConnection.catch(() => null); await mongoose.connection.close(); }); diff --git a/part4/bloglist/utils/mongo.js b/part4/bloglist/utils/mongo.js new file mode 100644 index 0000000..eb7c3cb --- /dev/null +++ b/part4/bloglist/utils/mongo.js @@ -0,0 +1,26 @@ +const mongoose = require("mongoose"); + +const config = require("./config"); +const logger = require("./logger"); + +let mongoConnection = null; + +const connectToMongo = () => { + if (!mongoConnection) { + logger.info("connecting to", config.MONGODB_URI); + + mongoConnection = mongoose + .connect(config.MONGODB_URI, { + family: 4, + serverSelectionTimeoutMS: 5000, + }) + .then(() => { + logger.info("connected to MongoDB"); + return mongoose.connection; + }); + } + + return mongoConnection; +}; + +module.exports = { connectToMongo };