-
Notifications
You must be signed in to change notification settings - Fork 24
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
Jobs tests #1286
Jobs tests #1286
Conversation
* reset dataset before every api test * Clear collections before each api test
1. Use CreateJobAuth enum instead of AuthOp to define jobDatasetAuthorization 2. Shift a block if groupOwner is present down after the admin check was passed (admin create a job for anonym) 3. Check if current authorization is in jobDatasetAuthorization in instanceAuthorizationJobCreate (types mismatching) 4. Add a check if unauthorized user creates a job for someone else
if anonymous user creates a job, initialize a jwt instance for him/her
string array includes string enum
1. comment out jobConfig matchin, as now in interceptor 2. fix filtering object hierarchy in #dataset kind of jobConfig's 3. not defining jobInstance ownerUser/Group as empty string 4. add jobInstance.jobParams initialization 5. add a check if datasets passed in the ID list exist
* Anonymous user can patch status update to a job in #all config. Added instance authorization * Implement JobDelete authorization
* similarly to Datasets, mongoose returns an Object and not JobClass instances. To pass this into CASL we first need to make those class instances. generateJobInstanceForPermissions implements a copy of object as correct class instance only with properties required in casl. * functionality of instanceAuthorizationJobStatusUpdate is now implemented in the patch endpoint function. This is done to avoid redefining a found job as a instance of JobClass with all properties * For both GET endpoints only the endpoint authorisation was implemented for user in the functions of the controller. To add the instance authorization too, first create JobClass instance of the found job Objects and pass them to respective casl expressions. * adds implementation of delete endpoints. The rules are defined in the CheckPolicies decorator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed jobs.controller
@despadam I made some changes you requested. For other comments, we can discuss tomorrow in person |
merge chanhes after conversation on how configuration will be stored
…e, st it can be used for all cases where we need to extract the configuration, without having to pass the full dto
@Despina, I've updated the change to configuration grabbing for statusUpdate as we discussed |
- Run lint:fix - Ignore no-explicit-any rule for jobParams (which are not type checked) - remove 'read' jobOperation (not implemented)
- Revert previous changes to ignore no-explicit-any - Use `unknown` for jobParam inputs plus stronger runtime checks - Fix compilation error in elastic-search service relating to deleting non-optional variables. - Remove rabbitmqaction validation. RabbitMQ should ignore the DTO body, and validate the config itself in the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good. I added a couple minor comments but it looks good.
Can you verify that mocha passes before merging? @despadam and I both ran into issues running the tests. Mocha should be added to the CI following this PR.
private body: Record<string, any> | null = null; | ||
|
||
getActionType(): string { | ||
return URLAction.actionType; | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird that this empty method causes a lint warning; it overrides the interface method.
src/jobs/jobs.controller.ts
Outdated
pid: { $eq: datasetIds[i] }, | ||
}, | ||
}; | ||
const idCount = await this.datasetsService.count(filter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be more performant to make a single database request here, rather than one request per datasetId?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're right, I changed that in the last commit
src/jobs/jobs.controller.ts
Outdated
throw new HttpException( | ||
{ | ||
status: HttpStatus.BAD_REQUEST, | ||
message: "At least one dataset in the ids list doesn't exist.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should include datasetIds[i]
in the error message to make debugging easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in the last commit
src/jobs/jobs.controller.ts
Outdated
@@ -758,6 +866,7 @@ export class JobsController { | |||
@Req() request: Request, | |||
@Param("id") id: string, | |||
): Promise<unknown> { | |||
Logger.log("Deleting job!"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should include the id in the log message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in the last commit
password: TestData.Accounts["archiveManager"]["password"], | ||
}, | ||
(tokenVal) => { | ||
accessTokenArchiveManager = tokenVal; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a lot of nesting! Not necessary for this PR, but maybe getToken
needs to be refactored to return a promise rather than use callbacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is addressed in PR #1350
test/Jobs.js
Outdated
// res.body.should.not.have.property("id"); | ||
// res.body.should.have.propert("message").and.be.equal("Dataset ids list was not provided in jobParams"); | ||
// }); | ||
// }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why commented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I was confused by the logic myself a bit. I changed this one into 0065. Now these tests at the beginning cover:
jobParams
is passed with propertydatasetIds
, but the array is empty --> fail (0040)jobParams
is passed with propertydatasetIds
, but it refers to datasetIds that are not in database --> fail (0050)jobParams
is not passed at all --> fail (0060)jobParams
is passed as empty object --> fail (0065)
I additionally implemented the check for jobParams
property in the create
endpoint. It checks that jobParams
is passed and is not empty. Before that if no jobParams
were passed a 500 internal error was thrown. Now the error message is explicitly saying that jobParams
need to be defined and not empty.
the last two tests are new. 0060 before was testing with an empty object as jobParams, which passed before. Now, as I I changed the implementation a little, this test fails. I think it is logical that if a job has no context it shouldn't be accepted? This test now is numbered as 0065.
0060 tests the case where no jobParams
passed at all.
} | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
async validate(dto: T) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sbliven I struggle to understand the need for validate()
in the action class
. I was always wondering whether it makes sense validating after calling the constructor, and your changes here I think prove my point that it probably doesn't. I would suggest following this example and moving all validation inside the constructor of each action. Then:
- On job
create
if creating an action fails, the job creation should also fail. - On job
statusUpdate
things get a bit more complicated. Since we are using a global job configuration, instead of job specific, if no changes were made to the configuration then no validation is needed at all and we can proceed directly to performing the job. But, if the configuration has changed, we would need a method that would first update the values of the class' attributes, before performing the action.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After discussing with @sofyalaski, I will create a separate PR to address this.
0060 now checks if a job was passed without a required parameter JobParams 0065 (new) checks if a job was passed with an empty object for jobParams 1950 now tries to delete a job that doesn't exist and fails 1960 was called 1950 before counts on GET are changed (because 0060 before was passing)
* now makes one request to the db to find datasets and extracts their pids. * loggs the names of all dataset pids that are not in the db in case of an error * job endpoint implements the check that the jobParams were passed and are not empty, otherwise it will throw a bad request with respective message * job endpoint loggs the id of job to be deleted and implements a check if job exist in db, otherwise throws an error.
@sbliven in the commit two weeks ago I added running the tests on PR to the "relase-*" branches, and you can see the bars here at the bottom, I assume. For me, the API tests seem to be passing (API test include both |
Description
Implements API tests for jobs authorization endpoints and proposes fixes for missing cases
Motivation
Fixes are proposed to follow the authorization logic described in the documentation
Fixes:
jobs.controller.ts
CreateJobAuth
enum instead ofAuthOp
to definejobDatasetAuthorization
instanceAuthorizationJobCreate
shift an "if-block" checking the presence ofownerGroup
down after the admin check was passed (reason: admin should be able to create a job for anonym)jobDatasetAuthorization
(types mismatching)checkDatasetIds
function add a check if each requested datasetId exists in database ( for the "dataset" -kind of job configurations)generateJobInstanceForPermissions
function, which is similar to the one in datasets.controller. mongoosefindOne
andfindAll
do not return an instance of JobClass as implemented but a simple JS Object. Since we still need to pass that object to casl( which expects the instance of JobClass) we need conversion. To not write all properties of JobClass, a minimal copy with only properties required for permission checking is created. The return instances are not affected by this and remain JS Object.instanceAuthorizationJobStatusUpdate
is now implemented in the patch endpoint function. This is done to avoid redefining a job return byfindOne
as a instance of JobClass with all properties.jobs.service.ts
create
andstatusUpdate
functionscasl-ability.factory.ts
Changes
configuration.ts
Tests included