Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mongodb setup bug + tests #2257

Merged
merged 16 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,17 @@ export async function superAdmin(): Promise<void> {

// Get the mongodb url
/**
* The `mongoDB` function connects to a MongoDB database by asking for a URL, checking the connection,
* and updating the environment variable with the URL.
* The `mongoDB` function manages the connection to a MongoDB database.
* It performs the following steps:
* 1. Checks if there is an existing MongoDB URL in the environment variables.
* 2. If an existing URL is found, it attempts to establish a connection to the URL.
* - If the connection is successful, it returns the URL.
* - If the connection fails, it returns null.
* 3. If a URL is returned from the previous step (i.e., a successful connection was made), it prompts the user to either keep the existing URL or change it.
* 4. If null is returned from the previous step (i.e., no successful connection was made), it prompts the user to enter a new MongoDB URL.
* 5. It then enters a loop where it continues to prompt the user for a MongoDB URL until a successful connection can be made.
* 6. Once a successful connection is made, it saves the MongoDB URL to the environment variables.
* This function is part of the initial setup process and is designed to ensure a valid MongoDB connection before proceeding.
*/
export async function mongoDB(): Promise<void> {
let DB_URL = process.env.MONGO_DB_URL;
Expand Down
61 changes: 33 additions & 28 deletions src/setup/MongoDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,45 @@ import inquirer from "inquirer";
import { MongoClient } from "mongodb";

/**
* Function to check if Existing MongoDB instance is running
* The function `checkExistingMongoDB` checks for an existing MongoDB connection by iterating through a
* list of URLs and testing the connection using the `checkConnection` function.
* @returns The function `checkExistingMongoDB` returns a promise that resolves to a string or null.
* The `checkExistingMongoDB` function checks for an existing MongoDB URL in the environment variables and attempts to establish a connection.
*
* It performs the following steps:
* 1. Retrieves the MongoDB URL from the environment variables.
* 2. If no URL is found, it immediately returns null.
* 3. If a URL is found, it attempts to establish a connection using the `checkConnection` function.
* - If the connection is successful (i.e., `checkConnection` returns true), it returns the URL.
* - If the connection fails (i.e., `checkConnection` returns false), it returns null.
*
* This function is used during the initial setup process to check if a valid MongoDB connection can be made with the existing URL in the environment variables.
* @returns A promise that resolves to a string (if a connection could be made to the existing URL) or null (if no existing URL or connection could not be made).
*/
export async function checkExistingMongoDB(): Promise<string | null> {
const existingMongoDbUrls = [
process.env.MONGO_DB_URL,
"mongodb://localhost:27017",
];
const existingMongoDbUrls = process.env.MONGO_DB_URL;

for (const url of existingMongoDbUrls) {
if (!url) {
continue;
}

const isConnected = await checkConnection(url);
if (isConnected) {
return url;
}
if (!existingMongoDbUrls) {
return null;
}

return null;
const isConnected = await checkConnection(existingMongoDbUrls);
if (isConnected) {
return existingMongoDbUrls;
} else return null;
}

// Check the connection to MongoDB with the specified URL.
/**
* The function `checkConnection` is an asynchronous function that checks the connection to a MongoDB
* database using the provided URL and returns a boolean value indicating whether the connection was
* successful or not.
* @param url - The `url` parameter is a string that represents the connection URL for the
* MongoDB server. It typically includes the protocol (e.g., `mongodb://`), the host and port
* information, and any authentication credentials if required.
* @returns a Promise that resolves to a boolean value. The boolean value indicates whether the
* connection to the MongoDB server was successful (true) or not (false).
* The `checkConnection` function attempts to establish a connection to a MongoDB instance using a provided URL.
*
* @param url - The MongoDB connection URL.
* @returns A promise that resolves to a boolean indicating whether the connection was successful (true) or not (false).
*
* It performs the following steps:
* 1. Tries to establish a connection to the MongoDB instance using the provided URL with a server selection timeout of 1000 milliseconds.
* 2. If the connection is successful, it closes the connection and returns true.
* 3. If the connection fails, it logs an error message and returns false.
* - If the error is an instance of the Error class, it logs the error message.
* - If the error is not an instance of the Error class, it logs a generic error message and the error itself.
*
* This function is used during the initial setup process to test the MongoDB connection.
*/
export async function checkConnection(url: string): Promise<boolean> {
console.log("\nChecking MongoDB connection....");
Expand All @@ -54,6 +58,7 @@ export async function checkConnection(url: string): Promise<boolean> {
);
} else {
console.log(`\nConnection to MongoDB failed. Please try again.\n`);
console.log(error);
}
return false;
}
Expand All @@ -71,7 +76,7 @@ export async function askForMongoDBUrl(): Promise<string> {
type: "input",
name: "url",
message: "Enter your MongoDB URL:",
default: process.env.MONGO_DB_URL,
default: "mongodb://localhost:27017",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. What happens if the parameter is already defined and it's not localhost or port 27017? Will the application break?
  2. Can a ternary be used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have already defined then it's going to show us
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but if another url is set in our env, it won't show that, it'll always show "mongodb://localhost:27017"
the line should be this default: process.env.MONGO_DB_URL ?? "mongodb://localhost:27017"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check the screenshot in previous comment, it's showing different. The port is different from default.

default means - when we have Yes/No type, do you see one of them marked automatically and u press enter?

Copy link
Contributor

@meetulr meetulr Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the screenshot is for a log, this one. The check that you modified is different, this one

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You said it doesn't show from env. That url is from env itself, check the port. It's different port from default

Copy link
Contributor

@meetulr meetulr Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what? we're talking about the line that Peter commented on, you've hard coded mongodb://localhost:27017 there, so when that function runs, it'll always show mongodb://localhost:27017 for that prompt.

You said it doesn't show from env. That url is from env itself, check the port. It's different port from default

the screenshot you've provided is just for a log link, it will show what's in the .env. The prompt you've modified is different, with its default value hard-coded, that's what we mean here.

},
]);

