Skip to content

Commit 6c6f50a

Browse files
authored
feat(backend): tenant id filter tests for gql pagination (#3567)
* feat(backend): tenant id filter tests for gql pagination * fix: improve tests based on comments
1 parent 490f627 commit 6c6f50a

File tree

9 files changed

+998
-26
lines changed

9 files changed

+998
-26
lines changed

packages/backend/src/graphql/resolvers/asset.test.ts

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { ApolloError, gql } from '@apollo/client'
1+
import {
2+
ApolloClient,
3+
ApolloError,
4+
gql,
5+
NormalizedCacheObject
6+
} from '@apollo/client'
27
import assert from 'assert'
38
import { v4 as uuid } from 'uuid'
49

@@ -661,6 +666,163 @@ describe('Asset Resolvers', (): void => {
661666
})
662667
})
663668
})
669+
670+
describe('tenant boundaries', (): void => {
671+
let operatorAsset: AssetModel
672+
let tenantAsset: AssetModel
673+
let secondTenantAsset: AssetModel
674+
let tenantedApolloClient: ApolloClient<NormalizedCacheObject>
675+
676+
const pageQuery = gql`
677+
query Assets($tenantId: String) {
678+
assets(tenantId: $tenantId) {
679+
edges {
680+
node {
681+
id
682+
}
683+
}
684+
}
685+
}
686+
`
687+
beforeEach(async (): Promise<void> => {
688+
operatorAsset = await createAsset(deps)
689+
690+
const tenant = await createTenant(deps)
691+
tenantedApolloClient = await createApolloClient(
692+
appContainer.container,
693+
appContainer.app,
694+
tenant.id
695+
)
696+
tenantAsset = await createAsset(deps, { tenantId: tenant.id })
697+
secondTenantAsset = await createAsset(deps, { tenantId: tenant.id })
698+
})
699+
test('operator can get assets across all tenants', async (): Promise<void> => {
700+
const query = await appContainer.apolloClient
701+
.query({
702+
query: pageQuery
703+
})
704+
.then((query): AssetsConnection => {
705+
if (query.data) {
706+
return query.data.assets
707+
} else {
708+
throw new Error('Data was empty')
709+
}
710+
})
711+
expect(query.edges).toHaveLength(3)
712+
expect(query.edges).toEqual(
713+
expect.arrayContaining([
714+
expect.objectContaining({
715+
node: expect.objectContaining({
716+
id: operatorAsset.id
717+
})
718+
}),
719+
expect.objectContaining({
720+
node: expect.objectContaining({
721+
id: tenantAsset.id
722+
})
723+
}),
724+
expect.objectContaining({
725+
node: expect.objectContaining({
726+
id: secondTenantAsset.id
727+
})
728+
})
729+
])
730+
)
731+
})
732+
733+
test('tenant cannot get assets across all tenants', async (): Promise<void> => {
734+
const query = await tenantedApolloClient
735+
.query({
736+
query: pageQuery
737+
})
738+
.then((query): AssetsConnection => {
739+
if (query.data) {
740+
return query.data.assets
741+
} else {
742+
throw new Error('Data was empty')
743+
}
744+
})
745+
expect(query.edges).toHaveLength(2)
746+
expect(query.edges).toEqual(
747+
expect.arrayContaining([
748+
expect.objectContaining({
749+
node: expect.objectContaining({
750+
id: tenantAsset.id
751+
})
752+
}),
753+
expect.objectContaining({
754+
node: expect.objectContaining({
755+
id: secondTenantAsset.id
756+
})
757+
})
758+
])
759+
)
760+
})
761+
762+
test('operator can specify filter assets across all tenants', async (): Promise<void> => {
763+
const query = await appContainer.apolloClient
764+
.query({
765+
query: pageQuery,
766+
variables: {
767+
tenantId: tenantAsset.tenantId
768+
}
769+
})
770+
.then((query): AssetsConnection => {
771+
if (query.data) {
772+
return query.data.assets
773+
} else {
774+
throw new Error('Data was empty')
775+
}
776+
})
777+
expect(query.edges).toHaveLength(2)
778+
expect(query.edges).toEqual(
779+
expect.arrayContaining([
780+
expect.objectContaining({
781+
node: expect.objectContaining({
782+
id: tenantAsset.id
783+
})
784+
}),
785+
expect.objectContaining({
786+
node: expect.objectContaining({
787+
id: secondTenantAsset.id
788+
})
789+
})
790+
])
791+
)
792+
})
793+
794+
test('tenant cannot filter assets across all tenants', async (): Promise<void> => {
795+
const query = await tenantedApolloClient
796+
.query({
797+
query: pageQuery,
798+
variables: {
799+
tenantId: Config.operatorTenantId
800+
}
801+
})
802+
.then((query): AssetsConnection => {
803+
if (query.data) {
804+
return query.data.assets
805+
} else {
806+
throw new Error('Data was empty')
807+
}
808+
})
809+
expect(query.edges).toHaveLength(2)
810+
expect(query.edges).toEqual(
811+
expect.arrayContaining([
812+
expect.objectContaining({
813+
node: expect.objectContaining({
814+
id: tenantAsset.id
815+
})
816+
}),
817+
expect.objectContaining({
818+
node: expect.objectContaining({
819+
id: secondTenantAsset.id
820+
})
821+
})
822+
])
823+
)
824+
})
825+
})
664826
})
665827

