Skip to content

Commit

Permalink
chore: add more tests for privacy policy rules and nested transaction…
Browse files Browse the repository at this point in the history
… query contexts (#228)
  • Loading branch information
wschurman authored May 30, 2024
1 parent 8490ad5 commit 428cc6f
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
4 changes: 3 additions & 1 deletion packages/entity/src/EntityPrivacyPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,9 @@ export default abstract class EntityPrivacyPolicy<
case RuleEvaluationResult.ALLOW:
return entity;
default:
throw new Error('should not be a fourth type of rule evaluation result');
throw new Error(
`Invalid RuleEvaluationResult returned from rule: ${entity} (viewer = ${viewerContext}, action = ${EntityAuthorizationAction[action]}, ruleIndex = ${i})`
);
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/entity/src/EntityQueryContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ export class EntityTransactionalQueryContext extends EntityQueryContext {
* to EntityMutator and EntityLoader methods, those methods and their
* dependent triggers and validators will run within the nested transaction.
*
* This exists to forward post-commit callbacks to the parent query context.
* This exists to forward post-commit callbacks to the parent query context but only after
* successful commit of the nested transaction.
*/
export class EntityNestedTransactionalQueryContext extends EntityTransactionalQueryContext {
private readonly postCommitInvalidationCallbacksToTransfer: PostCommitCallback[] = [];
Expand Down
48 changes: 48 additions & 0 deletions packages/entity/src/__tests__/EntityPrivacyPolicy-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,30 @@ class SkipAllPolicy extends EntityPrivacyPolicy<BlahFields, string, ViewerContex
];
}

class InvalidCreateRuleResultPolicy extends EntityPrivacyPolicy<
BlahFields,
string,
ViewerContext,
BlahEntity
> {
protected override readonly createRules = [
{
async evaluateAsync(): Promise<RuleEvaluationResult> {
return 2 as any;
},
},
];
protected override readonly readRules = [
new AlwaysSkipPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
];
protected override readonly updateRules = [
new AlwaysSkipPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
];
protected override readonly deleteRules = [
new AlwaysSkipPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
];
}

class AlwaysThrowPrivacyPolicyRule extends PrivacyPolicyRule<
BlahFields,
string,
Expand Down Expand Up @@ -343,6 +367,30 @@ describe(EntityPrivacyPolicy, () => {
).once();
});

it('throws when an invalid result is returned', async () => {
const viewerContext = instance(mock(ViewerContext));
const queryContext = instance(mock(EntityQueryContext));
const privacyPolicyEvaluationContext = instance(mock<EntityPrivacyPolicyEvaluationContext>());
const metricsAdapterMock = mock<IEntityMetricsAdapter>();
const metricsAdapter = instance(metricsAdapterMock);
const entity = new BlahEntity({
viewerContext,
id: '1',
databaseFields: { id: '1' },
selectedFields: { id: '1' },
});
const policy = new InvalidCreateRuleResultPolicy();
await expect(
policy.authorizeCreateAsync(
viewerContext,
queryContext,
privacyPolicyEvaluationContext,
entity,
metricsAdapter
)
).rejects.toThrow('Invalid RuleEvaluationResult returned from rule');
});

it('throws EntityNotAuthorizedError when empty policy', async () => {
const viewerContext = instance(mock(ViewerContext));
const queryContext = instance(mock(EntityQueryContext));
Expand Down
18 changes: 18 additions & 0 deletions packages/entity/src/__tests__/EntityQueryContext-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,24 @@ describe(EntityQueryContext, () => {
expect(postCommitCallback).toHaveBeenCalledTimes(2);
expect(postCommitInvalidationCallback).toHaveBeenCalledTimes(2);
});

it('does not support calling runPostCommitCallbacksAsync on nested transaction', async () => {
const companionProvider = createUnitTestEntityCompanionProvider();
const viewerContext = new ViewerContext(companionProvider);

await expect(
viewerContext.runInTransactionForDatabaseAdaptorFlavorAsync(
'postgres',
async (queryContext) => {
await queryContext.runInNestedTransactionAsync(async (innerQueryContext) => {
await innerQueryContext.runPostCommitCallbacksAsync();
});
}
)
).rejects.toThrowError(
'Must not call runPostCommitCallbacksAsync on EntityNestedTransactionalQueryContext'
);
});
});

describe('transaction config', () => {
Expand Down

0 comments on commit 428cc6f

Please sign in to comment.