@@ -22,6 +22,7 @@ import { QuotaService } from '../services/quota.js'
2222import { createInMemoryQuotaApi } from '../services/quota.memory.js'
2323import { BillingService } from '../services/billing.js'
2424import { createInMemoryBillingApi } from '../services/billing.memory.js'
25+ import type { BillingApi } from '../services/billing.js'
2526import { AuditLog } from '../services/audit-log.js'
2627import { createInMemoryAuditLog } from '../services/audit-log.memory.js'
2728import { NodeRepo } from '../services/node-repo.js'
@@ -38,7 +39,7 @@ import type { NodeClientApi } from '../services/node-client.js'
3839const TEST_ORG = 'org_test_123'
3940const TEST_USER = 'user_test_456'
4041
41- function createTestEnv ( overrides ?: { nodeClient ?: NodeClientApi } ) {
42+ function createTestEnv ( overrides ?: { nodeClient ?: NodeClientApi ; billingApi ?: BillingApi } ) {
4243 const sandboxRepo = createInMemorySandboxRepo ( )
4344 const execRepo = createInMemoryExecRepo ( )
4445 const sessionRepo = createInMemorySessionRepo ( )
@@ -47,7 +48,7 @@ function createTestEnv(overrides?: { nodeClient?: NodeClientApi }) {
4748 const redis = createInMemoryRedisApi ( )
4849 const artifactRepo = createInMemoryArtifactRepo ( )
4950 const quotaApi = createInMemoryQuotaApi ( )
50- const billingApi = createInMemoryBillingApi ( )
51+ const billingApi = overrides ?. billingApi ?? createInMemoryBillingApi ( )
5152 const auditLog = createInMemoryAuditLog ( )
5253
5354 const TestLayer = AppLive . pipe (
@@ -560,6 +561,36 @@ describe.skipIf(!RUN_API_INTEGRATION_TESTS)('POST /v1/sandboxes — node daemon
560561 } )
561562} )
562563
564+ describe . skipIf ( ! RUN_API_INTEGRATION_TESTS ) ( 'POST /v1/sandboxes/:id/stop' , ( ) => {
565+ test ( 'returns 202 even if final billing metering fails' , async ( ) => {
566+ const baseBillingApi = createInMemoryBillingApi ( )
567+ const env = createTestEnv ( {
568+ billingApi : {
569+ ...baseBillingApi ,
570+ getBillingTier : ( ) => Effect . die ( new Error ( 'billing unavailable' ) ) ,
571+ trackCompute : ( ) => Effect . die ( new Error ( 'billing unavailable' ) ) ,
572+ } ,
573+ } )
574+
575+ const sandboxId = await createRunningSandbox ( env )
576+
577+ const result = await env . runTest (
578+ Effect . gen ( function * ( ) {
579+ const client = yield * HttpClient . HttpClient
580+ const response = yield * client . execute (
581+ HttpClientRequest . post ( `/v1/sandboxes/${ sandboxId } /stop` ) ,
582+ )
583+ const body = yield * response . json
584+ return { status : response . status , body : body as { sandbox_id : string ; status : string } }
585+ } ) ,
586+ )
587+
588+ expect ( result . status ) . toBe ( 202 )
589+ expect ( result . body . sandbox_id ) . toBe ( sandboxId )
590+ expect ( result . body . status ) . toBe ( 'stopping' )
591+ } )
592+ } )
593+
563594// ---------------------------------------------------------------------------
564595// Quota enforcement — create sandbox
565596// ---------------------------------------------------------------------------
0 commit comments