1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as cloudidentity from "@distilled.cloud/gcp/cloudidentity_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import * as Schedule from "effect/Schedule";
7import { customer, logLevel, runLifecycle } from "./common.ts";
8
9const { test } = Test.make({ providers: GCP.providers() });
10
11const waitUntilGone = (name: string) =>
12 cloudidentity.getDevices({ name, customer }).pipe(
13 Effect.as("found" as const),
14 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
15 Effect.repeat({
16 schedule: Schedule.spaced("1 second"),
17 until: (status) => status === "gone",
18 times: 10,
19 }),
20 );
21
22test.provider(
23 "getDevices on a missing device fails with a typed tag",
24 (stack) =>
25 Effect.gen(function* () {
26 yield* stack.destroy();
27
28 const error = yield* Effect.flip(
29 cloudidentity.getDevices({
30 name: "devices/alchemy-missing-device",
31 customer,
32 }),
33 );
34 expect(error._tag).toEqual("InsufficientScopes");
35
36 yield* stack.destroy();
37 }).pipe(logLevel),
38 {
39 tags: ["provider:gcp", "provider:gcp:cloudidentity", "live"],
40 timeout: 90_000,
41 },
42);
43
44test.provider.skipIf(!!process.env.GCP_TEST_CLOUDIDENTITY)(
45 "createDevices without Cloud Identity Premium fails with a typed entitlement error",
46 (stack) =>
47 Effect.gen(function* () {
48 yield* stack.destroy();
49
50 const error = yield* Effect.flip(
51 cloudidentity.createDevices({
52 customer,
53 body: {
54 serialNumber: "alchemy-probe-device",
55 deviceType: "LINUX",
56 assetTag: "alchemy-probe",
57 },
58 }),
59 );
60 expect(error._tag).toEqual("InsufficientScopes");
61
62 yield* stack.destroy();
63 }).pipe(logLevel),
64 {
65 tags: ["provider:gcp", "provider:gcp:cloudidentity", "live"],
66 timeout: 90_000,
67 },
68);
69
70test.provider.skipIf(!runLifecycle)(
71 "create and delete a company-owned device",
72 (stack) =>
73 Effect.gen(function* () {
74 yield* stack.destroy();
75
76 const created = yield* stack.deploy(
77 Effect.gen(function* () {
78 return yield* GCP.CloudIdentity.Device("Laptop", {
79 customer,
80 deviceType: "LINUX",
81 hostname: "eng-laptop",
82 assetTag: "desk-14",
83 });
84 }),
85 );
86
87 expect(created.name.startsWith("devices/")).toEqual(true);
88 expect(created.serialNumber?.length).toBeGreaterThan(0);
89 expect(created.assetTag).toEqual("desk-14");
90
91 const fetched = yield* cloudidentity.getDevices({
92 name: created.name,
93 customer,
94 });
95 expect(fetched.name).toEqual(created.name);
96 expect(fetched.assetTag).toContain("[alchemy ");
97
98 yield* stack.destroy();
99
100 const gone = yield* waitUntilGone(created.name);
101 expect(gone).toEqual("gone");
102 }).pipe(logLevel),
103 {
104 tags: ["provider:gcp", "provider:gcp:cloudidentity", "live"],
105 timeout: 90_000,
106 },
107);