1import * as AWS from "@/AWS";
2import {
3 deleteChannelWithEndpoints,
4 listAllChannelGroups,
5 listGroupChannels,
6 retryWhileMpConflict,
7} from "@/AWS/MediaPackageV2/internal.ts";
8import * as Test from "@/Test/Alchemy";
9import * as mediapackagev2 from "@distilled.cloud/aws/mediapackagev2";
10import { expect } from "alchemy-test";
11import * as Effect from "effect/Effect";
12
13const { test } = Test.make({ providers: AWS.providers() });
14
15// One-off orphan sweep for the account's MediaPackageV2 surface. Deletes
16// EVERY channel group (reaping channels + origin endpoints first, exercising
17// the provider's reap-children delete path) and asserts zero remain.
18// Env-gated so it can never race the lifecycle suite's own deployments.
19test.provider.skipIf(!process.env.MPV2_SWEEP)(
20 "sweep: reap every channel group and verify zero remain",
21 () =>
22 Effect.gen(function* () {
23 // Plant a deterministic orphan chain (group -> channel -> endpoint)
24 // out-of-band so the sweep provably reaps children before the group —
25 // the exact scenario that leaked under nuke.
26 yield* mediapackagev2
27 .createChannelGroup({ ChannelGroupName: "alchemy-mpv2-sweep-probe" })
28 .pipe(Effect.catchTag("ConflictException", () => Effect.void));
29 yield* mediapackagev2
30 .createChannel({
31 ChannelGroupName: "alchemy-mpv2-sweep-probe",
32 ChannelName: "probe-feed",
33 InputType: "HLS",
34 })
35 .pipe(Effect.catchTag("ConflictException", () => Effect.void));
36 yield* mediapackagev2
37 .createOriginEndpoint({
38 ChannelGroupName: "alchemy-mpv2-sweep-probe",
39 ChannelName: "probe-feed",
40 OriginEndpointName: "probe-playback",
41 ContainerType: "TS",
42 Segment: { SegmentDurationSeconds: 6 },
43 HlsManifests: [{ ManifestName: "index" }],
44 })
45 .pipe(Effect.catchTag("ConflictException", () => Effect.void));
46
47 const groups = yield* listAllChannelGroups();
48 expect(groups.length).toBeGreaterThanOrEqual(1);
49 yield* Effect.forEach(
50 groups,
51 (group) =>
52 Effect.gen(function* () {
53 const channels = yield* listGroupChannels(group.ChannelGroupName);
54 yield* Effect.forEach(
55 channels,
56 (channel) =>
57 deleteChannelWithEndpoints(
58 group.ChannelGroupName,
59 channel.ChannelName,
60 ),
61 { concurrency: 5, discard: true },
62 );
63 yield* mediapackagev2
64 .deleteChannelGroup({ ChannelGroupName: group.ChannelGroupName })
65 .pipe(retryWhileMpConflict);
66 }),
67 { concurrency: 3, discard: true },
68 );
69 const remaining = yield* listAllChannelGroups();
70 expect(remaining).toHaveLength(0);
71 }),
72 {
73 tags: ["provider:aws", "provider:aws:mediapackagev2", "live"],
74 timeout: 120_000,
75 },
76);