78 lines
2.6 KiB
TypeScript
78 lines
2.6 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { createPinia, setActivePinia } from 'pinia'
|
|
import { terminateInstance, terminatingInstances, terminatingKey } from './instances'
|
|
|
|
/** 可控完成时机的 fetch stub;fail 控制 resolve 后是成功还是 500 */
|
|
function stubTerminateFetch(fail = false) {
|
|
const calls = { count: 0 }
|
|
let release!: () => void
|
|
const gate = new Promise<void>((r) => (release = r))
|
|
vi.stubGlobal('fetch', async () => {
|
|
calls.count++
|
|
await gate
|
|
if (fail) {
|
|
return {
|
|
ok: false,
|
|
status: 500,
|
|
url: '/api/v1/x',
|
|
json: async () => ({ error: '终止失败' }),
|
|
} as unknown as Response
|
|
}
|
|
return { ok: true, status: 200, text: async () => '' } as unknown as Response
|
|
})
|
|
return { calls, release }
|
|
}
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear()
|
|
setActivePinia(createPinia())
|
|
terminatingInstances.clear()
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals()
|
|
})
|
|
|
|
describe('共享终止锁', () => {
|
|
it('请求飞行中 key 在集合内,完成后移除', async () => {
|
|
const { release } = stubTerminateFetch()
|
|
const p = terminateInstance(3, 'ocid1.instance..x', false)
|
|
expect(terminatingInstances.has(terminatingKey(3, 'ocid1.instance..x'))).toBe(true)
|
|
release()
|
|
await p
|
|
expect(terminatingInstances.size).toBe(0)
|
|
})
|
|
|
|
it('请求失败同样释放锁,不留脏状态', async () => {
|
|
const { release } = stubTerminateFetch(true)
|
|
const p = terminateInstance(3, 'ocid1.instance..x', true)
|
|
expect(terminatingInstances.size).toBe(1)
|
|
release()
|
|
await expect(p).rejects.toMatchObject({ message: '终止失败' })
|
|
expect(terminatingInstances.size).toBe(0)
|
|
})
|
|
|
|
it('同一物理实例跨配置共享 key,后到调用被拒', async () => {
|
|
const { calls, release } = stubTerminateFetch()
|
|
const instanceId = 'ocid1.instance.oc1..same'
|
|
const first = terminateInstance(1, instanceId, false)
|
|
await expect(terminateInstance(2, instanceId, true)).rejects.toMatchObject({ status: 409 })
|
|
expect(terminatingKey(1, instanceId)).toBe(terminatingKey(2, instanceId))
|
|
expect(calls.count).toBe(1)
|
|
release()
|
|
await first
|
|
})
|
|
|
|
it('不同实例互不影响', async () => {
|
|
const { release } = stubTerminateFetch()
|
|
const pa = terminateInstance(1, 'a', false)
|
|
const pb = terminateInstance(2, 'b', false)
|
|
expect(terminatingInstances.has(terminatingKey(1, 'a'))).toBe(true)
|
|
expect(terminatingInstances.has(terminatingKey(2, 'b'))).toBe(true)
|
|
expect(terminatingKey(1, 'a')).not.toBe(terminatingKey(2, 'b'))
|
|
release()
|
|
await Promise.all([pa, pb])
|
|
expect(terminatingInstances.size).toBe(0)
|
|
})
|
|
})
|