1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as datamigration from "@distilled.cloud/gcp/datamigration_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import {
7 logLevel,
8 currentProject,
9 runSlowLifecycle,
10 waitUntilGone,
11} from "./common.ts";
12
13const { test } = Test.make({ providers: GCP.providers() });
14
15test.provider(
16 "getProjectsLocationsMigrationJobs on a missing job fails with a typed tag",
17 (stack) =>
18 Effect.gen(function* () {
19 const project = yield* currentProject;
20
21 yield* stack.destroy();
22
23 const error = yield* Effect.flip(
24 datamigration.getProjectsLocationsMigrationJobs({
25 name: `projects/${project}/locations/us-central1/migrationJobs/alchemy-missing-job`,
26 }),
27 );
28 expect(error._tag).toEqual("NotFound");
29
30 yield* stack.destroy();
31 }).pipe(logLevel),
32 {
33 tags: ["provider:gcp", "provider:gcp:datamigration", "live"],
34 timeout: 90_000,
35 },
36);
37
38test.provider.skipIf(!runSlowLifecycle)(
39 "create, update, and delete a mysql to cloudsql migration job",
40 (stack) =>
41 Effect.gen(function* () {
42 const project = yield* currentProject;
43
44 yield* stack.destroy();
45
46 const created = yield* stack.deploy(
47 Effect.gen(function* () {
48 const source = yield* GCP.DataMigration.ConnectionProfile(
49 "MysqlSrc",
50 {
51 location: "us-central1",
52 displayName: "job-src",
53 mysql: {
54 host: "10.0.0.8",
55 port: 3306,
56 username: "alchemy",
57 password: "AlchemyTestPass1",
58 },
59 },
60 );
61 const dest = yield* GCP.DataMigration.ConnectionProfile("MysqlDest", {
62 location: "us-central1",
63 displayName: "job-dest",
64 cloudsql: {
65 settings: {
66 sourceId: source.name,
67 databaseVersion: "MYSQL_8_0",
68 tier: "db-n1-standard-1",
69 rootPassword: "AlchemyTestPass1",
70 dataDiskSizeGb: "10",
71 },
72 },
73 });
74 const job = yield* GCP.DataMigration.MigrationJob("Replica", {
75 location: "us-central1",
76 displayName: "mysql-replica",
77 labels: { env: "test" },
78 type: "CONTINUOUS",
79 source: source.name,
80 destination: dest.name,
81 staticIpConnectivity: {},
82 });
83 return { source, dest, job };
84 }),
85 );
86
87 expect(created.job.migrationJobId).toEqual(expect.any(String));
88 expect(created.job.name).toEqual(
89 `projects/${project}/locations/us-central1/migrationJobs/${created.job.migrationJobId}`,
90 );
91 expect(created.job.type).toEqual("CONTINUOUS");
92 expect(created.job.source).toEqual(created.source.name);
93 expect(created.job.destination).toEqual(created.dest.name);
94 expect(created.job.labels).toMatchObject({ env: "test" });
95
96 const fetched = yield* datamigration.getProjectsLocationsMigrationJobs({
97 name: created.job.name,
98 });
99 expect(fetched.name).toEqual(created.job.name);
100 expect(fetched.displayName).toEqual("mysql-replica");
101 expect(fetched.labels?.env).toEqual("test");
102
103 const updated = yield* stack.deploy(
104 Effect.gen(function* () {
105 const source = yield* GCP.DataMigration.ConnectionProfile(
106 "MysqlSrc",
107 {
108 connectionProfileId: created.source.connectionProfileId,
109 location: "us-central1",
110 displayName: "job-src",
111 mysql: {
112 host: "10.0.0.8",
113 port: 3306,
114 username: "alchemy",
115 },
116 },
117 );
118 const dest = yield* GCP.DataMigration.ConnectionProfile("MysqlDest", {
119 connectionProfileId: created.dest.connectionProfileId,
120 location: "us-central1",
121 displayName: "job-dest",
122 cloudsql: {
123 settings: {
124 sourceId: source.name,
125 databaseVersion: "MYSQL_8_0",
126 tier: "db-n1-standard-1",
127 dataDiskSizeGb: "10",
128 },
129 },
130 });
131 const job = yield* GCP.DataMigration.MigrationJob("Replica", {
132 migrationJobId: created.job.migrationJobId,
133 location: "us-central1",
134 displayName: "mysql-replica-v2",
135 labels: { env: "prod", team: "dms" },
136 type: "CONTINUOUS",
137 source: source.name,
138 destination: dest.name,
139 staticIpConnectivity: {},
140 });
141 return { source, dest, job };
142 }),
143 );
144
145 expect(updated.job.name).toEqual(created.job.name);
146 expect(updated.job.displayName).toEqual("mysql-replica-v2");
147 expect(updated.job.labels).toMatchObject({ env: "prod", team: "dms" });
148
149 const fetchedUpdate =
150 yield* datamigration.getProjectsLocationsMigrationJobs({
151 name: updated.job.name,
152 });
153 expect(fetchedUpdate.displayName).toEqual("mysql-replica-v2");
154 expect(fetchedUpdate.labels?.team).toEqual("dms");
155
156 yield* stack.destroy();
157 const gone = yield* waitUntilGone(
158 datamigration.getProjectsLocationsMigrationJobs({
159 name: created.job.name,
160 }),
161 );
162 expect(gone).toEqual("gone");
163 }).pipe(logLevel),
164 // The Cloud SQL destination profile provisions an instance (20–40 minutes).
165 {
166 tags: ["provider:gcp", "provider:gcp:datamigration", "live"],
167 timeout: 3_600_000,
168 retry: 0,
169 },
170);