@highstate/backend 0.9.18 → 0.9.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OU5OQBLB.js → chunk-I7BWSAN6.js} +3 -28
- package/dist/{chunk-OU5OQBLB.js.map → chunk-I7BWSAN6.js.map} +1 -1
- package/dist/chunk-RC6Q3XQQ.js +1547 -0
- package/dist/chunk-RC6Q3XQQ.js.map +1 -0
- package/dist/chunk-VB4YL327.js +139 -0
- package/dist/chunk-VB4YL327.js.map +1 -0
- package/dist/database/local/prisma.config.js +26 -0
- package/dist/database/local/prisma.config.js.map +1 -0
- package/dist/highstate.manifest.json +2 -1
- package/dist/index.js +7590 -7289
- package/dist/index.js.map +1 -1
- package/dist/library/package-resolution-worker.js +1 -1
- package/dist/library/package-resolution-worker.js.map +1 -1
- package/dist/library/worker/main.js +35 -29
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +2 -2
- package/package.json +18 -9
- package/prisma/backend/_schema/layout.prisma +7 -0
- package/prisma/backend/_schema/library.prisma +17 -0
- package/prisma/backend/_schema/project.prisma +101 -0
- package/prisma/backend/_schema/pulumi.prisma +17 -0
- package/prisma/backend/postgresql/main.prisma +17 -0
- package/prisma/backend/sqlite/main.prisma +17 -0
- package/prisma/backend/sqlite/migrations/20250817070609_initiial/migration.sql +34 -0
- package/prisma/backend/sqlite/migrations/20250817104948_add_fields/migration.sql +59 -0
- package/prisma/backend/sqlite/migrations/20250818082732_add_models/migration.sql +41 -0
- package/prisma/backend/sqlite/migrations/20250818083106_a/migration.sql +19 -0
- package/prisma/backend/sqlite/migrations/20250818101945_hi/migration.sql +1 -0
- package/prisma/backend/sqlite/migrations/20250819082315_a/migration.sql +5 -0
- package/prisma/backend/sqlite/migrations/migration_lock.toml +3 -0
- package/prisma/project/api-key.prisma +32 -0
- package/prisma/project/artifact.prisma +52 -0
- package/prisma/project/custom-status.prisma +46 -0
- package/prisma/project/evaluation.prisma +45 -0
- package/prisma/project/instance.prisma +157 -0
- package/prisma/project/layout.prisma +23 -0
- package/prisma/project/lock.prisma +18 -0
- package/prisma/project/main.prisma +17 -0
- package/prisma/project/migrations/20250816081310_initial/migration.sql +300 -0
- package/prisma/project/migrations/20250816082523_test/migration.sql +72 -0
- package/prisma/project/migrations/20250818065643_update/migration.sql +42 -0
- package/prisma/project/migrations/20250818070758_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818070913_a/migration.sql +8 -0
- package/prisma/project/migrations/20250818082720_add_motels/migration.sql +11 -0
- package/prisma/project/migrations/20250818112523_hello/migration.sql +35 -0
- package/prisma/project/migrations/20250819082305_a/migration.sql +14 -0
- package/prisma/project/migrations/20250819165004_add_missing_fields/migration.sql +216 -0
- package/prisma/project/migrations/20250819171309_a/migration.sql +22 -0
- package/prisma/project/migrations/20250820113949_a/migration.sql +66 -0
- package/prisma/project/migrations/20250820144256_b/migration.sql +31 -0
- package/prisma/project/migrations/20250820145547_a/migration.sql +24 -0
- package/prisma/project/migrations/20250820182517_b/migration.sql +2 -0
- package/prisma/project/migrations/20250821172324_a/migration.sql +2 -0
- package/prisma/project/migrations/20250822081339_a/migration.sql +219 -0
- package/prisma/project/migrations/20250822083742_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822105134_boom/migration.sql +1 -0
- package/prisma/project/migrations/20250822141028_b/migration.sql +1 -0
- package/prisma/project/migrations/20250822142342_b/migration.sql +16 -0
- package/prisma/project/migrations/20250824072720_a/migration.sql +1 -0
- package/prisma/project/migrations/20250824093656_b/migration.sql +21 -0
- package/prisma/project/migrations/20250825082518_a/migration.sql +1 -0
- package/prisma/project/migrations/20250825085343_b/migration.sql +1 -0
- package/prisma/project/migrations/20250825091312_a/migration.sql +1 -0
- package/prisma/project/migrations/20250903095431_hi/migration.sql +44 -0
- package/prisma/project/migrations/20250903174255_a/migration.sql +24 -0
- package/prisma/project/migrations/20250908095205_hi/migration.sql +18 -0
- package/prisma/project/migrations/20250909155857_hi/migration.sql +15 -0
- package/prisma/project/migrations/migration_lock.toml +3 -0
- package/prisma/project/model.prisma +37 -0
- package/prisma/project/operation.prisma +148 -0
- package/prisma/project/page.prisma +49 -0
- package/prisma/project/secret.prisma +54 -0
- package/prisma/project/service-account.prisma +42 -0
- package/prisma/project/terminal.prisma +107 -0
- package/prisma/project/trigger.prisma +37 -0
- package/prisma/project/unlock-method.prisma +46 -0
- package/prisma/project/worker.prisma +169 -0
- package/src/artifact/abstractions.ts +13 -13
- package/src/artifact/encryption.ts +30 -54
- package/src/artifact/factory.ts +6 -9
- package/src/artifact/local.ts +33 -46
- package/src/business/api-key.ts +24 -36
- package/src/business/artifact.test.ts +978 -0
- package/src/business/artifact.ts +136 -216
- package/src/business/evaluation.ts +328 -0
- package/src/business/index.ts +5 -2
- package/src/business/instance-lock.test.ts +1060 -0
- package/src/business/instance-lock.ts +387 -78
- package/src/business/instance-state.test.ts +735 -0
- package/src/business/instance-state.ts +582 -337
- package/src/business/operation.test.ts +439 -0
- package/src/business/operation.ts +174 -208
- package/src/business/project-model.ts +258 -0
- package/src/business/project-unlock.ts +168 -126
- package/src/business/project.ts +287 -179
- package/src/business/secret.test.ts +469 -130
- package/src/business/secret.ts +177 -217
- package/src/business/settings.test.ts +695 -0
- package/src/business/settings.ts +855 -0
- package/src/business/terminal-session.ts +90 -0
- package/src/business/unit-extra.test.ts +539 -0
- package/src/business/unit-extra.ts +160 -0
- package/src/business/worker.test.ts +356 -579
- package/src/business/worker.ts +238 -339
- package/src/common/codebase.ts +65 -0
- package/src/common/index.ts +3 -5
- package/src/common/logger.ts +5 -0
- package/src/common/utils.ts +4 -3
- package/src/config.ts +10 -11
- package/src/database/_generated/backend/postgresql/client.ts +72 -0
- package/src/database/_generated/backend/postgresql/commonInputTypes.ts +350 -0
- package/src/database/_generated/backend/postgresql/enums.ts +13 -0
- package/src/database/_generated/backend/postgresql/internal/class.ts +320 -0
- package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +1238 -0
- package/src/database/_generated/backend/postgresql/models/Library.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/Project.ts +2175 -0
- package/src/database/_generated/backend/postgresql/models/ProjectModelStorage.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/ProjectSpace.ts +1602 -0
- package/src/database/_generated/backend/postgresql/models/PulumiBackend.ts +1263 -0
- package/src/database/_generated/backend/postgresql/models/UserWorkspaseLayout.ts +1065 -0
- package/src/database/_generated/backend/postgresql/models.ts +16 -0
- package/src/database/_generated/backend/postgresql/pjtg.ts +182 -0
- package/src/database/_generated/backend/sqlite/client.ts +72 -0
- package/src/database/_generated/backend/sqlite/commonInputTypes.ts +331 -0
- package/src/database/_generated/backend/sqlite/enums.ts +13 -0
- package/src/database/_generated/backend/sqlite/internal/class.ts +318 -0
- package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +1207 -0
- package/src/database/_generated/backend/sqlite/models/Library.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/Project.ts +2169 -0
- package/src/database/_generated/backend/sqlite/models/ProjectModelStorage.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/ProjectSpace.ts +1599 -0
- package/src/database/_generated/backend/sqlite/models/PulumiBackend.ts +1261 -0
- package/src/database/_generated/backend/sqlite/models/UserWorkspaseLayout.ts +1063 -0
- package/src/database/_generated/backend/sqlite/models.ts +16 -0
- package/src/database/_generated/backend/sqlite/pjtg.ts +182 -0
- package/src/database/_generated/project/client.ts +204 -0
- package/src/database/_generated/project/commonInputTypes.ts +827 -0
- package/src/database/_generated/project/enums.ts +104 -0
- package/src/database/_generated/project/internal/class.ts +479 -0
- package/src/database/_generated/project/internal/prismaNamespace.ts +2974 -0
- package/src/database/_generated/project/models/ApiKey.ts +1506 -0
- package/src/database/_generated/project/models/Artifact.ts +2051 -0
- package/src/database/_generated/project/models/HubModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceCustomStatus.ts +1713 -0
- package/src/database/_generated/project/models/InstanceEvaluationState.ts +1312 -0
- package/src/database/_generated/project/models/InstanceLock.ts +1268 -0
- package/src/database/_generated/project/models/InstanceModel.ts +1125 -0
- package/src/database/_generated/project/models/InstanceOperationState.ts +1707 -0
- package/src/database/_generated/project/models/InstanceState.ts +4613 -0
- package/src/database/_generated/project/models/Operation.ts +1647 -0
- package/src/database/_generated/project/models/OperationLog.ts +1455 -0
- package/src/database/_generated/project/models/Page.ts +1838 -0
- package/src/database/_generated/project/models/Secret.ts +1692 -0
- package/src/database/_generated/project/models/ServiceAccount.ts +2165 -0
- package/src/database/_generated/project/models/Terminal.ts +2038 -0
- package/src/database/_generated/project/models/TerminalSession.ts +1454 -0
- package/src/database/_generated/project/models/TerminalSessionLog.ts +1280 -0
- package/src/database/_generated/project/models/Trigger.ts +1430 -0
- package/src/database/_generated/project/models/UnlockMethod.ts +1220 -0
- package/src/database/_generated/project/models/UserCompositeViewport.ts +1280 -0
- package/src/database/_generated/project/models/UserProjectViewport.ts +1059 -0
- package/src/database/_generated/project/models/Worker.ts +1459 -0
- package/src/database/_generated/project/models/WorkerUnitRegistration.ts +1524 -0
- package/src/database/_generated/project/models/WorkerVersion.ts +1974 -0
- package/src/database/_generated/project/models/WorkerVersionLog.ts +1318 -0
- package/src/database/_generated/project/models.ts +35 -0
- package/src/database/_generated/project/pjtg.ts +182 -0
- package/src/database/abstractions.ts +19 -0
- package/src/database/factory.ts +37 -0
- package/src/database/index.ts +6 -0
- package/src/database/local/backend.ts +134 -0
- package/src/database/local/index.ts +3 -0
- package/src/database/local/meta.ts +46 -0
- package/src/database/local/prisma.config.ts +25 -0
- package/src/database/local/project.ts +39 -0
- package/src/database/manager.ts +181 -0
- package/src/database/migrate.ts +35 -0
- package/src/database/prisma.ts +56 -0
- package/src/database/well-known.ts +38 -0
- package/src/index.ts +4 -4
- package/src/library/abstractions.ts +3 -5
- package/src/library/factory.ts +1 -1
- package/src/library/local.ts +81 -26
- package/src/library/package-resolution-worker.ts +1 -1
- package/src/library/worker/evaluator.ts +40 -23
- package/src/library/worker/loader.lite.ts +1 -1
- package/src/library/worker/main.ts +3 -10
- package/src/library/worker/protocol.ts +0 -1
- package/src/lock/index.ts +0 -1
- package/src/lock/manager.ts +0 -10
- package/src/orchestrator/manager.ts +190 -104
- package/src/orchestrator/operation-context.ts +357 -0
- package/src/orchestrator/operation-plan.destroy.test.md +357 -0
- package/src/orchestrator/operation-plan.destroy.test.ts +775 -0
- package/src/orchestrator/operation-plan.fixtures.ts +213 -0
- package/src/orchestrator/operation-plan.md +198 -0
- package/src/orchestrator/operation-plan.refresh.test.md +199 -0
- package/src/orchestrator/operation-plan.refresh.test.ts +367 -0
- package/src/orchestrator/operation-plan.ts +709 -0
- package/src/orchestrator/operation-plan.update.test.md +485 -0
- package/src/orchestrator/operation-plan.update.test.ts +1066 -0
- package/src/orchestrator/operation-workset.ts +233 -578
- package/src/orchestrator/operation.ts +440 -948
- package/src/orchestrator/plan-test-builder.ts +267 -0
- package/src/project-model/abstractions.ts +118 -0
- package/src/project-model/backends/codebase.ts +365 -0
- package/src/project-model/backends/database.ts +440 -0
- package/src/project-model/errors.ts +81 -0
- package/src/project-model/factory.ts +24 -0
- package/src/project-model/index.ts +4 -0
- package/src/project-model/utils.test.ts +544 -0
- package/src/project-model/utils.ts +242 -0
- package/src/pubsub/abstractions.ts +10 -1
- package/src/pubsub/factory.ts +4 -4
- package/src/pubsub/index.ts +1 -0
- package/src/pubsub/manager.ts +29 -13
- package/src/pubsub/memory.ts +31 -0
- package/src/runner/abstractions.ts +40 -41
- package/src/runner/artifact-env.ts +19 -8
- package/src/runner/factory.ts +6 -6
- package/src/runner/force-abort.ts +3 -6
- package/src/runner/local.ts +74 -67
- package/src/runner/pulumi.ts +23 -63
- package/src/services.ts +181 -123
- package/src/shared/models/backend/index.ts +3 -1
- package/src/shared/models/backend/library.ts +9 -1
- package/src/shared/models/backend/project.ts +43 -42
- package/src/shared/models/backend/pulumi.ts +14 -0
- package/src/shared/models/backend/unlock-method.ts +1 -1
- package/src/shared/models/backend/well-known.ts +58 -0
- package/src/shared/models/base.ts +40 -26
- package/src/shared/models/errors.ts +82 -1
- package/src/shared/models/index.ts +3 -2
- package/src/shared/models/prisma.ts +36 -0
- package/src/shared/models/project/api-key.ts +37 -59
- package/src/shared/models/project/artifact.ts +16 -76
- package/src/shared/models/project/custom-status.ts +12 -0
- package/src/shared/models/project/index.ts +8 -7
- package/src/shared/models/project/lock.ts +10 -78
- package/src/shared/models/project/model.ts +19 -1
- package/src/shared/models/project/operation.ts +235 -99
- package/src/shared/models/project/page.ts +37 -48
- package/src/shared/models/project/secret.ts +29 -89
- package/src/shared/models/project/service-account.ts +12 -17
- package/src/shared/models/project/state.ts +100 -407
- package/src/shared/models/project/terminal.ts +75 -88
- package/src/shared/models/project/trigger.ts +13 -49
- package/src/shared/models/project/unlock-method.ts +20 -26
- package/src/shared/models/project/worker.ts +89 -90
- package/src/shared/resolvers/graph-resolver.ts +21 -0
- package/src/shared/resolvers/index.ts +1 -1
- package/src/shared/resolvers/input-hash.ts +24 -14
- package/src/shared/resolvers/input.ts +9 -2
- package/src/shared/resolvers/registry.ts +5 -4
- package/src/shared/resolvers/state.ts +12 -1
- package/src/shared/resolvers/validation.ts +7 -3
- package/src/shared/utils/index.ts +1 -2
- package/src/shared/utils/promise-tracker.ts +30 -3
- package/src/terminal/abstractions.ts +1 -1
- package/src/terminal/docker.ts +3 -3
- package/src/terminal/manager.ts +102 -118
- package/src/test-utils/database.ts +119 -0
- package/src/test-utils/index.ts +2 -0
- package/src/test-utils/services.ts +134 -0
- package/src/unlock/abstractions.ts +5 -23
- package/src/unlock/memory.ts +9 -14
- package/src/worker/abstractions.ts +7 -4
- package/src/worker/docker.ts +14 -19
- package/src/worker/manager.ts +366 -97
- package/dist/chunk-NAAIDR4U.js +0 -8499
- package/dist/chunk-NAAIDR4U.js.map +0 -1
- package/dist/chunk-Y7DXREVO.js +0 -1745
- package/dist/chunk-Y7DXREVO.js.map +0 -1
- package/dist/magic-string.es-5ABAC4JN.js +0 -1292
- package/dist/magic-string.es-5ABAC4JN.js.map +0 -1
- package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +0 -356
- package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +0 -274
- package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +0 -223
- package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +0 -147
- package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +0 -280
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +0 -360
- package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +0 -215
- package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +0 -427
- package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +0 -217
- package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +0 -132
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +0 -454
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +0 -426
- package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +0 -372
- package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +0 -383
- package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +0 -245
- package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +0 -174
- package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +0 -432
- package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +0 -220
- package/src/business/backend-unlock.ts +0 -10
- package/src/common/clock.ts +0 -18
- package/src/common/performance.ts +0 -44
- package/src/common/random.ts +0 -68
- package/src/common/test/index.ts +0 -2
- package/src/common/test/render.ts +0 -98
- package/src/common/test/tracer.ts +0 -359
- package/src/hotstate/abstractions.ts +0 -48
- package/src/hotstate/factory.ts +0 -17
- package/src/hotstate/index.ts +0 -3
- package/src/hotstate/manager.ts +0 -192
- package/src/hotstate/memory.ts +0 -100
- package/src/hotstate/validation.ts +0 -100
- package/src/lock/test.ts +0 -108
- package/src/project/abstractions.ts +0 -78
- package/src/project/evaluation.ts +0 -248
- package/src/project/factory.ts +0 -11
- package/src/project/index.ts +0 -3
- package/src/project/local.ts +0 -417
- package/src/pubsub/local.ts +0 -36
- package/src/pubsub/validation.ts +0 -33
- package/src/shared/utils/args.ts +0 -25
- package/src/state/abstractions.ts +0 -289
- package/src/state/encryption.ts +0 -98
- package/src/state/factory.ts +0 -20
- package/src/state/index.ts +0 -7
- package/src/state/local/backend.ts +0 -106
- package/src/state/local/collection.ts +0 -361
- package/src/state/local/index.ts +0 -2
- package/src/state/manager.ts +0 -890
- package/src/state/memory/backend.ts +0 -70
- package/src/state/memory/collection.ts +0 -270
- package/src/state/memory/index.ts +0 -2
- package/src/state/repository/index.ts +0 -2
- package/src/state/repository/repository.index.ts +0 -193
- package/src/state/repository/repository.ts +0 -507
- package/src/state/test.ts +0 -457
- /package/src/{state → database/local}/keyring.ts +0 -0
|
@@ -0,0 +1,735 @@
|
|
|
1
|
+
import type { InstanceId, InstanceModel } from "@highstate/contract"
|
|
2
|
+
import type { ArtifactService } from "../artifact"
|
|
3
|
+
import type { PubSubManager } from "../pubsub"
|
|
4
|
+
import type { RunnerBackend } from "../runner"
|
|
5
|
+
import type { ProjectService } from "./project"
|
|
6
|
+
import type { SecretService } from "./secret"
|
|
7
|
+
import type { UnitExtraService } from "./unit-extra"
|
|
8
|
+
import type { WorkerService } from "./worker"
|
|
9
|
+
import { parseInstanceId } from "@highstate/contract"
|
|
10
|
+
import { createId } from "@paralleldrive/cuid2"
|
|
11
|
+
import { describe, type MockedObject, vi } from "vitest"
|
|
12
|
+
import { InstanceLockedError, InstanceStateNotFoundError } from "../shared"
|
|
13
|
+
import { test } from "../test-utils"
|
|
14
|
+
import { InstanceStateService } from "./instance-state"
|
|
15
|
+
|
|
16
|
+
const instanceStateTest = test.extend<{
|
|
17
|
+
pubsubManager: MockedObject<PubSubManager>
|
|
18
|
+
projectService: MockedObject<ProjectService>
|
|
19
|
+
runnerBackend: MockedObject<RunnerBackend>
|
|
20
|
+
workerService: MockedObject<WorkerService>
|
|
21
|
+
artifactService: MockedObject<ArtifactService>
|
|
22
|
+
unitExtraService: MockedObject<UnitExtraService>
|
|
23
|
+
secretService: MockedObject<SecretService>
|
|
24
|
+
instanceStateService: InstanceStateService
|
|
25
|
+
}>({
|
|
26
|
+
pubsubManager: async ({}, use) => {
|
|
27
|
+
const pubsubManager = vi.mockObject({
|
|
28
|
+
publish: vi.fn().mockResolvedValue(undefined),
|
|
29
|
+
subscribe: vi.fn(),
|
|
30
|
+
publishMany: vi.fn().mockResolvedValue(undefined),
|
|
31
|
+
} as unknown as PubSubManager)
|
|
32
|
+
|
|
33
|
+
await use(pubsubManager)
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
projectService: async ({}, use) => {
|
|
37
|
+
const projectService = vi.mockObject({
|
|
38
|
+
getProjectOrThrow: vi.fn(),
|
|
39
|
+
} as unknown as ProjectService)
|
|
40
|
+
|
|
41
|
+
await use(projectService)
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
runnerBackend: async ({}, use) => {
|
|
45
|
+
const runnerBackend = vi.mockObject({
|
|
46
|
+
deleteState: vi.fn().mockResolvedValue(undefined),
|
|
47
|
+
} as unknown as RunnerBackend)
|
|
48
|
+
|
|
49
|
+
await use(runnerBackend)
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
workerService: async ({}, use) => {
|
|
53
|
+
const workerService = vi.mockObject({
|
|
54
|
+
cleanupWorkerUsageAndSync: vi.fn().mockResolvedValue(undefined),
|
|
55
|
+
} as unknown as WorkerService)
|
|
56
|
+
|
|
57
|
+
await use(workerService)
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
artifactService: async ({}, use) => {
|
|
61
|
+
const artifactService = vi.mockObject({
|
|
62
|
+
collectGarbage: vi.fn().mockResolvedValue(undefined),
|
|
63
|
+
} as unknown as ArtifactService)
|
|
64
|
+
|
|
65
|
+
await use(artifactService)
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
unitExtraService: async ({}, use) => {
|
|
69
|
+
const unitExtraService = vi.mockObject({} as unknown as UnitExtraService)
|
|
70
|
+
await use(unitExtraService)
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
secretService: async ({}, use) => {
|
|
74
|
+
const secretService = vi.mockObject({} as unknown as SecretService)
|
|
75
|
+
await use(secretService)
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
instanceStateService: async (
|
|
79
|
+
{
|
|
80
|
+
database,
|
|
81
|
+
pubsubManager,
|
|
82
|
+
runnerBackend,
|
|
83
|
+
workerService,
|
|
84
|
+
artifactService,
|
|
85
|
+
unitExtraService,
|
|
86
|
+
secretService,
|
|
87
|
+
logger,
|
|
88
|
+
},
|
|
89
|
+
use,
|
|
90
|
+
) => {
|
|
91
|
+
const service = new InstanceStateService(
|
|
92
|
+
database,
|
|
93
|
+
pubsubManager,
|
|
94
|
+
runnerBackend,
|
|
95
|
+
workerService,
|
|
96
|
+
artifactService,
|
|
97
|
+
unitExtraService,
|
|
98
|
+
secretService,
|
|
99
|
+
logger.child({ service: "InstanceStateService" }),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
await use(service)
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe("getInstanceStates", () => {
|
|
107
|
+
instanceStateTest(
|
|
108
|
+
"successfully retrieves instance states",
|
|
109
|
+
async ({ instanceStateService, project, createInstanceState, expect }) => {
|
|
110
|
+
// arrange
|
|
111
|
+
const instanceState1 = await createInstanceState(project.id)
|
|
112
|
+
const instanceState2 = await createInstanceState(project.id)
|
|
113
|
+
|
|
114
|
+
// act
|
|
115
|
+
const instanceStates = await instanceStateService.getInstanceStates(project.id)
|
|
116
|
+
|
|
117
|
+
// assert
|
|
118
|
+
expect(instanceStates).toHaveLength(2)
|
|
119
|
+
expect(instanceStates.map(i => i.id)).toEqual([instanceState1.id, instanceState2.id])
|
|
120
|
+
expect(instanceStates[0].secretNames).toEqual([])
|
|
121
|
+
expect(instanceStates[0].lastOperationState).toBeUndefined()
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
instanceStateTest(
|
|
126
|
+
"includes evaluation states when requested",
|
|
127
|
+
async ({ instanceStateService, projectDatabase, project, createInstanceState, expect }) => {
|
|
128
|
+
// arrange
|
|
129
|
+
const instanceState = await createInstanceState(project.id)
|
|
130
|
+
|
|
131
|
+
await projectDatabase.instanceEvaluationState.create({
|
|
132
|
+
data: {
|
|
133
|
+
stateId: instanceState.id,
|
|
134
|
+
status: "evaluated",
|
|
135
|
+
model: {
|
|
136
|
+
id: "test.v1:example",
|
|
137
|
+
kind: "unit",
|
|
138
|
+
type: "test.v1",
|
|
139
|
+
name: "example",
|
|
140
|
+
args: {},
|
|
141
|
+
inputs: {},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// act
|
|
147
|
+
const instanceStates = await instanceStateService.getInstanceStates(project.id, {
|
|
148
|
+
includeEvaluationState: true,
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// assert
|
|
152
|
+
const instanceWithEvaluation = instanceStates.find(state => state.id === instanceState.id)
|
|
153
|
+
expect(instanceWithEvaluation).toBeDefined()
|
|
154
|
+
expect(instanceWithEvaluation?.evaluationState).toBeDefined()
|
|
155
|
+
expect(instanceWithEvaluation?.evaluationState?.status).toBe("evaluated")
|
|
156
|
+
},
|
|
157
|
+
)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
describe("forgetInstanceState", () => {
|
|
161
|
+
instanceStateTest(
|
|
162
|
+
"successfully deletes instance with no operation state",
|
|
163
|
+
async ({
|
|
164
|
+
instanceStateService,
|
|
165
|
+
projectDatabase,
|
|
166
|
+
project,
|
|
167
|
+
createInstanceState,
|
|
168
|
+
projectService,
|
|
169
|
+
pubsubManager,
|
|
170
|
+
workerService,
|
|
171
|
+
artifactService,
|
|
172
|
+
expect,
|
|
173
|
+
}) => {
|
|
174
|
+
// arrange
|
|
175
|
+
const instanceState = await createInstanceState(project.id)
|
|
176
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
177
|
+
|
|
178
|
+
// act
|
|
179
|
+
await instanceStateService.forgetInstanceState(
|
|
180
|
+
project.id,
|
|
181
|
+
instanceState.instanceId as InstanceId,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
// assert
|
|
185
|
+
const updatedState = await projectDatabase.instanceState.findUnique({
|
|
186
|
+
where: { id: instanceState.id },
|
|
187
|
+
})
|
|
188
|
+
expect(updatedState?.status).toBe("undeployed")
|
|
189
|
+
expect(updatedState?.statusFields).toBeNull()
|
|
190
|
+
expect(updatedState?.inputHash).toBeNull()
|
|
191
|
+
expect(updatedState?.outputHash).toBeNull()
|
|
192
|
+
expect(updatedState?.dependencyOutputHash).toBeNull()
|
|
193
|
+
|
|
194
|
+
// verify side effects were called
|
|
195
|
+
expect(workerService.cleanupWorkerUsageAndSync).toHaveBeenCalledWith(project.id)
|
|
196
|
+
expect(artifactService.collectGarbage).toHaveBeenCalledWith(project.id)
|
|
197
|
+
expect(pubsubManager.publish).toHaveBeenCalledWith(
|
|
198
|
+
["instance-state", project.id],
|
|
199
|
+
expect.objectContaining({
|
|
200
|
+
type: "patched",
|
|
201
|
+
stateId: instanceState.id,
|
|
202
|
+
patch: expect.objectContaining({
|
|
203
|
+
status: "undeployed",
|
|
204
|
+
}),
|
|
205
|
+
}),
|
|
206
|
+
)
|
|
207
|
+
},
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
instanceStateTest(
|
|
211
|
+
"successfully deletes instance with destroyed operation state",
|
|
212
|
+
async ({
|
|
213
|
+
instanceStateService,
|
|
214
|
+
projectDatabase,
|
|
215
|
+
project,
|
|
216
|
+
createInstanceState,
|
|
217
|
+
projectService,
|
|
218
|
+
expect,
|
|
219
|
+
}) => {
|
|
220
|
+
// arrange
|
|
221
|
+
const instanceState = await createInstanceState(project.id)
|
|
222
|
+
|
|
223
|
+
// create operation with destroyed status
|
|
224
|
+
const operationId = createId()
|
|
225
|
+
await projectDatabase.operation.create({
|
|
226
|
+
data: {
|
|
227
|
+
id: operationId,
|
|
228
|
+
meta: { title: "Test Operation" },
|
|
229
|
+
type: "destroy",
|
|
230
|
+
options: {},
|
|
231
|
+
requestedInstanceIds: [instanceState.instanceId],
|
|
232
|
+
startedAt: new Date(),
|
|
233
|
+
},
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
await projectDatabase.instanceOperationState.create({
|
|
237
|
+
data: {
|
|
238
|
+
operationId,
|
|
239
|
+
stateId: instanceState.id,
|
|
240
|
+
status: "updated",
|
|
241
|
+
model: {} as InstanceModel,
|
|
242
|
+
resolvedInputs: {},
|
|
243
|
+
},
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
247
|
+
|
|
248
|
+
// act
|
|
249
|
+
await instanceStateService.forgetInstanceState(
|
|
250
|
+
project.id,
|
|
251
|
+
instanceState.instanceId as InstanceId,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
// assert
|
|
255
|
+
const updatedState = await projectDatabase.instanceState.findUnique({
|
|
256
|
+
where: { id: instanceState.id },
|
|
257
|
+
})
|
|
258
|
+
expect(updatedState?.status).toBe("undeployed")
|
|
259
|
+
},
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
instanceStateTest(
|
|
263
|
+
"successfully deletes instance with active operation state",
|
|
264
|
+
async ({
|
|
265
|
+
instanceStateService,
|
|
266
|
+
projectDatabase,
|
|
267
|
+
project,
|
|
268
|
+
createInstanceState,
|
|
269
|
+
projectService,
|
|
270
|
+
expect,
|
|
271
|
+
}) => {
|
|
272
|
+
// arrange
|
|
273
|
+
const instanceState = await createInstanceState(project.id)
|
|
274
|
+
|
|
275
|
+
// create operation with pending status
|
|
276
|
+
const operationId = createId()
|
|
277
|
+
await projectDatabase.operation.create({
|
|
278
|
+
data: {
|
|
279
|
+
id: operationId,
|
|
280
|
+
meta: { title: "Test Operation" },
|
|
281
|
+
type: "update",
|
|
282
|
+
options: {},
|
|
283
|
+
requestedInstanceIds: [instanceState.instanceId],
|
|
284
|
+
startedAt: new Date(),
|
|
285
|
+
},
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
await projectDatabase.instanceOperationState.create({
|
|
289
|
+
data: {
|
|
290
|
+
operationId,
|
|
291
|
+
stateId: instanceState.id,
|
|
292
|
+
status: "updating",
|
|
293
|
+
model: {} as InstanceModel,
|
|
294
|
+
resolvedInputs: {},
|
|
295
|
+
},
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
299
|
+
|
|
300
|
+
// act
|
|
301
|
+
await instanceStateService.forgetInstanceState(
|
|
302
|
+
project.id,
|
|
303
|
+
instanceState.instanceId as InstanceId,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
// assert
|
|
307
|
+
const updatedState = await projectDatabase.instanceState.findUnique({
|
|
308
|
+
where: { id: instanceState.id },
|
|
309
|
+
})
|
|
310
|
+
expect(updatedState?.status).toBe("undeployed")
|
|
311
|
+
},
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
instanceStateTest(
|
|
315
|
+
"throws error when instance has active locks",
|
|
316
|
+
async ({
|
|
317
|
+
instanceStateService,
|
|
318
|
+
projectDatabase,
|
|
319
|
+
project,
|
|
320
|
+
createInstanceState,
|
|
321
|
+
projectService,
|
|
322
|
+
expect,
|
|
323
|
+
}) => {
|
|
324
|
+
// arrange
|
|
325
|
+
const instanceState = await createInstanceState(project.id)
|
|
326
|
+
|
|
327
|
+
await projectDatabase.instanceLock.create({
|
|
328
|
+
data: {
|
|
329
|
+
stateId: instanceState.id,
|
|
330
|
+
token: "test-lock-token",
|
|
331
|
+
meta: { title: "Test Lock" },
|
|
332
|
+
},
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
336
|
+
|
|
337
|
+
// act & assert
|
|
338
|
+
await expect(
|
|
339
|
+
instanceStateService.forgetInstanceState(
|
|
340
|
+
project.id,
|
|
341
|
+
instanceState.instanceId as InstanceId,
|
|
342
|
+
),
|
|
343
|
+
).rejects.toThrow(InstanceLockedError)
|
|
344
|
+
},
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
instanceStateTest(
|
|
348
|
+
"handles terminal data when clearTerminalData=true",
|
|
349
|
+
async ({
|
|
350
|
+
instanceStateService,
|
|
351
|
+
projectDatabase,
|
|
352
|
+
project,
|
|
353
|
+
createInstanceState,
|
|
354
|
+
projectService,
|
|
355
|
+
expect,
|
|
356
|
+
}) => {
|
|
357
|
+
// arrange
|
|
358
|
+
const instanceState = await createInstanceState(project.id)
|
|
359
|
+
|
|
360
|
+
// create service account for terminal
|
|
361
|
+
const serviceAccount = await projectDatabase.serviceAccount.create({
|
|
362
|
+
data: {
|
|
363
|
+
id: createId(),
|
|
364
|
+
meta: { title: "Test Service Account" },
|
|
365
|
+
},
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
await projectDatabase.terminal.create({
|
|
369
|
+
data: {
|
|
370
|
+
id: createId(),
|
|
371
|
+
stateId: instanceState.id,
|
|
372
|
+
name: "test-terminal",
|
|
373
|
+
serviceAccountId: serviceAccount.id,
|
|
374
|
+
meta: { title: "Test Terminal" },
|
|
375
|
+
status: "active",
|
|
376
|
+
spec: { image: "test:latest" },
|
|
377
|
+
},
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
381
|
+
|
|
382
|
+
// act
|
|
383
|
+
await instanceStateService.forgetInstanceState(
|
|
384
|
+
project.id,
|
|
385
|
+
instanceState.instanceId as InstanceId,
|
|
386
|
+
{
|
|
387
|
+
clearTerminalData: true,
|
|
388
|
+
},
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
// assert
|
|
392
|
+
const terminals = await projectDatabase.terminal.findMany({
|
|
393
|
+
where: { stateId: instanceState.id },
|
|
394
|
+
})
|
|
395
|
+
expect(terminals).toHaveLength(0)
|
|
396
|
+
},
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
instanceStateTest(
|
|
400
|
+
"marks terminals as unavailable when clearTerminalData=false",
|
|
401
|
+
async ({
|
|
402
|
+
instanceStateService,
|
|
403
|
+
projectDatabase,
|
|
404
|
+
project,
|
|
405
|
+
createInstanceState,
|
|
406
|
+
projectService,
|
|
407
|
+
expect,
|
|
408
|
+
}) => {
|
|
409
|
+
// arrange
|
|
410
|
+
const instanceState = await createInstanceState(project.id)
|
|
411
|
+
|
|
412
|
+
// create service account for terminal
|
|
413
|
+
const serviceAccount = await projectDatabase.serviceAccount.create({
|
|
414
|
+
data: {
|
|
415
|
+
id: createId(),
|
|
416
|
+
meta: { title: "Test Service Account" },
|
|
417
|
+
},
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
const terminalId = createId()
|
|
421
|
+
await projectDatabase.terminal.create({
|
|
422
|
+
data: {
|
|
423
|
+
id: terminalId,
|
|
424
|
+
stateId: instanceState.id,
|
|
425
|
+
name: "test-terminal",
|
|
426
|
+
serviceAccountId: serviceAccount.id,
|
|
427
|
+
meta: { title: "Test Terminal" },
|
|
428
|
+
status: "active",
|
|
429
|
+
spec: { image: "test:latest" },
|
|
430
|
+
},
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
434
|
+
|
|
435
|
+
// act
|
|
436
|
+
await instanceStateService.forgetInstanceState(
|
|
437
|
+
project.id,
|
|
438
|
+
instanceState.instanceId as InstanceId,
|
|
439
|
+
{
|
|
440
|
+
clearTerminalData: false,
|
|
441
|
+
},
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
// assert
|
|
445
|
+
const terminal = await projectDatabase.terminal.findUnique({
|
|
446
|
+
where: { id: terminalId },
|
|
447
|
+
})
|
|
448
|
+
expect(terminal?.status).toBe("unavailable")
|
|
449
|
+
},
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
instanceStateTest(
|
|
453
|
+
"deletes secrets when deleteSecrets=true",
|
|
454
|
+
async ({
|
|
455
|
+
instanceStateService,
|
|
456
|
+
projectDatabase,
|
|
457
|
+
project,
|
|
458
|
+
createInstanceState,
|
|
459
|
+
projectService,
|
|
460
|
+
expect,
|
|
461
|
+
}) => {
|
|
462
|
+
// arrange
|
|
463
|
+
const instanceState = await createInstanceState(project.id)
|
|
464
|
+
|
|
465
|
+
await projectDatabase.secret.create({
|
|
466
|
+
data: {
|
|
467
|
+
id: createId(),
|
|
468
|
+
stateId: instanceState.id,
|
|
469
|
+
name: "test-secret",
|
|
470
|
+
meta: { title: "Test Secret" },
|
|
471
|
+
content: "secret-value",
|
|
472
|
+
},
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
476
|
+
|
|
477
|
+
// act
|
|
478
|
+
await instanceStateService.forgetInstanceState(
|
|
479
|
+
project.id,
|
|
480
|
+
instanceState.instanceId as InstanceId,
|
|
481
|
+
{
|
|
482
|
+
deleteSecrets: true,
|
|
483
|
+
},
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
// assert
|
|
487
|
+
const secrets = await projectDatabase.secret.findMany({
|
|
488
|
+
where: { stateId: instanceState.id },
|
|
489
|
+
})
|
|
490
|
+
expect(secrets).toHaveLength(0)
|
|
491
|
+
},
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
instanceStateTest(
|
|
495
|
+
"keeps secrets when deleteSecrets=false",
|
|
496
|
+
async ({
|
|
497
|
+
instanceStateService,
|
|
498
|
+
projectDatabase,
|
|
499
|
+
project,
|
|
500
|
+
createInstanceState,
|
|
501
|
+
projectService,
|
|
502
|
+
expect,
|
|
503
|
+
}) => {
|
|
504
|
+
// arrange
|
|
505
|
+
const instanceState = await createInstanceState(project.id)
|
|
506
|
+
|
|
507
|
+
const secretId = createId()
|
|
508
|
+
await projectDatabase.secret.create({
|
|
509
|
+
data: {
|
|
510
|
+
id: secretId,
|
|
511
|
+
stateId: instanceState.id,
|
|
512
|
+
name: "test-secret",
|
|
513
|
+
meta: { title: "Test Secret" },
|
|
514
|
+
content: "secret-value",
|
|
515
|
+
},
|
|
516
|
+
})
|
|
517
|
+
|
|
518
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
519
|
+
|
|
520
|
+
// act
|
|
521
|
+
await instanceStateService.forgetInstanceState(
|
|
522
|
+
project.id,
|
|
523
|
+
instanceState.instanceId as InstanceId,
|
|
524
|
+
{
|
|
525
|
+
deleteSecrets: false,
|
|
526
|
+
},
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
// assert
|
|
530
|
+
const secret = await projectDatabase.secret.findUnique({
|
|
531
|
+
where: { id: secretId },
|
|
532
|
+
})
|
|
533
|
+
expect(secret).toBeDefined()
|
|
534
|
+
expect(secret?.stateId).toBe(instanceState.id)
|
|
535
|
+
},
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
instanceStateTest(
|
|
539
|
+
"recursively deletes child instances",
|
|
540
|
+
async ({
|
|
541
|
+
instanceStateService,
|
|
542
|
+
projectDatabase,
|
|
543
|
+
project,
|
|
544
|
+
createInstanceState,
|
|
545
|
+
projectService,
|
|
546
|
+
pubsubManager,
|
|
547
|
+
expect,
|
|
548
|
+
}) => {
|
|
549
|
+
// arrange
|
|
550
|
+
const parentInstance = await createInstanceState(project.id, "composite.v1", "composite")
|
|
551
|
+
const childInstance = await createInstanceState(project.id)
|
|
552
|
+
|
|
553
|
+
// set both instances to deployed status and establish parent-child relationship
|
|
554
|
+
await projectDatabase.instanceState.update({
|
|
555
|
+
where: { id: parentInstance.id },
|
|
556
|
+
data: { status: "deployed" },
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
await projectDatabase.instanceState.update({
|
|
560
|
+
where: { id: childInstance.id },
|
|
561
|
+
data: { parentId: parentInstance.id, status: "deployed" },
|
|
562
|
+
})
|
|
563
|
+
|
|
564
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
565
|
+
|
|
566
|
+
// act
|
|
567
|
+
await instanceStateService.forgetInstanceState(
|
|
568
|
+
project.id,
|
|
569
|
+
parentInstance.instanceId as InstanceId,
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
// assert
|
|
573
|
+
const updatedParent = await projectDatabase.instanceState.findUnique({
|
|
574
|
+
where: { id: parentInstance.id },
|
|
575
|
+
})
|
|
576
|
+
const updatedChild = await projectDatabase.instanceState.findUnique({
|
|
577
|
+
where: { id: childInstance.id },
|
|
578
|
+
})
|
|
579
|
+
|
|
580
|
+
expect(updatedParent?.status).toBe("undeployed")
|
|
581
|
+
expect(updatedChild?.status).toBe("undeployed")
|
|
582
|
+
|
|
583
|
+
// verify both instances got state update events
|
|
584
|
+
expect(pubsubManager.publish).toHaveBeenCalledTimes(2)
|
|
585
|
+
},
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
instanceStateTest(
|
|
589
|
+
"calls Pulumi deleteState for unit instances",
|
|
590
|
+
async ({
|
|
591
|
+
instanceStateService,
|
|
592
|
+
project,
|
|
593
|
+
createInstanceState,
|
|
594
|
+
projectService,
|
|
595
|
+
runnerBackend,
|
|
596
|
+
expect,
|
|
597
|
+
}) => {
|
|
598
|
+
// arrange
|
|
599
|
+
const instanceState = await createInstanceState(project.id, "server.v1", "unit")
|
|
600
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
601
|
+
|
|
602
|
+
// act
|
|
603
|
+
await instanceStateService.forgetInstanceState(
|
|
604
|
+
project.id,
|
|
605
|
+
instanceState.instanceId as InstanceId,
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
// assert
|
|
609
|
+
const [instanceType, instanceName] = parseInstanceId(instanceState.instanceId as InstanceId)
|
|
610
|
+
expect(runnerBackend.deleteState).toHaveBeenCalledWith({
|
|
611
|
+
projectId: project.id,
|
|
612
|
+
stateId: instanceState.id,
|
|
613
|
+
libraryId: project.libraryId,
|
|
614
|
+
instanceName,
|
|
615
|
+
instanceType,
|
|
616
|
+
})
|
|
617
|
+
},
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
instanceStateTest(
|
|
621
|
+
"throws error for missing instance",
|
|
622
|
+
async ({ instanceStateService, project, projectService, expect }) => {
|
|
623
|
+
// arrange
|
|
624
|
+
const nonexistentInstanceId: InstanceId = "server.v1:nonexistent"
|
|
625
|
+
projectService.getProjectOrThrow.mockResolvedValue(project)
|
|
626
|
+
|
|
627
|
+
// act & assert
|
|
628
|
+
await expect(
|
|
629
|
+
instanceStateService.forgetInstanceState(project.id, nonexistentInstanceId),
|
|
630
|
+
).rejects.toThrow(InstanceStateNotFoundError)
|
|
631
|
+
},
|
|
632
|
+
)
|
|
633
|
+
})
|
|
634
|
+
|
|
635
|
+
describe("replaceCustomStatus", () => {
|
|
636
|
+
instanceStateTest(
|
|
637
|
+
"successfully replaces custom status",
|
|
638
|
+
async ({ instanceStateService, projectDatabase, project, createInstanceState, expect }) => {
|
|
639
|
+
// arrange
|
|
640
|
+
const instanceState = await createInstanceState(project.id)
|
|
641
|
+
const serviceAccountId = createId()
|
|
642
|
+
|
|
643
|
+
// create service account first
|
|
644
|
+
await projectDatabase.serviceAccount.create({
|
|
645
|
+
data: {
|
|
646
|
+
id: serviceAccountId,
|
|
647
|
+
meta: { title: "Test Service Account" },
|
|
648
|
+
},
|
|
649
|
+
})
|
|
650
|
+
|
|
651
|
+
const status = {
|
|
652
|
+
instanceId: instanceState.instanceId,
|
|
653
|
+
name: "health",
|
|
654
|
+
meta: { title: "Health Status" },
|
|
655
|
+
value: "healthy",
|
|
656
|
+
title: "Health Status",
|
|
657
|
+
message: "Service is running normally",
|
|
658
|
+
order: 10,
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// act
|
|
662
|
+
await instanceStateService.updateCustomStatus(
|
|
663
|
+
project.id,
|
|
664
|
+
instanceState.id,
|
|
665
|
+
serviceAccountId,
|
|
666
|
+
status,
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
// assert
|
|
670
|
+
const customStatus = await projectDatabase.instanceCustomStatus.findUnique({
|
|
671
|
+
where: {
|
|
672
|
+
stateId_serviceAccountId_name: {
|
|
673
|
+
stateId: instanceState.id,
|
|
674
|
+
serviceAccountId,
|
|
675
|
+
name: status.name,
|
|
676
|
+
},
|
|
677
|
+
},
|
|
678
|
+
})
|
|
679
|
+
|
|
680
|
+
expect(customStatus).toBeDefined()
|
|
681
|
+
expect(customStatus?.value).toBe("healthy")
|
|
682
|
+
expect(customStatus?.message).toBe("Service is running normally")
|
|
683
|
+
expect(customStatus?.order).toBe(10)
|
|
684
|
+
},
|
|
685
|
+
)
|
|
686
|
+
})
|
|
687
|
+
|
|
688
|
+
describe("removeCustomStatus", () => {
|
|
689
|
+
instanceStateTest(
|
|
690
|
+
"successfully removes custom status",
|
|
691
|
+
async ({ instanceStateService, projectDatabase, project, createInstanceState, expect }) => {
|
|
692
|
+
// arrange
|
|
693
|
+
const instanceState = await createInstanceState(project.id)
|
|
694
|
+
|
|
695
|
+
// create service account first
|
|
696
|
+
const serviceAccount = await projectDatabase.serviceAccount.create({
|
|
697
|
+
data: {
|
|
698
|
+
meta: { title: "Test Service Account" },
|
|
699
|
+
},
|
|
700
|
+
})
|
|
701
|
+
|
|
702
|
+
await projectDatabase.instanceCustomStatus.create({
|
|
703
|
+
data: {
|
|
704
|
+
stateId: instanceState.id,
|
|
705
|
+
serviceAccountId: serviceAccount.id,
|
|
706
|
+
name: "health",
|
|
707
|
+
meta: { title: "Health Status" },
|
|
708
|
+
value: "healthy",
|
|
709
|
+
order: 10,
|
|
710
|
+
},
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
// act
|
|
714
|
+
await instanceStateService.removeCustomStatus(
|
|
715
|
+
project.id,
|
|
716
|
+
instanceState.id,
|
|
717
|
+
serviceAccount.id,
|
|
718
|
+
"health",
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
// assert
|
|
722
|
+
const customStatus = await projectDatabase.instanceCustomStatus.findUnique({
|
|
723
|
+
where: {
|
|
724
|
+
stateId_serviceAccountId_name: {
|
|
725
|
+
stateId: instanceState.id,
|
|
726
|
+
serviceAccountId: serviceAccount.id,
|
|
727
|
+
name: "health",
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
})
|
|
731
|
+
|
|
732
|
+
expect(customStatus).toBeNull()
|
|
733
|
+
},
|
|
734
|
+
)
|
|
735
|
+
})
|