Skip to content

Commit db99a4d

Browse files
authored
Require message for mock API notFoundErr, add messages to all calls (#2293)
require message for mock API notFoundErr, add messages everywhere
1 parent 1f9ba6f commit db99a4d

File tree

3 files changed

+41
-43
lines changed

3 files changed

+41
-43
lines changed

app/api/__tests__/hooks.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ describe('useApiQuery', () => {
129129
const error = onError.mock.lastCall?.[0]
130130
expect(error).toEqual({
131131
errorCode: 'ObjectNotFound',
132-
message: 'Not found',
132+
message: "Not found: project 'nonexistent'",
133133
statusCode: 404,
134134
})
135135
})
@@ -207,7 +207,7 @@ describe('useApiMutation', () => {
207207

208208
expect(result.current.error).toEqual({
209209
errorCode: 'ObjectNotFound',
210-
message: 'Not found',
210+
message: "Not found: project 'nonexistent'",
211211
statusCode: 404,
212212
})
213213
})

mock-api/msw/db.ts

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import { internalError } from './util'
2121

2222
const notFoundBody = { error_code: 'ObjectNotFound' } as const
2323
export type NotFound = typeof notFoundBody
24-
export const notFoundErr = (msg?: string) => {
25-
const message = msg ? `not found: ${msg}` : 'not found'
24+
export const notFoundErr = (msg: string) => {
25+
const message = `not found: ${msg}`
2626
return json({ error_code: 'ObjectNotFound', message } as const, { status: 404 })
2727
}
2828

@@ -33,14 +33,14 @@ export const badSelectorErr = (resource: string, parents: string[]) => {
3333

3434
export const lookupById = <T extends { id: string }>(table: T[], id: string) => {
3535
const item = table.find((i) => i.id === id)
36-
if (!item) throw notFoundErr
36+
if (!item) throw notFoundErr(`by id ${id}`)
3737
return item
3838
}
3939

4040
export const getIpFromPool = (poolName: string | undefined) => {
4141
const pool = lookup.ipPool({ pool: poolName })
4242
const ipPoolRange = db.ipPoolRanges.find((range) => range.ip_pool_id === pool.id)
43-
if (!ipPoolRange) throw notFoundErr('IP pool range')
43+
if (!ipPoolRange) throw notFoundErr(`IP range for pool '${poolName}'`)
4444

4545
// right now, we're just using the first address in the range, but we'll
4646
// want to filter the list of available IPs for the first unused address
@@ -51,31 +51,31 @@ export const getIpFromPool = (poolName: string | undefined) => {
5151

5252
export const lookup = {
5353
project({ project: id }: PP.Project): Json<Api.Project> {
54-
if (!id) throw notFoundErr
54+
if (!id) throw notFoundErr('no project specified')
5555

5656
if (isUuid(id)) return lookupById(db.projects, id)
5757

5858
const project = db.projects.find((p) => p.name === id)
59-
if (!project) throw notFoundErr
59+
if (!project) throw notFoundErr(`project '${id}'`)
6060

6161
return project
6262
},
6363
instance({ instance: id, ...projectSelector }: PP.Instance): Json<Api.Instance> {
64-
if (!id) throw notFoundErr
64+
if (!id) throw notFoundErr('no instance specified')
6565

6666
if (isUuid(id)) return lookupById(db.instances, id)
6767

6868
const project = lookup.project(projectSelector)
6969
const instance = db.instances.find((i) => i.project_id === project.id && i.name === id)
70-
if (!instance) throw notFoundErr
70+
if (!instance) throw notFoundErr(`instance '${id}'`)
7171

7272
return instance
7373
},
7474
networkInterface({
7575
interface: id,
7676
...instanceSelector
7777
}: PP.NetworkInterface): Json<Api.InstanceNetworkInterface> {
78-
if (!id) throw notFoundErr
78+
if (!id) throw notFoundErr('no NIC specified')
7979

8080
if (isUuid(id)) return lookupById(db.networkInterfaces, id)
8181

@@ -84,24 +84,24 @@ export const lookup = {
8484
const nic = db.networkInterfaces.find(
8585
(n) => n.instance_id === instance.id && n.name === id
8686
)
87-
if (!nic) throw notFoundErr
87+
if (!nic) throw notFoundErr(`NIC '${id}'`)
8888

8989
return nic
9090
},
9191
disk({ disk: id, ...projectSelector }: PP.Disk): Json<Api.Disk> {
92-
if (!id) throw notFoundErr
92+
if (!id) throw notFoundErr('no disk specified')
9393

9494
if (isUuid(id)) return lookupById(db.disks, id)
9595

9696
const project = lookup.project(projectSelector)
9797

9898
const disk = db.disks.find((d) => d.project_id === project.id && d.name === id)
99-
if (!disk) throw notFoundErr
99+
if (!disk) throw notFoundErr(`disk '${id}'`)
100100

101101
return disk
102102
},
103103
floatingIp({ floatingIp: id, ...projectSelector }: PP.FloatingIp): Json<Api.FloatingIp> {
104-
if (!id) throw notFoundErr
104+
if (!id) throw notFoundErr('no floating IP specified')
105105

106106
if (isUuid(id)) {
107107
if (projectSelector.project) throw badSelectorErr('floating IP', ['project'])
@@ -112,45 +112,45 @@ export const lookup = {
112112
const floatingIp = db.floatingIps.find(
113113
(i) => i.project_id === project.id && i.name === id
114114
)
115-
if (!floatingIp) throw notFoundErr
115+
if (!floatingIp) throw notFoundErr(`floating IP '${id}'`)
116116

117117
return floatingIp
118118
},
119119
snapshot({ snapshot: id, ...projectSelector }: PP.Snapshot): Json<Api.Snapshot> {
120-
if (!id) throw notFoundErr
120+
if (!id) throw notFoundErr('no snapshot specified')
121121

122122
if (isUuid(id)) return lookupById(db.snapshots, id)
123123

124124
const project = lookup.project(projectSelector)
125125
const snapshot = db.snapshots.find((i) => i.project_id === project.id && i.name === id)
126-
if (!snapshot) throw notFoundErr
126+
if (!snapshot) throw notFoundErr(`snapshot '${id}'`)
127127

128128
return snapshot
129129
},
130130
vpc({ vpc: id, ...projectSelector }: PP.Vpc): Json<Api.Vpc> {
131-
if (!id) throw notFoundErr
131+
if (!id) throw notFoundErr('no VPC specified')
132132

133133
if (isUuid(id)) return lookupById(db.vpcs, id)
134134

135135
const project = lookup.project(projectSelector)
136136
const vpc = db.vpcs.find((v) => v.project_id === project.id && v.name === id)
137-
if (!vpc) throw notFoundErr
137+
if (!vpc) throw notFoundErr(`vpc '${id}'`)
138138

139139
return vpc
140140
},
141141
vpcSubnet({ subnet: id, ...vpcSelector }: PP.VpcSubnet): Json<Api.VpcSubnet> {
142-
if (!id) throw notFoundErr
142+
if (!id) throw notFoundErr('no subnet specified')
143143

144144
if (isUuid(id)) return lookupById(db.vpcSubnets, id)
145145

146146
const vpc = lookup.vpc(vpcSelector)
147147
const subnet = db.vpcSubnets.find((s) => s.vpc_id === vpc.id && s.name === id)
148-
if (!subnet) throw notFoundErr
148+
if (!subnet) throw notFoundErr(`subnet '${id}'`)
149149

150150
return subnet
151151
},
152152
image({ image: id, project: projectId }: PP.Image): Json<Api.Image> {
153-
if (!id) throw notFoundErr
153+
if (!id) throw notFoundErr('no image specified')
154154

155155
if (isUuid(id)) return lookupById(db.images, id)
156156

@@ -164,11 +164,11 @@ export const lookup = {
164164
image = db.images.find((d) => d.project_id === project.id && d.name === id)
165165
}
166166

167-
if (!image) throw notFoundErr
167+
if (!image) throw notFoundErr(`image '${id}'`)
168168
return image
169169
},
170170
ipPool({ pool: id }: PP.IpPool): Json<Api.IpPool> {
171-
if (!id) throw notFoundErr('Missing IP pool ID or name')
171+
if (!id) throw notFoundErr('no pool specified')
172172

173173
if (isUuid(id)) return lookupById(db.ipPools, id)
174174

@@ -188,7 +188,7 @@ export const lookup = {
188188
const ipPoolSilo = db.ipPoolSilos.find(
189189
(ips) => ips.ip_pool_id === pool.id && ips.silo_id === silo.id
190190
)
191-
if (!ipPoolSilo) throw notFoundErr
191+
if (!ipPoolSilo) throw notFoundErr(`link for pool '${poolId}' and silo '${siloId}'`)
192192

193193
return ipPoolSilo
194194
},
@@ -220,47 +220,45 @@ export const lookup = {
220220
const ipPoolSilo = db.ipPoolSilos.find(
221221
(ips) => ips.ip_pool_id === pool.id && ips.silo_id === silo.id
222222
)
223-
if (!ipPoolSilo) throw notFoundErr
223+
if (!ipPoolSilo) {
224+
throw notFoundErr(`link for pool '${path.pool}' and silo '${path.silo}'`)
225+
}
224226

225227
return { ...pool, is_default: ipPoolSilo.is_default }
226228
},
227229
siloDefaultIpPool(path: PP.Silo): Json<Api.IpPool> {
228230
const silo = lookup.silo(path)
229231

230232
const link = db.ipPoolSilos.find((ips) => ips.silo_id === silo.id && ips.is_default)
231-
if (!link) throw notFoundErr
233+
if (!link) throw notFoundErr(`default pool for silo '${path.silo}'`)
232234

233235
return lookupById(db.ipPools, link.ip_pool_id)
234236
},
235-
samlIdp({
236-
provider: id,
237-
...siloSelector
238-
}: PP.IdentityProvider): Json<Api.SamlIdentityProvider> {
239-
if (!id) throw notFoundErr
237+
samlIdp({ provider: id, silo }: PP.IdentityProvider): Json<Api.SamlIdentityProvider> {
238+
if (!id) throw notFoundErr('no IdP specified')
240239

241-
const silo = lookup.silo(siloSelector)
240+
const dbSilo = lookup.silo({ silo })
242241

243242
const dbIdp = db.identityProviders.find(
244243
({ type, siloId, provider }) =>
245-
type === 'saml' && siloId === silo.id && provider.name === id
244+
type === 'saml' && siloId === dbSilo.id && provider.name === id
246245
)
247246

248-
if (!dbIdp) throw notFoundErr
247+
if (!dbIdp) throw notFoundErr(`IdP '${id}' for silo '${silo}'`)
249248

250249
return dbIdp.provider
251250
},
252251
silo({ silo: id }: PP.Silo): Json<Api.Silo> {
253-
if (!id) throw notFoundErr
252+
if (!id) throw notFoundErr('silo not specified')
254253

255254
if (isUuid(id)) return lookupById(db.silos, id)
256255

257256
const silo = db.silos.find((o) => o.name === id)
258-
if (!silo) throw notFoundErr
257+
if (!silo) throw notFoundErr(`silo '${id}'`)
259258
return silo
260259
},
261260
sled({ sledId: id }: PP.Sled): Json<Api.Sled> {
262-
if (!id) throw notFoundErr
263-
261+
if (!id) throw notFoundErr('sled not specified')
264262
return lookupById(db.sleds, id)
265263
},
266264
sshKey({ sshKey: id }: PP.SshKey): Json<Api.SshKey> {
@@ -270,7 +268,7 @@ export const lookup = {
270268
if (isUuid(id)) return lookupById(userSshKeys, id)
271269

272270
const sshKey = userSshKeys.find((key) => key.name === id)
273-
if (!sshKey) throw notFoundErr
271+
if (!sshKey) throw notFoundErr(`SSH key '${id}'`)
274272
return sshKey
275273
},
276274
}

mock-api/msw/handlers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export const handlers = makeHandlers({
205205
diskBulkWriteImport: ({ path, query, body }) => {
206206
const disk = lookup.disk({ ...path, ...query })
207207
const diskImport = db.diskBulkImportState.get(disk.id)
208-
if (!diskImport) throw notFoundErr
208+
if (!diskImport) throw notFoundErr(`disk import for disk '${disk.id}'`)
209209
// if (Math.random() < 0.01) throw 400
210210
diskImport.blocks[body.offset] = true
211211
return 204
@@ -838,7 +838,7 @@ export const handlers = makeHandlers({
838838
.map((r) => r.id)
839839

840840
// if nothing in the DB matches, 404
841-
if (idsToDelete.length === 0) throw notFoundErr()
841+
if (idsToDelete.length === 0) throw notFoundErr(`IP range ${body.first}-${body.last}`)
842842

843843
db.ipPoolRanges = db.ipPoolRanges.filter((r) => !idsToDelete.includes(r.id))
844844

0 commit comments

Comments
 (0)