Skip to content

Commit

Permalink
chore: Port ctl code to Typescript (#37606)
Browse files Browse the repository at this point in the history
This PR converts the Javscript code of the `ctl` module, into
Typescript, and in the process already fixing two small bugs that went
undetected because... of lack of good type checking.

The linting exceptions are still there and will be removed in the next
PR. Didn't want to change anymore than necessary or Git will detect
these changes as "new files" instead of as "renames".


## Automation

/test sanity

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/11949059369>
> Commit: e156dac
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11949059369&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Sanity`
> Spec:
> <hr>Thu, 21 Nov 2024 08:45:48 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

- **New Features**
- Introduced TypeScript support by updating entry points and adding type
definitions for `nodemailer` and `readline-sync`.
- Enhanced logging and error handling functionalities across various
modules.

- **Improvements**
- Transitioned from CommonJS to ES module syntax for better
compatibility and maintainability.
  - Improved clarity and structure in command handling and test files.

- **Bug Fixes**
- Corrected regex patterns and variable declarations in tests to enhance
reliability.

- **Chores**
- Updated dependencies and refined module exports for better
organization.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
sharat87 authored Nov 21, 2024
1 parent 2099fce commit d6fbaa5
Show file tree
Hide file tree
Showing 18 changed files with 213 additions and 279 deletions.
2 changes: 1 addition & 1 deletion app/client/packages/rts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const getWorkflowDependencies = () => {
const bundle = async () => {
return esbuild
.build({
entryPoints: ["src/server.ts", "src/ctl/index.js"],
entryPoints: ["src/server.ts", "src/ctl/index.ts"],
bundle: true,
sourcemap: true,
platform: "node",
Expand Down
2 changes: 2 additions & 0 deletions app/client/packages/rts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"devDependencies": {
"@types/express": "^4.17.14",
"@types/jest": "^29.2.3",
"@types/nodemailer": "^6.4.17",
"@types/readline-sync": "^1.4.8",
"jest": "^29.3.1",
"supertest": "^6.3.3",
"ts-jest": "29.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
const backup = require("./backup");
const Constants = require("./constants");
const os = require("os");
const fsPromises = require("fs/promises");
const utils = require("./utils");
const readlineSync = require("readline-sync");
jest.mock("./utils", () => ({
...jest.requireActual("./utils"),
execCommand: jest.fn().mockImplementation(async (a) => a.join(" ")),
}));

import * as backup from "./backup";
import * as Constants from "./constants";
import os from "os";
import fsPromises from "fs/promises";
import * as utils from "./utils";
import readlineSync from "readline-sync";

describe("Backup Tests", () => {
test("Timestamp string in ISO format", () => {
console.log(backup.getTimeStampInISO());
expect(backup.getTimeStampInISO()).toMatch(
/(\d{4})-(\d{2})-(\d{2})T(\d{2})\-(\d{2})\-(\d{2})\.(\d{3})Z/,
/(\d{4})-(\d{2})-(\d{2})T(\d{2})-(\d{2})-(\d{2})\.(\d{3})Z/,
);
});

Expand All @@ -18,23 +23,23 @@ describe("Backup Tests", () => {
res.toBeGreaterThan(1024 * 1024);
});

it("Checkx the constant is 2 GB", () => {
let size = 2 * 1024 * 1024 * 1024;
it("Check the constant is 2 GB", () => {
const size = 2 * 1024 * 1024 * 1024;
expect(Constants.MIN_REQUIRED_DISK_SPACE_IN_BYTES).toBe(size);
});

it("Should throw Error when the available size is below MIN_REQUIRED_DISK_SPACE_IN_BYTES", () => {
let size = Constants.MIN_REQUIRED_DISK_SPACE_IN_BYTES - 1;
const size = Constants.MIN_REQUIRED_DISK_SPACE_IN_BYTES - 1;
expect(() => backup.checkAvailableBackupSpace(size)).toThrow();
});

it("Should not hould throw Error when the available size is >= MIN_REQUIRED_DISK_SPACE_IN_BYTES", () => {
it("Should not should throw Error when the available size is >= MIN_REQUIRED_DISK_SPACE_IN_BYTES", () => {
expect(() => {
backup.checkAvailableBackupSpace(
Constants.MIN_REQUIRED_DISK_SPACE_IN_BYTES,
);
}).not.toThrow(
"Not enough space avaliable at /appsmith-stacks. Please ensure availability of atleast 5GB to backup successfully.",
"Not enough space available at /appsmith-stacks. Please ensure availability of at least 5GB to backup successfully.",
);
});

Expand All @@ -46,19 +51,18 @@ describe("Backup Tests", () => {
});

test("Test backup contents path generation", () => {
var root = "/rootDir";
var timestamp = "0000-00-0T00-00-00.00Z";
const root = "/rootDir";
const timestamp = "0000-00-0T00-00-00.00Z";
expect(backup.getBackupContentsPath(root, timestamp)).toBe(
"/rootDir/appsmith-backup-0000-00-0T00-00-00.00Z",
);
});

test("Test mongodump CMD generaton", async () => {
var dest = "/dest";
var appsmithMongoURI = "mongodb://username:password@host/appsmith";
var cmd =
test("Test mongodump CMD generation", async () => {
const dest = "/dest";
const appsmithMongoURI = "mongodb://username:password@host/appsmith";
const cmd =
"mongodump --uri=mongodb://username:password@host/appsmith --archive=/dest/mongodb-data.gz --gzip";
utils.execCommand = jest.fn().mockImplementation(async (a) => a.join(" "));
const res = await backup.executeMongoDumpCMD(dest, appsmithMongoURI);
expect(res).toBe(cmd);
console.log(res);
Expand All @@ -77,10 +81,9 @@ describe("Backup Tests", () => {
});

test("Test ln command generation", async () => {
var gitRoot = "/appsmith-stacks/git-storage";
var dest = "/destdir";
var cmd = "ln -s /appsmith-stacks/git-storage /destdir/git-storage";
utils.execCommand = jest.fn().mockImplementation(async (a) => a.join(" "));
const gitRoot = "/appsmith-stacks/git-storage";
const dest = "/destdir";
const cmd = "ln -s /appsmith-stacks/git-storage /destdir/git-storage";
const res = await backup.executeCopyCMD(gitRoot, dest);
expect(res).toBe(cmd);
console.log(res);
Expand Down Expand Up @@ -127,8 +130,8 @@ describe("Backup Tests", () => {
test("Cleanup Backups when limit is 4 and there are 5 files", async () => {
const backupArchivesLimit = 4;
fsPromises.rm = jest.fn().mockImplementation(async (a) => console.log(a));
var backupFiles = ["file1", "file2", "file3", "file4", "file5"];
var expectedBackupFiles = ["file2", "file3", "file4", "file5"];
const backupFiles = ["file1", "file2", "file3", "file4", "file5"];
const expectedBackupFiles = ["file2", "file3", "file4", "file5"];
const res = await backup.removeOldBackups(backupFiles, backupArchivesLimit);
console.log(res);

Expand All @@ -138,8 +141,8 @@ describe("Backup Tests", () => {
test("Cleanup Backups when limit is 2 and there are 5 files", async () => {
const backupArchivesLimit = 2;
fsPromises.rm = jest.fn().mockImplementation(async (a) => console.log(a));
var backupFiles = ["file1", "file2", "file3", "file4", "file5"];
var expectedBackupFiles = ["file4", "file5"];
const backupFiles = ["file1", "file2", "file3", "file4", "file5"];
const expectedBackupFiles = ["file4", "file5"];
const res = await backup.removeOldBackups(backupFiles, backupArchivesLimit);
console.log(res);

Expand All @@ -149,8 +152,8 @@ describe("Backup Tests", () => {
test("Cleanup Backups when limit is 4 and there are 4 files", async () => {
const backupArchivesLimit = 4;
fsPromises.rm = jest.fn().mockImplementation(async (a) => console.log(a));
var backupFiles = ["file1", "file2", "file3", "file4"];
var expectedBackupFiles = ["file1", "file2", "file3", "file4"];
const backupFiles = ["file1", "file2", "file3", "file4"];
const expectedBackupFiles = ["file1", "file2", "file3", "file4"];
const res = await backup.removeOldBackups(backupFiles, backupArchivesLimit);
console.log(res);

Expand All @@ -160,8 +163,8 @@ describe("Backup Tests", () => {
test("Cleanup Backups when limit is 4 and there are 2 files", async () => {
const backupArchivesLimit = 4;
fsPromises.rm = jest.fn().mockImplementation(async (a) => console.log(a));
var backupFiles = ["file1", "file2"];
var expectedBackupFiles = ["file1", "file2"];
const backupFiles = ["file1", "file2"];
const expectedBackupFiles = ["file1", "file2"];
const res = await backup.removeOldBackups(backupFiles, backupArchivesLimit);
console.log(res);

Expand All @@ -171,8 +174,8 @@ describe("Backup Tests", () => {
test("Cleanup Backups when limit is 2 and there is 1 file", async () => {
const backupArchivesLimit = 4;
fsPromises.rm = jest.fn().mockImplementation(async (a) => console.log(a));
var backupFiles = ["file1"];
var expectedBackupFiles = ["file1"];
const backupFiles = ["file1"];
const expectedBackupFiles = ["file1"];
const res = await backup.removeOldBackups(backupFiles, backupArchivesLimit);
console.log(res);
expect(res).toEqual(expectedBackupFiles);
Expand All @@ -181,24 +184,22 @@ describe("Backup Tests", () => {
test("Cleanup Backups when limit is 2 and there is no file", async () => {
const backupArchivesLimit = 4;
fsPromises.rm = jest.fn().mockImplementation(async (a) => console.log(a));
var backupFiles = [];
var expectedBackupFiles = [];
const backupFiles = [];
const expectedBackupFiles = [];
const res = await backup.removeOldBackups(backupFiles, backupArchivesLimit);
console.log(res);
expect(res).toEqual(expectedBackupFiles);
});

test("Test get encryption password from user prompt whene both passords are the same", async () => {
test("Test get encryption password from user prompt when both passwords are the same", async () => {
const password = "password#4321";
readlineSync.question = jest.fn().mockImplementation((a) => {
return password;
});
readlineSync.question = jest.fn().mockImplementation(() => password);
const password_res = backup.getEncryptionPasswordFromUser();

expect(password_res).toEqual(password);
});

test("Test get encryption password from user prompt when both passords are the different", async () => {
test("Test get encryption password from user prompt when both passwords are the different", async () => {
const password = "password#4321";
readlineSync.question = jest.fn().mockImplementation((a) => {
if (a == "Enter the above password again: ") {
Expand All @@ -214,9 +215,6 @@ describe("Backup Tests", () => {
test("Get encrypted archive path", async () => {
const archivePath = "/rootDir/appsmith-backup-0000-00-0T00-00-00.00Z";
const encryptionPassword = "password#4321";
utils.execCommand = jest
.fn()
.mockImplementation(async (a) => console.log(a));
const encArchivePath = await backup.encryptBackupArchive(
archivePath,
encryptionPassword,
Expand All @@ -228,9 +226,6 @@ describe("Backup Tests", () => {
});

test("Test backup encryption function", async () => {
utils.execCommand = jest
.fn()
.mockImplementation(async (a) => console.log(a));
const archivePath = "/rootDir/appsmith-backup-0000-00-0T00-00-00.00Z";
const encryptionPassword = "password#123";
const res = await backup.encryptBackupArchive(
Expand All @@ -243,32 +238,32 @@ describe("Backup Tests", () => {
});

test("Get DB name from Mongo URI 1", async () => {
var mongodb_uri =
const mongodb_uri =
"mongodb+srv://admin:password@test.cluster.mongodb.net/my_db_name?retryWrites=true&minPoolSize=1&maxPoolSize=10&maxIdleTimeMS=900000&authSource=admin";
var expectedDBName = "my_db_name";
const expectedDBName = "my_db_name";
const dbName = utils.getDatabaseNameFromMongoURI(mongodb_uri);
expect(dbName).toEqual(expectedDBName);
});

test("Get DB name from Mongo URI 2", async () => {
var mongodb_uri =
const mongodb_uri =
"mongodb+srv://admin:password@test.cluster.mongodb.net/test123?retryWrites=true&minPoolSize=1&maxPoolSize=10&maxIdleTimeMS=900000&authSource=admin";
var expectedDBName = "test123";
const expectedDBName = "test123";
const dbName = utils.getDatabaseNameFromMongoURI(mongodb_uri);
expect(dbName).toEqual(expectedDBName);
});

test("Get DB name from Mongo URI 3", async () => {
var mongodb_uri =
const mongodb_uri =
"mongodb+srv://admin:password@test.cluster.mongodb.net/test123";
var expectedDBName = "test123";
const expectedDBName = "test123";
const dbName = utils.getDatabaseNameFromMongoURI(mongodb_uri);
expect(dbName).toEqual(expectedDBName);
});

test("Get DB name from Mongo URI 4", async () => {
var mongodb_uri = "mongodb://appsmith:pAssW0rd!@localhost:27017/appsmith";
var expectedDBName = "appsmith";
const mongodb_uri = "mongodb://appsmith:pAssW0rd!@localhost:27017/appsmith";
const expectedDBName = "appsmith";
const dbName = utils.getDatabaseNameFromMongoURI(mongodb_uri);
expect(dbName).toEqual(expectedDBName);
});
Loading

0 comments on commit d6fbaa5

Please sign in to comment.