1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as dns from "@distilled.cloud/gcp/dns_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8import { GcpEnvironment } from "@/GCP/Environment";
9import { withNetworkSlot } from "../networkQuota.ts";
10
11const { test } = Test.make({ providers: GCP.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const waitUntilGone = (
19 project: string,
20 responsePolicy: string,
21 ruleName: string,
22) =>
23 dns
24 .getResponsePolicyRules({
25 project,
26 responsePolicy,
27 responsePolicyRule: ruleName,
28 })
29 .pipe(
30 Effect.as("found" as const),
31 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
32 Effect.repeat({
33 schedule: Schedule.spaced("1 second"),
34 until: (status) => status === "gone",
35 times: 10,
36 }),
37 );
38
39test.provider(
40 "getResponsePolicyRules on a missing rule fails with a typed tag",
41 (stack) =>
42 Effect.gen(function* () {
43 yield* stack.destroy();
44
45 const { project } = yield* GcpEnvironment.current;
46 const error = yield* Effect.flip(
47 dns.getResponsePolicyRules({
48 project,
49 responsePolicy: "alchemy-missing-policy",
50 responsePolicyRule: "alchemy-missing-rule",
51 }),
52 );
53 expect(error._tag).toEqual("NotFound");
54
55 yield* stack.destroy();
56 }).pipe(logLevel),
57 { tags: ["provider:gcp", "provider:gcp:dns", "live"], timeout: 90_000 },
58);
59
60test.provider(
61 "create, update, and delete a response policy rule",
62 (stack) =>
63 Effect.gen(function* () {
64 yield* stack.destroy();
65
66 const created = yield* stack.deploy(
67 Effect.gen(function* () {
68 const vpc = yield* GCP.Compute.Network("Vpc", {
69 autoCreateSubnetworks: false,
70 });
71 const policy = yield* GCP.DNS.ResponsePolicy("Overrides", {
72 description: "alchemy response policy for rule test",
73 networks: [vpc.networkName],
74 });
75 const rule = yield* GCP.DNS.ResponsePolicyRule("Internal", {
76 responsePolicy: policy.responsePolicyName,
77 dnsName: "rule.internal.example.com.",
78 localData: [{ type: "A", ttl: 300, rrdatas: ["10.0.0.20"] }],
79 });
80 return { vpc, policy, rule };
81 }),
82 );
83
84 expect(created.rule.responsePolicy).toEqual(
85 created.policy.responsePolicyName,
86 );
87 expect(created.rule.dnsName).toEqual("rule.internal.example.com.");
88
89 const fetched = yield* dns.getResponsePolicyRules({
90 project: created.rule.project,
91 responsePolicy: created.policy.responsePolicyName,
92 responsePolicyRule: created.rule.ruleName,
93 });
94 expect(fetched.dnsName).toEqual("rule.internal.example.com.");
95 expect(fetched.localData?.localDatas?.[0]?.rrdatas).toEqual([
96 "10.0.0.20",
97 ]);
98
99 const updated = yield* stack.deploy(
100 Effect.gen(function* () {
101 const vpc = yield* GCP.Compute.Network("Vpc", {
102 networkName: created.vpc.networkName,
103 autoCreateSubnetworks: false,
104 });
105 const policy = yield* GCP.DNS.ResponsePolicy("Overrides", {
106 responsePolicyName: created.policy.responsePolicyName,
107 description: "alchemy response policy for rule test",
108 networks: [vpc.networkName],
109 });
110 const rule = yield* GCP.DNS.ResponsePolicyRule("Internal", {
111 responsePolicy: policy.responsePolicyName,
112 ruleName: created.rule.ruleName,
113 dnsName: "rule.internal.example.com.",
114 localData: [{ type: "A", ttl: 60, rrdatas: ["10.0.0.21"] }],
115 });
116 return { vpc, policy, rule };
117 }),
118 );
119
120 expect(updated.rule.ruleName).toEqual(created.rule.ruleName);
121 expect(updated.rule.localData).toEqual([
122 {
123 name: "rule.internal.example.com.",
124 type: "A",
125 ttl: 60,
126 rrdatas: ["10.0.0.21"],
127 },
128 ]);
129
130 yield* stack.destroy();
131 const gone = yield* waitUntilGone(
132 created.rule.project,
133 created.policy.responsePolicyName,
134 created.rule.ruleName,
135 );
136 expect(gone).toEqual("gone");
137 }).pipe(logLevel, withNetworkSlot),
138 { tags: ["provider:gcp", "provider:gcp:dns", "live"], timeout: 120_000 },
139);