-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: script runner beginings * feat: adding tests and update to service * fix: updates per eric
- Loading branch information
1 parent
a324a17
commit 24be7e8
Showing
9 changed files
with
303 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
-- CreateTable | ||
CREATE TABLE "script_runs" ( | ||
"id" UUID NOT NULL DEFAULT uuid_generate_v4(), | ||
"created_at" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updated_at" TIMESTAMP(6) NOT NULL, | ||
"script_name" TEXT NOT NULL, | ||
"triggering_user" UUID NOT NULL, | ||
"did_script_run" BOOLEAN NOT NULL DEFAULT false, | ||
|
||
CONSTRAINT "script_runs_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "script_runs_script_name_key" ON "script_runs"("script_name"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { | ||
Controller, | ||
Put, | ||
Request, | ||
UseGuards, | ||
UsePipes, | ||
ValidationPipe, | ||
} from '@nestjs/common'; | ||
import { Request as ExpressRequest } from 'express'; | ||
import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; | ||
import { ScriptRunnerService } from '../services/script-runner.service'; | ||
import { defaultValidationPipeOptions } from '../utilities/default-validation-pipe-options'; | ||
import { SuccessDTO } from '../dtos/shared/success.dto'; | ||
import { OptionalAuthGuard } from '../guards/optional.guard'; | ||
import { AdminOrJurisdictionalAdminGuard } from '../guards/admin-or-jurisdiction-admin.guard'; | ||
|
||
@Controller('scriptRunner') | ||
@ApiTags('scriptRunner') | ||
@UsePipes(new ValidationPipe(defaultValidationPipeOptions)) | ||
@UseGuards(OptionalAuthGuard, AdminOrJurisdictionalAdminGuard) | ||
export class ScirptRunnerController { | ||
constructor(private readonly scriptRunnerService: ScriptRunnerService) {} | ||
|
||
@Put('exampleScript') | ||
@ApiOperation({ | ||
summary: 'An example of how the script runner can work', | ||
operationId: 'exampleScript', | ||
}) | ||
@ApiOkResponse({ type: SuccessDTO }) | ||
async update(@Request() req: ExpressRequest): Promise<SuccessDTO> { | ||
return await this.scriptRunnerService.example(req); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { ScirptRunnerController } from '../controllers/script-runner.controller'; | ||
import { ScriptRunnerService } from '../services/script-runner.service'; | ||
import { PrismaModule } from './prisma.module'; | ||
import { PermissionModule } from './permission.module'; | ||
|
||
@Module({ | ||
imports: [PrismaModule, PermissionModule], | ||
controllers: [ScirptRunnerController], | ||
providers: [ScriptRunnerService], | ||
exports: [ScriptRunnerService], | ||
}) | ||
export class ScirptRunnerModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { Injectable, BadRequestException } from '@nestjs/common'; | ||
import { Request as ExpressRequest } from 'express'; | ||
import { PrismaService } from './prisma.service'; | ||
import { SuccessDTO } from '../dtos/shared/success.dto'; | ||
import { User } from '../dtos/users/user.dto'; | ||
import { mapTo } from '../utilities/mapTo'; | ||
|
||
/** | ||
this is the service for running scripts | ||
most functions in here will be unique, but each function should only be allowed to fire once | ||
*/ | ||
@Injectable() | ||
export class ScriptRunnerService { | ||
constructor(private prisma: PrismaService) {} | ||
|
||
/** | ||
this is simply an example | ||
*/ | ||
async example(req: ExpressRequest): Promise<SuccessDTO> { | ||
const requestingUser = mapTo(User, req['user']); | ||
await this.markScriptAsRunStart('example', requestingUser); | ||
const rawJurisdictions = await this.prisma.jurisdictions.findMany(); | ||
await this.markScriptAsComplete('example', requestingUser); | ||
return { success: !!rawJurisdictions.length }; | ||
} | ||
|
||
// |------------------ HELPERS GO BELOW ------------------ | // | ||
|
||
/** | ||
* | ||
* @param scriptName the name of the script that is going to be run | ||
* @param userTriggeringTheRun the user that is attempting to trigger the script run | ||
* @description this checks to see if the script has already ran, if not marks the script in the db | ||
*/ | ||
async markScriptAsRunStart( | ||
scriptName: string, | ||
userTriggeringTheRun: User, | ||
): Promise<void> { | ||
// check to see if script is already ran in db | ||
const storedScriptRun = await this.prisma.scriptRuns.findUnique({ | ||
where: { | ||
scriptName, | ||
}, | ||
}); | ||
|
||
if (storedScriptRun?.didScriptRun) { | ||
// if script run has already successfully completed throw already succeed error | ||
throw new BadRequestException( | ||
`${scriptName} has already been run and succeeded`, | ||
); | ||
} else if (storedScriptRun?.didScriptRun === false) { | ||
// if script run was attempted but failed, throw attempt already failed error | ||
throw new BadRequestException( | ||
`${scriptName} has an attempted run and it failed, or is in progress. If it failed, please delete the db entry and try again`, | ||
); | ||
} else { | ||
// if no script run has been attempted create script run entry | ||
await this.prisma.scriptRuns.create({ | ||
data: { | ||
scriptName, | ||
triggeringUser: userTriggeringTheRun.id, | ||
}, | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* @param scriptName the name of the script that is going to be run | ||
* @param userTriggeringTheRun the user that is setting the script run as successfully completed | ||
* @description this marks the script run entry in the db as successfully completed | ||
*/ | ||
async markScriptAsComplete( | ||
scriptName: string, | ||
userTriggeringTheRun: User, | ||
): Promise<void> { | ||
await this.prisma.scriptRuns.update({ | ||
data: { | ||
didScriptRun: true, | ||
triggeringUser: userTriggeringTheRun.id, | ||
}, | ||
where: { | ||
scriptName, | ||
}, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { Logger } from '@nestjs/common'; | ||
import { randomUUID } from 'crypto'; | ||
import { SchedulerRegistry } from '@nestjs/schedule'; | ||
import { ScriptRunnerService } from '../../../src/services/script-runner.service'; | ||
import { PrismaService } from '../../../src/services/prisma.service'; | ||
import { User } from '../../../src/dtos/users/user.dto'; | ||
|
||
describe('Testing script runner service', () => { | ||
let service: ScriptRunnerService; | ||
let prisma: PrismaService; | ||
beforeAll(async () => { | ||
const module: TestingModule = await Test.createTestingModule({ | ||
providers: [ | ||
ScriptRunnerService, | ||
PrismaService, | ||
Logger, | ||
SchedulerRegistry, | ||
], | ||
}).compile(); | ||
|
||
service = module.get<ScriptRunnerService>(ScriptRunnerService); | ||
prisma = module.get<PrismaService>(PrismaService); | ||
}); | ||
|
||
// | ---------- HELPER TESTS BELOW ---------- | // | ||
it('should mark script run as started if no script run present in db', async () => { | ||
prisma.scriptRuns.findUnique = jest.fn().mockResolvedValue(null); | ||
prisma.scriptRuns.create = jest.fn().mockResolvedValue(null); | ||
|
||
const id = randomUUID(); | ||
const scriptName = 'new run attempt'; | ||
|
||
await service.markScriptAsRunStart(scriptName, { | ||
id, | ||
} as unknown as User); | ||
|
||
expect(prisma.scriptRuns.findUnique).toHaveBeenCalledWith({ | ||
where: { | ||
scriptName, | ||
}, | ||
}); | ||
expect(prisma.scriptRuns.create).toHaveBeenCalledWith({ | ||
data: { | ||
scriptName, | ||
triggeringUser: id, | ||
}, | ||
}); | ||
}); | ||
|
||
it('should error if script run is in progress or failed', async () => { | ||
prisma.scriptRuns.findUnique = jest.fn().mockResolvedValue({ | ||
id: randomUUID(), | ||
didScriptRun: false, | ||
}); | ||
prisma.scriptRuns.create = jest.fn().mockResolvedValue(null); | ||
|
||
const id = randomUUID(); | ||
const scriptName = 'new run attempt 2'; | ||
|
||
await expect( | ||
async () => | ||
await service.markScriptAsRunStart(scriptName, { | ||
id, | ||
} as unknown as User), | ||
).rejects.toThrowError( | ||
`${scriptName} has an attempted run and it failed, or is in progress. If it failed, please delete the db entry and try again`, | ||
); | ||
|
||
expect(prisma.scriptRuns.findUnique).toHaveBeenCalledWith({ | ||
where: { | ||
scriptName, | ||
}, | ||
}); | ||
expect(prisma.scriptRuns.create).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should error if script run already succeeded', async () => { | ||
prisma.scriptRuns.findUnique = jest.fn().mockResolvedValue({ | ||
id: randomUUID(), | ||
didScriptRun: true, | ||
}); | ||
prisma.scriptRuns.create = jest.fn().mockResolvedValue(null); | ||
|
||
const id = randomUUID(); | ||
const scriptName = 'new run attempt 3'; | ||
|
||
await expect( | ||
async () => | ||
await service.markScriptAsRunStart(scriptName, { | ||
id, | ||
} as unknown as User), | ||
).rejects.toThrowError(`${scriptName} has already been run and succeeded`); | ||
|
||
expect(prisma.scriptRuns.findUnique).toHaveBeenCalledWith({ | ||
where: { | ||
scriptName, | ||
}, | ||
}); | ||
expect(prisma.scriptRuns.create).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should mark script run as started if no script run present in db', async () => { | ||
prisma.scriptRuns.update = jest.fn().mockResolvedValue(null); | ||
|
||
const id = randomUUID(); | ||
const scriptName = 'new run attempt 4'; | ||
|
||
await service.markScriptAsComplete(scriptName, { | ||
id, | ||
} as unknown as User); | ||
|
||
expect(prisma.scriptRuns.update).toHaveBeenCalledWith({ | ||
data: { | ||
didScriptRun: true, | ||
triggeringUser: id, | ||
}, | ||
where: { | ||
scriptName, | ||
}, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters