2828 */
2929
3030import { describe , it , expect , vi , beforeEach , afterEach } from 'vitest' ;
31- import { ObjectQL } from '@objectstack/objectql' ;
31+ import { ObjectQL , assertEngineFindOnePredicate } from '@objectstack/objectql' ;
3232import { AuthManager } from './auth-manager' ;
3333import { authIdentityObjects } from './manifest' ;
3434
@@ -199,6 +199,26 @@ async function expectReadFaultRefusal(attempt: Promise<unknown>, object: string)
199199/** The registration answer an ObjectQL engine gives through `getSchema`. */
200200const schemaFor = ( ...registered : string [ ] ) => vi . fn ( ( object : string ) => ( registered . includes ( object ) ? { name : object } : undefined ) ) ;
201201
202+ /**
203+ * An engine double that answers the registration question (`getSchema`) beside
204+ * its two reads. Its `findOne` keeps ObjectQL's own predicate contract
205+ * (`assertEngineFindOnePredicate`), so it is no looser than the engine it
206+ * stands in for.
207+ */
208+ function registeringEngine (
209+ registered : string [ ] ,
210+ answers : { findOne : ( ) => Promise < unknown > ; find : ( ) => Promise < unknown > } ,
211+ ) {
212+ return {
213+ getSchema : schemaFor ( ...registered ) ,
214+ findOne : vi . fn ( async ( object : string , q ?: Query ) => {
215+ assertEngineFindOnePredicate ( object , q as never ) ;
216+ return answers . findOne ( ) ;
217+ } ) ,
218+ find : vi . fn ( answers . find ) ,
219+ } ;
220+ }
221+
202222describe ( 'organization slug guard — fails closed when a read cannot answer (#21941)' , ( ) => {
203223 it ( 'an organization read that throws is refused (503), and the environment read is never made' , async ( ) => {
204224 // SUPERSEDED PIN, quoted — what the guard answered before:
@@ -217,13 +237,12 @@ describe('organization slug guard — fails closed when a read cannot answer (#2
217237
218238 it ( 'an environment read that throws is refused (503) — on an engine that registers the object' , async ( ) => {
219239 // SUPERSEDED PIN, quoted — `find` threw and the hook resolved `undefined`.
220- const engine = {
221- getSchema : schemaFor ( 'sys_organization' , 'sys_environment' ) ,
222- findOne : vi . fn ( async ( ) => ORG ) ,
223- find : vi . fn ( async ( ) => {
240+ const engine = registeringEngine ( [ 'sys_organization' , 'sys_environment' ] , {
241+ findOne : async ( ) => ORG ,
242+ find : async ( ) => {
224243 throw new Error ( 'connection reset' ) ;
225- } ) ,
226- } ;
244+ } ,
245+ } ) ;
227246 const update = await slugGuard ( engine ) ;
228247 await expectReadFaultRefusal ( update ( 'acme-new' ) , 'sys_environment' ) ;
229248 expect ( engine . find ) . toHaveBeenCalledTimes ( 1 ) ;
@@ -241,30 +260,27 @@ describe('organization slug guard — fails closed when a read cannot answer (#2
241260 } ) ;
242261
243262 it ( 'a healthy read on a registered object still refuses the change while an active environment references the org, and allows it otherwise' , async ( ) => {
244- const refusing = {
245- getSchema : schemaFor ( 'sys_organization' , 'sys_environment' ) ,
246- findOne : vi . fn ( async ( ) => ORG ) ,
247- find : vi . fn ( async ( ) => ENVS ) ,
248- } ;
263+ const refusing = registeringEngine ( [ 'sys_organization' , 'sys_environment' ] , {
264+ findOne : async ( ) => ORG ,
265+ find : async ( ) => ENVS ,
266+ } ) ;
249267 await expectSlugRefusal ( ( await slugGuard ( refusing ) ) ( 'acme-new' ) ) ;
250- const allowing = {
251- getSchema : schemaFor ( 'sys_organization' , 'sys_environment' ) ,
252- findOne : vi . fn ( async ( ) => ORG ) ,
253- find : vi . fn ( async ( ) => [ { id : 'e2' , status : 'archived' } ] ) ,
254- } ;
268+ const allowing = registeringEngine ( [ 'sys_organization' , 'sys_environment' ] , {
269+ findOne : async ( ) => ORG ,
270+ find : async ( ) => [ { id : 'e2' , status : 'archived' } ] ,
271+ } ) ;
255272 await expect ( ( await slugGuard ( allowing ) ) ( 'acme-new' ) ) . resolves . toBeUndefined ( ) ;
256273 } ) ;
257274
258275 it ( 'an engine that does not register `sys_environment` declares the guard inapplicable — nothing is read' , async ( ) => {
259- const engine = {
260- getSchema : schemaFor ( 'sys_organization' ) ,
261- findOne : vi . fn ( async ( ) => {
276+ const engine = registeringEngine ( [ 'sys_organization' ] , {
277+ findOne : async ( ) => {
262278 throw new Error ( 'must not be read' ) ;
263- } ) ,
264- find : vi . fn ( async ( ) => {
279+ } ,
280+ find : async ( ) => {
265281 throw new Error ( 'must not be read' ) ;
266- } ) ,
267- } ;
282+ } ,
283+ } ) ;
268284 const update = await slugGuard ( engine ) ;
269285 await expect ( update ( 'acme-new' ) ) . resolves . toBeUndefined ( ) ;
270286 expect ( engine . getSchema ) . toHaveBeenCalledWith ( 'sys_environment' ) ;
0 commit comments