Files
speckle-server/packages/server/modules/multiregion/tests/unit/projectRegion.spec.ts
T
Gergő Jedlicska f210d9b749 gergo/web 2109 project region based db connection selector (#3434)
* feat(projects): add project regions, default to null

* feat(multiregion): add projectRegion Db client lookup logic

* feat(multiregion): add project region repositories and caching

* feat(multiRegion): db initialization and get project db client

* feat(docker-compose): add second db for regions testing

* feat(multiRegion): initialize region with pubs and subs working

* fix(multiRegion): get region client even if it was registered in another pod

* feat(workspaces): create workspace resolver split

* feat: update server region metadata

* feat(projects): rewrite project creation

* feat(multiRegion): getRegionDb

* fix(workspaces): get projects now can retur null

* feat(multiRegion): make local multi region DB-s work

* feat: set d efault workspace region

* CR changes

* tests

* feat(multiRegion): bind region properly

* fe update

* test fixes

* feat(multiRegion): automatically create aiven extras plugin

* ci(postgres): use published postgres with aiven extras

* fix(multiRegion): roll back the aiven extras migration, there is a better way

* tests fix

* fix(billing): we do not need to add a seat, if the workspace is on a plan, but has no sub

---------

Co-authored-by: Kristaps Fabians Geikins <fabis94@live.com>
2024-11-06 17:29:08 +01:00

131 lines
4.7 KiB
TypeScript

import { StreamNotFoundError } from '@/modules/core/errors/stream'
import {
getProjectDbClientFactory,
getProjectRegionKeyFactory
} from '@/modules/multiregion/services/projectRegion'
import { expectToThrow } from '@/test/assertionHelper'
import { Optional } from '@speckle/shared'
import { expect } from 'chai'
import cryptoRandomString from 'crypto-random-string'
import { Knex } from 'knex'
describe('projectRegions @multiregion', () => {
describe('getProjectRegionKeyFactory creates a function, that', () => {
it('first returns from memory', async () => {
const getProjectRegion = getProjectRegionKeyFactory({
getRegionKeyFromMemory: () => null,
writeRegionToMemory: () => {
expect.fail()
},
getRegionKeyFromCache: () => {
expect.fail()
},
writeRegionKeyToCache: () => {
expect.fail()
},
getRegionKeyFromStorage: () => {
expect.fail()
}
})
const res = await getProjectRegion({
projectId: cryptoRandomString({ length: 10 })
})
expect(res).to.be.null
})
it('writes to memory and returns from the cache if not found in memory', async () => {
const regionKey = cryptoRandomString({ length: 10 })
const projectId = cryptoRandomString({ length: 10 })
let memoryKey: Optional<{ projectId: string; regionKey: string | null }> =
undefined
const getProjectRegion = getProjectRegionKeyFactory({
getRegionKeyFromMemory: () => undefined,
writeRegionToMemory: (projectRegion) => {
memoryKey = projectRegion
},
getRegionKeyFromCache: async () => regionKey,
writeRegionKeyToCache: () => {
expect.fail()
},
getRegionKeyFromStorage: () => {
expect.fail()
}
})
const res = await getProjectRegion({ projectId })
expect(res).to.be.equal(regionKey)
expect(memoryKey).deep.equal({ projectId, regionKey })
})
it('throws StreamNotFoundError if the project is not in the storage', async () => {
const getProjectRegion = getProjectRegionKeyFactory({
getRegionKeyFromMemory: () => undefined,
writeRegionToMemory: () => {
expect.fail()
},
getRegionKeyFromCache: async () => undefined,
writeRegionKeyToCache: async () => {
expect.fail()
},
getRegionKeyFromStorage: async () => undefined
})
const err = await expectToThrow(
async () =>
await getProjectRegion({ projectId: cryptoRandomString({ length: 10 }) })
)
expect(err.message).to.be.equal(new StreamNotFoundError().message)
})
it('writes to cache and memory and returns from storage if not found before', async () => {
const regionKey = cryptoRandomString({ length: 10 })
const projectId = cryptoRandomString({ length: 10 })
let memoryKey: Optional<{ projectId: string; regionKey: string | null }> =
undefined
let cacheKey: Optional<{ projectId: string; regionKey: string | null }> =
undefined
const getProjectRegion = getProjectRegionKeyFactory({
getRegionKeyFromMemory: () => undefined,
writeRegionToMemory: (projectRegion) => {
memoryKey = projectRegion
},
getRegionKeyFromCache: async () => undefined,
writeRegionKeyToCache: async (projectRegion) => {
cacheKey = projectRegion
},
getRegionKeyFromStorage: async () => regionKey
})
const res = await getProjectRegion({ projectId })
expect(res).to.be.equal(regionKey)
expect(memoryKey).deep.equal({ projectId, regionKey })
expect(cacheKey).deep.equal({ projectId, regionKey })
})
})
describe('getProjectDbClientFactory creates a function, that', () => {
it('returns the db from getDefaultDb if regionKey is null', async () => {
const db = {} as unknown as Knex
const getProjectDbClient = getProjectDbClientFactory({
getProjectRegionKey: async () => null,
getDefaultDb: () => db,
getRegionDb: () => {
expect.fail()
}
})
const res = await getProjectDbClient({
projectId: cryptoRandomString({ length: 10 })
})
expect(res).to.equal(db)
})
it('returns the fb from getRegionDb if there is a regionKey', async () => {
const db = {} as unknown as Knex
const getProjectDbClient = getProjectDbClientFactory({
getProjectRegionKey: async () => cryptoRandomString({ length: 10 }),
getDefaultDb: () => {
expect.fail()
},
getRegionDb: async () => db
})
const res = await getProjectDbClient({
projectId: cryptoRandomString({ length: 10 })
})
expect(res).to.equal(db)
})
})
})