666828
describe('updateAsset', (): void => {

packages/backend/src/graphql/resolvers/combined_payments.test.ts

Lines changed: 151 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { IocContract } from '@adonisjs/fold'
2-
import { gql } from '@apollo/client'
2+
import { ApolloClient, gql, NormalizedCacheObject } from '@apollo/client'
33
import { AppServices } from '../../app'
4-
import { createTestApp, TestContainer } from '../../tests/app'
4+
import {
5+
createApolloClient,
6+
createTestApp,
7+
TestContainer
8+
} from '../../tests/app'
59
import { initIocContainer } from '../..'
610
import { Config } from '../../config/app'
711
import { truncateTables } from '../../tests/tableManager'
@@ -16,8 +20,12 @@ import {
1620
createCombinedPayment,
1721
toCombinedPayment
1822
} from '../../tests/combinedPayment'
19-
import { PaymentType } from '../../open_payments/payment/combined/model'
23+
import {
24+
CombinedPayment,
25+
PaymentType
26+
} from '../../open_payments/payment/combined/model'
2027
import { getPageTests } from './page.test'
28+
import { createTenant } from '../../tests/tenant'
2129

2230
describe('Payment', (): void => {
2331
let deps: IocContract<AppServices>
@@ -240,4 +248,144 @@ describe('Payment', (): void => {
240248
createdAt: combinedOutgoingPayment.createdAt.toISOString()
241249
})
242250
})
251+
252+
describe('tenant boundaries', (): void => {
253+
let operatorPayment: CombinedPayment
254+
let tenantPayment: CombinedPayment
255+
let secondTenantPayment: CombinedPayment
256+
let tenenatedApolloClient: ApolloClient<NormalizedCacheObject>
257+
258+
const pageQuery = gql`
259+
query Payments($tenantId: String) {
260+
payments(tenantId: $tenantId) {
261+
edges {
262+
node {
263+
id
264+
}
265+
}
266+
}
267+
}
268+
`
269+
270+
beforeEach(async (): Promise<void> => {
271+
operatorPayment = await createCombinedPayment(deps)
272+
const tenant = await createTenant(deps)
273+
tenenatedApolloClient = await createApolloClient(
274+
appContainer.container,
275+
appContainer.app,
276+
tenant.id
277+
)
278+
tenantPayment = await createCombinedPayment(deps, { tenantId: tenant.id })
279+
secondTenantPayment = await createCombinedPayment(deps, {
280+
tenantId: tenant.id
281+
})
282+
})
283+
284+
test('operator can get payments across all tenants', async (): Promise<void> => {
285+
const query = await appContainer.apolloClient
286+
.query({
287+
query: pageQuery
288+
})
289+
.then((query): PaymentConnection => {
290+
if (query.data) {
291+
return query.data.payments
292+
} else {
293+
throw new Error('data was empty')
294+
}
295+
})
296+
expect(query.edges).toHaveLength(3)
297+
expect(query.edges).toEqual(
298+
expect.arrayContaining([
299+
expect.objectContaining({
300+
node: expect.objectContaining({ id: operatorPayment.id })
301+
}),
302+
expect.objectContaining({
303+
node: expect.objectContaining({ id: tenantPayment.id })
304+
}),
305+
expect.objectContaining({
306+
node: expect.objectContaining({ id: secondTenantPayment.id })
307+
})
308+
])
309+
)
310+
})
311+
312+
test('tenant cannot get payments across all tenants', async (): Promise<void> => {
313+
const query = await tenenatedApolloClient
314+
.query({
315+
query: pageQuery
316+
})
317+
.then((query): PaymentConnection => {
318+
if (query.data) {
319+
return query.data.payments
320+
} else {
321+
throw new Error('data was empty')
322+
}
323+
})
324+
expect(query.edges).toHaveLength(2)
325+
expect(query.edges).toEqual(
326+
expect.arrayContaining([
327+
expect.objectContaining({
328+
node: expect.objectContaining({ id: tenantPayment.id })
329+
}),
330+
expect.objectContaining({
331+
node: expect.objectContaining({ id: secondTenantPayment.id })
332+
})
333+
])
334+
)
335+
})
336+
337+
test('operator can filter payments across all tenants', async (): Promise<void> => {
338+
const query = await appContainer.apolloClient
339+
.query({
340+
query: pageQuery,
341+
variables: { tenantId: tenantPayment.tenantId }
342+
})
343+
.then((query): PaymentConnection => {
344+
if (query.data) {
345+
return query.data.payments
346+
} else {
347+
throw new Error('data was empty')
348+
}
349+
})
350+
expect(query.edges).toHaveLength(2)
351+
expect(query.edges).toEqual(
352+
expect.arrayContaining([
353+
expect.objectContaining({
354+
node: expect.objectContaining({ id: tenantPayment.id })
355+
}),
356+
expect.objectContaining({
357+
node: expect.objectContaining({ id: secondTenantPayment.id })
358+
})
359+
])
360+
)
361+
})
362+
363+
test('tenant cannot filter payments across all tenants', async (): Promise<void> => {
364+
const query = await tenenatedApolloClient
365+
.query({
366+
query: pageQuery,
367+
variables: {
368+
tenantId: operatorPayment.tenantId
369+
}
370+
})
371+
.then((query): PaymentConnection => {
372+
if (query.data) {
373+
return query.data.payments
374+
} else {
375+
throw new Error('data was empty')
376+
}
377+
})
378+
expect(query.edges).toHaveLength(2)
379+
expect(query.edges).toEqual(
380+
expect.arrayContaining([
381+
expect.objectContaining({
382+
node: expect.objectContaining({ id: tenantPayment.id })
383+
}),
384+
expect.objectContaining({
385+
node: expect.objectContaining({ id: secondTenantPayment.id })
386+
})
387+
])
388+
)
389+
})
390+
})
243391
})

0 commit comments

Comments
 (0)