From f8a71f01c882198a6eaa5dedba2ccd02c2759785 Mon Sep 17 00:00:00 2001 From: Aditya Agarwal Date: Sun, 11 Feb 2024 22:36:31 +0530 Subject: [PATCH 1/4] Made the session optional for database with no replica set --- README.md | 9 ++++---- src/db.ts | 8 ++++++- src/utilities/checkDbUrl.ts | 31 +++++++++++++++++++++++++ tests/utilities/checkDbUrl.spec.ts | 37 ++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 src/utilities/checkDbUrl.ts create mode 100644 tests/utilities/checkDbUrl.spec.ts diff --git a/README.md b/README.md index 327fa7941a..200e9cffa8 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,10 @@ Core features include: -- [Talawa API](#talawa-api) - - [Talawa Components](#talawa-components) - - [Documentation](#documentation) - - [Installation](#installation) - - [Image Upload](#image-upload) +- [Talawa Components](#talawa-components) +- [Documentation](#documentation) +- [Installation](#installation) +- [Image Upload](#image-upload) diff --git a/src/db.ts b/src/db.ts index 82c17e6d7e..103500173f 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,6 +1,7 @@ import mongoose from "mongoose"; import { MONGO_DB_URL } from "./constants"; import { logger } from "./libraries"; +import { isAtlasUrl, isReplicaSetConnection } from "./utilities/checkDbUrl"; let session!: mongoose.ClientSession; @@ -12,7 +13,12 @@ export const connect = async (): Promise => { useFindAndModify: false, useNewUrlParser: true, }); - session = await mongoose.startSession(); + if ( + isAtlasUrl(MONGO_DB_URL as string) || + isReplicaSetConnection(MONGO_DB_URL as string) + ) { + session = await mongoose.startSession(); + } } catch (error: unknown) { if (error instanceof Error) { const errorMessage = error.toString(); diff --git a/src/utilities/checkDbUrl.ts b/src/utilities/checkDbUrl.ts new file mode 100644 index 0000000000..13bfff7429 --- /dev/null +++ b/src/utilities/checkDbUrl.ts @@ -0,0 +1,31 @@ +export const isReplicaSetConnection = (url: string): boolean => { + const replicaSetParam = getQueryParam(url, "replicaSet"); + + if (replicaSetParam !== null) { + return true; + } else { + const hostnames = extractHostnames(url); + return hostnames.length > 1; + } +}; + +const getQueryParam = (url: string, param: string): string | null => { + const match = url.match(new RegExp(`${param}=([^&]+)`)); + return match ? match[1] : null; +}; + +export const extractHostnames = (url: string): string[] => { + const matches = url.match(/\/\/([^/]+)/); + if (matches) { + return matches[1].split(","); + } + return []; +}; + +export const isAtlasUrl = (url: string): boolean => { + const urlWithoutProtocol = url.slice(url.indexOf("://") + 3); + const rest = urlWithoutProtocol.split("@")[1]; + const [hostname] = rest.split("/"); + + return hostname.endsWith(".mongodb.net"); +}; diff --git a/tests/utilities/checkDbUrl.spec.ts b/tests/utilities/checkDbUrl.spec.ts new file mode 100644 index 0000000000..19e3d29384 --- /dev/null +++ b/tests/utilities/checkDbUrl.spec.ts @@ -0,0 +1,37 @@ +import { expect, describe, it } from "vitest"; +import { + isReplicaSetConnection, + isAtlasUrl, +} from "../../src/utilities/checkDbUrl"; + +describe("testing isReplicaSet Connection for local database instance", () => { + it("should return true in case of replica set", async () => { + const url = + "mongodb://host1:port1,host2:port2,host3:port3/?replicaSet=myReplicaSet"; + const result = isReplicaSetConnection(url); + expect(result).toBe(true); + }); + + it("should return false in case of no replica set", async () => { + const url = "mongodb://localhost:27017/mydatabase"; + const result = isReplicaSetConnection(url); + expect(result).toBe(false); + }); +}); + +describe("testing isReplicaSet Connection for atlas url", () => { + it("should return true in case of atlas url", async () => { + const url = + "mongodb+srv://:@..mongodb.net/talawa-api"; + + const result = isAtlasUrl(url); + expect(result).toBe(true); + }); + + it("should return false in case of wrong atlas url", async () => { + const url = + "mongodb+srv://:@..mongodb/talawa-api"; + const result = isAtlasUrl(url); + expect(result).toBe(false); + }); +}); From 9e782a658809073b1fcd4559862f4c1b206d724c Mon Sep 17 00:00:00 2001 From: Aditya Agarwal Date: Sun, 18 Feb 2024 00:38:28 +0530 Subject: [PATCH 2/4] integrated hello command to check for replica set and removed previous changes --- INSTALLATION.md | 2 +- src/db.ts | 11 +++++---- src/utilities/checkDbUrl.ts | 31 ------------------------- tests/utilities/checkDbUrl.spec.ts | 37 ------------------------------ 4 files changed, 7 insertions(+), 74 deletions(-) delete mode 100644 src/utilities/checkDbUrl.ts delete mode 100644 tests/utilities/checkDbUrl.spec.ts diff --git a/INSTALLATION.md b/INSTALLATION.md index c2f0ed5284..4489bfa84c 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -41,7 +41,7 @@ This document provides instructions on how to set up and start a running instanc - [Setting up the RECAPTCHA_SECRET_KEY](#setting-up-the-recaptcha_secret_key) - [Setting up .env MAIL_USERNAME and MAIL_PASSWORD ReCAPTCHA Parameters](#setting-up-env-mail_username-and-mail_password-recaptcha-parameters) - [Setting up SMTP Email Variables in the .env File](#setting-up-smtp-email-variables-in-the-env-file) - - [Setting up Logger configurations _(optional)_](#setting-up-logger-configurations-_optional_) + - [Setting up Logger configurations](#setting-up-logger-configurations) - [Setting up COLORIZE_LOGS in .env file](#setting-up-colorize_logs-in-env-file) - [Setting up LOG_LEVEL in .env file](#setting-up-log_level-in-env-file) - [Importing Sample Database](#importing-sample-database) diff --git a/src/db.ts b/src/db.ts index 2b26fd5a62..b874df0aea 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,7 +1,6 @@ import mongoose from "mongoose"; import { MONGO_DB_URL } from "./constants"; import { logger } from "./libraries"; -import { isAtlasUrl, isReplicaSetConnection } from "./utilities/checkDbUrl"; let session!: mongoose.ClientSession; @@ -13,10 +12,12 @@ export const connect = async (): Promise => { useFindAndModify: false, useNewUrlParser: true, }); - if ( - isAtlasUrl(MONGO_DB_URL as string) || - isReplicaSetConnection(MONGO_DB_URL as string) - ) { + + const adminDb = mongoose.connection.db.admin(); + const result = await adminDb.command({ + hello: 1, + }); + if ("hosts" in result) { session = await mongoose.startSession(); } } catch (error: unknown) { diff --git a/src/utilities/checkDbUrl.ts b/src/utilities/checkDbUrl.ts deleted file mode 100644 index 13bfff7429..0000000000 --- a/src/utilities/checkDbUrl.ts +++ /dev/null @@ -1,31 +0,0 @@ -export const isReplicaSetConnection = (url: string): boolean => { - const replicaSetParam = getQueryParam(url, "replicaSet"); - - if (replicaSetParam !== null) { - return true; - } else { - const hostnames = extractHostnames(url); - return hostnames.length > 1; - } -}; - -const getQueryParam = (url: string, param: string): string | null => { - const match = url.match(new RegExp(`${param}=([^&]+)`)); - return match ? match[1] : null; -}; - -export const extractHostnames = (url: string): string[] => { - const matches = url.match(/\/\/([^/]+)/); - if (matches) { - return matches[1].split(","); - } - return []; -}; - -export const isAtlasUrl = (url: string): boolean => { - const urlWithoutProtocol = url.slice(url.indexOf("://") + 3); - const rest = urlWithoutProtocol.split("@")[1]; - const [hostname] = rest.split("/"); - - return hostname.endsWith(".mongodb.net"); -}; diff --git a/tests/utilities/checkDbUrl.spec.ts b/tests/utilities/checkDbUrl.spec.ts deleted file mode 100644 index 19e3d29384..0000000000 --- a/tests/utilities/checkDbUrl.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { expect, describe, it } from "vitest"; -import { - isReplicaSetConnection, - isAtlasUrl, -} from "../../src/utilities/checkDbUrl"; - -describe("testing isReplicaSet Connection for local database instance", () => { - it("should return true in case of replica set", async () => { - const url = - "mongodb://host1:port1,host2:port2,host3:port3/?replicaSet=myReplicaSet"; - const result = isReplicaSetConnection(url); - expect(result).toBe(true); - }); - - it("should return false in case of no replica set", async () => { - const url = "mongodb://localhost:27017/mydatabase"; - const result = isReplicaSetConnection(url); - expect(result).toBe(false); - }); -}); - -describe("testing isReplicaSet Connection for atlas url", () => { - it("should return true in case of atlas url", async () => { - const url = - "mongodb+srv://:@..mongodb.net/talawa-api"; - - const result = isAtlasUrl(url); - expect(result).toBe(true); - }); - - it("should return false in case of wrong atlas url", async () => { - const url = - "mongodb+srv://:@..mongodb/talawa-api"; - const result = isAtlasUrl(url); - expect(result).toBe(false); - }); -}); From 43340f6479c8bd4066ab20a02691d0d787418861 Mon Sep 17 00:00:00 2001 From: Aditya Agarwal Date: Mon, 19 Feb 2024 21:37:28 +0530 Subject: [PATCH 3/4] Added script to check replica set with logging and wrote test for it --- src/db.ts | 11 +++--- src/utilities/checkReplicaSet.ts | 20 +++++++++++ tests/utilities/checkReplicaSet.spec.ts | 48 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 src/utilities/checkReplicaSet.ts create mode 100644 tests/utilities/checkReplicaSet.spec.ts diff --git a/src/db.ts b/src/db.ts index b874df0aea..48f0437502 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,6 +1,7 @@ import mongoose from "mongoose"; import { MONGO_DB_URL } from "./constants"; import { logger } from "./libraries"; +import { checkReplicaSet } from "./utilities/checkReplicaSet"; let session!: mongoose.ClientSession; @@ -13,12 +14,12 @@ export const connect = async (): Promise => { useNewUrlParser: true, }); - const adminDb = mongoose.connection.db.admin(); - const result = await adminDb.command({ - hello: 1, - }); - if ("hosts" in result) { + const replicaSet = await checkReplicaSet(); + if (replicaSet) { + logger.info("Session started --> Connected to a replica set!"); session = await mongoose.startSession(); + } else { + logger.info("Session not started --> Not Connected to a replica set!"); } } catch (error: unknown) { if (error instanceof Error) { diff --git a/src/utilities/checkReplicaSet.ts b/src/utilities/checkReplicaSet.ts new file mode 100644 index 0000000000..0796d8ea79 --- /dev/null +++ b/src/utilities/checkReplicaSet.ts @@ -0,0 +1,20 @@ +import mongoose from "mongoose"; +import { logger } from "../libraries"; + +export const checkReplicaSet = async (): Promise => { + try { + const adminDb = mongoose.connection.db.admin(); + const result = await adminDb.command({ + hello: 1, + }); + + if ("hosts" in result) { + return true; + } else { + return false; + } + } catch (error) { + logger.error("Error checking replica set configuration :", error); + return false; + } +}; diff --git a/tests/utilities/checkReplicaSet.spec.ts b/tests/utilities/checkReplicaSet.spec.ts new file mode 100644 index 0000000000..be95405e7d --- /dev/null +++ b/tests/utilities/checkReplicaSet.spec.ts @@ -0,0 +1,48 @@ +import mongoose from "mongoose"; +import { checkReplicaSet } from "../../src/utilities/checkReplicaSet"; +import { expect, describe, it, beforeAll, afterAll } from "vitest"; +import { connect, disconnect } from "../helpers/db"; + +let MONGOOSE_INSTANCE: typeof mongoose; + +beforeAll(async (): Promise => { + MONGOOSE_INSTANCE = await connect(); +}); + +afterAll(async (): Promise => { + await disconnect(MONGOOSE_INSTANCE); +}); + +interface InterfaceAdminDbMock1 { + command: () => Promise<{ hosts: string[] }>; +} +interface InterfaceAdminDbMock2 { + command: () => Promise; +} + +describe("checkReplicaSet", () => { + it("should return true if replica set is configured", async () => { + const adminDbMock: InterfaceAdminDbMock1 = { + command: async (): Promise<{ hosts: string[] }> => ({ + hosts: ["host1", "host2"], + }), + }; + //@ts-expect-error cant find the right type + mongoose.connection.db.admin = (): object => adminDbMock; + const result = await checkReplicaSet(); + + expect(result).toBe(true); + }); + + it("should return false if replica set is not configured", async () => { + const adminDbMock: InterfaceAdminDbMock2 = { + command: async (): Promise => ({}), + }; + //@ts-expect-error cant find the right type + mongoose.connection.db.admin = (): object => adminDbMock; + + const result = await checkReplicaSet(); + + expect(result).toBe(false); + }); +}); From 7beebce1887ccd345a1015ae58a82c5174b1ecac Mon Sep 17 00:00:00 2001 From: Aditya Agarwal Date: Fri, 23 Feb 2024 00:17:34 +0530 Subject: [PATCH 4/4] Added additional check for setName property and updated the test --- src/utilities/checkReplicaSet.ts | 2 +- tests/utilities/checkReplicaSet.spec.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utilities/checkReplicaSet.ts b/src/utilities/checkReplicaSet.ts index 0796d8ea79..56f75deba8 100644 --- a/src/utilities/checkReplicaSet.ts +++ b/src/utilities/checkReplicaSet.ts @@ -8,7 +8,7 @@ export const checkReplicaSet = async (): Promise => { hello: 1, }); - if ("hosts" in result) { + if ("hosts" in result && "setName" in result) { return true; } else { return false; diff --git a/tests/utilities/checkReplicaSet.spec.ts b/tests/utilities/checkReplicaSet.spec.ts index be95405e7d..1aa439fd87 100644 --- a/tests/utilities/checkReplicaSet.spec.ts +++ b/tests/utilities/checkReplicaSet.spec.ts @@ -14,7 +14,7 @@ afterAll(async (): Promise => { }); interface InterfaceAdminDbMock1 { - command: () => Promise<{ hosts: string[] }>; + command: () => Promise<{ hosts: string[]; setName: string }>; } interface InterfaceAdminDbMock2 { command: () => Promise; @@ -23,8 +23,9 @@ interface InterfaceAdminDbMock2 { describe("checkReplicaSet", () => { it("should return true if replica set is configured", async () => { const adminDbMock: InterfaceAdminDbMock1 = { - command: async (): Promise<{ hosts: string[] }> => ({ + command: async (): Promise<{ hosts: string[]; setName: string }> => ({ hosts: ["host1", "host2"], + setName: "xyz", }), }; //@ts-expect-error cant find the right type @@ -40,7 +41,6 @@ describe("checkReplicaSet", () => { }; //@ts-expect-error cant find the right type mongoose.connection.db.admin = (): object => adminDbMock; - const result = await checkReplicaSet(); expect(result).toBe(false);