Skip to content

Commit 226d421

Browse files
authored
minor: refactor instanceCan and diskCan for better type safety (#2505)
* refactor instanceCan and diskCan for better type safety * ok well I did it
1 parent a76ba5f commit 226d421

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

app/api/util.spec.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import { describe, expect, it, test } from 'vitest'
99

10-
import { genName, parsePortRange, synthesizeData } from './util'
10+
import { diskCan, genName, instanceCan, parsePortRange, synthesizeData } from './util'
1111

1212
describe('parsePortRange', () => {
1313
describe('parses', () => {
@@ -136,3 +136,22 @@ describe('synthesizeData', () => {
136136
])
137137
})
138138
})
139+
140+
test('instanceCan', () => {
141+
expect(instanceCan.start({ runState: 'running' })).toBe(false)
142+
expect(instanceCan.start({ runState: 'stopped' })).toBe(true)
143+
144+
// @ts-expect-error typechecker rejects actions that don't exist
145+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
146+
instanceCan.abc
147+
})
148+
149+
test('diskCan', () => {
150+
expect(diskCan.delete({ state: { state: 'creating' } })).toBe(false)
151+
expect(diskCan.delete({ state: { state: 'attached', instance: 'xyz' } })).toBe(false)
152+
expect(diskCan.delete({ state: { state: 'detached' } })).toBe(true)
153+
154+
// @ts-expect-error typechecker rejects actions that don't exist
155+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
156+
diskCan.abc
157+
})

app/api/util.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export const genName = (...parts: [string, ...string[]]) => {
8989
)
9090
}
9191

92-
const instanceActions: Record<string, InstanceState[]> = {
92+
const instanceActions = {
9393
// NoVmm maps to to Stopped:
9494
// https://github.com/oxidecomputer/omicron/blob/6dd9802/nexus/db-model/src/instance_state.rs#L55
9595

@@ -120,12 +120,12 @@ const instanceActions: Record<string, InstanceState[]> = {
120120
updateNic: ['stopped'],
121121
// https://github.com/oxidecomputer/omicron/blob/6dd9802/nexus/src/app/instance.rs#L1520-L1522
122122
serialConsole: ['running', 'rebooting', 'migrating', 'repairing'],
123-
}
123+
} satisfies Record<string, InstanceState[]>
124124

125125
// setting .states is a cute way to make it ergonomic to call the test function
126126
// while also making the states available directly
127127

128-
export const instanceCan = R.mapValues(instanceActions, (states) => {
128+
export const instanceCan = R.mapValues(instanceActions, (states: InstanceState[]) => {
129129
const test = (i: { runState: InstanceState }) => states.includes(i.runState)
130130
test.states = states
131131
return test
@@ -140,7 +140,7 @@ export function instanceTransitioning({ runState }: Instance) {
140140
)
141141
}
142142

143-
const diskActions: Record<string, DiskState['state'][]> = {
143+
const diskActions = {
144144
// this is a weird one because the list of states is dynamic and it includes
145145
// 'creating' in the unwind of the disk create saga, but does not include
146146
// 'creating' in the disk delete saga, which is what we care about
@@ -154,9 +154,9 @@ const diskActions: Record<string, DiskState['state'][]> = {
154154
detach: ['attached'],
155155
// https://github.com/oxidecomputer/omicron/blob/3093818/nexus/db-queries/src/db/datastore/instance.rs#L1077-L1081
156156
setAsBootDisk: ['attached'],
157-
}
157+
} satisfies Record<string, DiskState['state'][]>
158158

159-
export const diskCan = R.mapValues(diskActions, (states) => {
159+
export const diskCan = R.mapValues(diskActions, (states: DiskState['state'][]) => {
160160
// only have to Pick because we want this to work for both Disk and
161161
// Json<Disk>, which we pass to it in the MSW handlers
162162
const test = (d: Pick<Disk, 'state'>) => states.includes(d.state.state)

0 commit comments

Comments
 (0)