Expand Down
62 changes: 60 additions & 2 deletions tests/setup/checkExistingMongoDB.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,66 @@
import { expect, it, describe } from "vitest";
import { checkExistingMongoDB } from "../../src/setup/MongoDB";
import { expect, it, describe, vi, afterEach } from "vitest";
import { checkConnection, checkExistingMongoDB } from "../../src/setup/MongoDB";
import { MongoClient } from "mongodb";

describe("Setup -> checkExistingMongoDB", () => {
afterEach(() => {
// Clear all mocks after each test
vi.restoreAllMocks();
});
it("should return the first valid URL when a connection is found", async () => {
const result = await checkExistingMongoDB();
expect(result).toBe(process.env.MONGO_DB_URL);
});

it("should return null if MONGO_DB_URL is not set", async () => {
process.env.MONGO_DB_URL = "";
const result = await checkExistingMongoDB();
expect(result).toBeNull();
});

it("should return null if checkConnection returns false", async () => {
// Set the environment variable
process.env.MONGO_DB_URL = "mongodb://testUrl";

// Spy on the checkConnection function to return false
vi.spyOn(MongoClient, "connect").mockImplementation(() => {
throw new Error("Test error");
});

// Call the function
const result = await checkExistingMongoDB();

// Check that the result is null
expect(result).toBeNull();
});

it("should return false and log error when connection fails", async () => {
// Spy on the MongoClient.connect function to throw an error
vi.spyOn(MongoClient, "connect").mockImplementation(() => {
throw new Error("Test error");
});

// Call the function with a test URL
const result = await checkConnection("mongodb://testUrl");

// Check that the result is false
expect(result).toBe(false);
});

it("should return false and log error when connection fails with unknown error type", async () => {
// Spy on the MongoClient.connect function to throw an Non-Error
vi.spyOn(MongoClient, "connect").mockImplementation(() => {
throw "Test error";
});

// Call the function with a test URL
const result = await checkConnection("mongodb://testUrl");

// Check that the result is false
expect(result).toBe(false);
});
it("should return the first valid URL when a connection is found", async () => {
process.env.MONGO_DB_URL = "mongodb://localhost:27017/talawa-api";
const result = await checkExistingMongoDB();
expect(result).toBe(process.env.MONGO_DB_URL);
});
Expand Down
Loading