@@ -0,0 +1,77 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user