Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 71 additions & 40 deletions packages/stack/src/services/AuthStorage.integration.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NodeHttpClient, NodeServices } from "@effect/platform-node";
import { describe, expect, it } from "@effect/vitest";
import { Effect, FileSystem, Layer, Redacted, Schema } from "effect";
import { afterAll, beforeAll, describe, expect, it } from "@effect/vitest";
import { Effect, Exit, FileSystem, Layer, Redacted, Schema, Scope } from "effect";
import { HttpClient, HttpClientRequest } from "effect/unstable/http";
import { SignJWT } from "jose";
import { makeStandaloneService } from "../../tests/standalone-service.ts";
Expand All @@ -10,55 +10,71 @@ import { makeDockerDatabaseRoot } from "../../tests/docker-fixture.ts";
import { httpHost } from "../../tests/helpers/endpoint.ts";
import { engineTarget, testEngine } from "../../tests/engine-target.ts";

const options = (root: string) => ({
const dockerOptions = (root: string) => ({
stackId: "catalog-auth-storage",
instanceId: "instance",
root,
cacheRoot: `${root}/cache`,
runtime: "native" as const,
});

const dockerOptions = (root: string) => ({
...options(root),
runtime: testEngine,
engineTarget,
});

const secret = "catalog-auth-storage-secret-with-at-least-32-chars";

let scope: Scope.Closeable;
let root: string;
let stopDatabase: Effect.Effect<void> | undefined;
let databaseUrl: string;

describe("service catalog", () => {
beforeAll(() => {
scope = Scope.makeUnsafe();
return Effect.gen(function* () {
const databaseRoot = yield* makeDockerDatabaseRoot("catalog-auth-storage-");
const databaseRecipe = yield* makeServiceRecipe(
{
service: "database",
config: {
version: "17",
databasePassword: Redacted.make("postgres"),
jwtSecret: Redacted.make(secret),
jwtExpiry: 3600,
},
},
dockerOptions(databaseRoot),
);
const database = yield* makeStandaloneService(databaseRecipe.definition, {
id: "database",
config: databaseRecipe.creation,
});
yield* database.start;
yield* database.ready;
const databaseRelay = yield* makeDockerTcpRelay(databaseRecipe.endpoint("sql"));
root = databaseRoot;
stopDatabase = database.stop.pipe(Effect.asVoid, Effect.orDie);
databaseUrl = `postgresql://supabase_admin:postgres@${databaseRelay.host}:${databaseRelay.port}/postgres`;
}).pipe(
Effect.provide(Layer.merge(NodeServices.layer, NodeHttpClient.layerNodeHttp)),
Scope.provide(scope),
Effect.runPromise,
);
}, 120_000);

afterAll(
() =>
Effect.suspend(() => stopDatabase ?? Effect.void).pipe(
Effect.ensuring(Scope.close(scope, Exit.void)),
Effect.runPromise,
),
60_000,
);

it.live(
"migrates Auth and serves Storage against the owned database",
"migrates Auth and signs in a signed-up user against the owned database",
() =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const client = yield* HttpClient.HttpClient;
const root = yield* makeDockerDatabaseRoot("catalog-auth-storage-");
// Ownership is by location: Storage's filePath is a caller path and must live outside
// the stack's data root, not merely outside the service's own instance root.
const callerRoot = yield* fs.makeTempDirectoryScoped({
prefix: "catalog-auth-storage-caller-",
});
const secret = "catalog-auth-storage-secret-with-at-least-32-chars";
const databaseRecipe = yield* makeServiceRecipe(
{
service: "database",
config: {
version: "17",
databasePassword: Redacted.make("postgres"),
jwtSecret: Redacted.make(secret),
jwtExpiry: 3600,
},
},
dockerOptions(root),
);
const database = yield* makeStandaloneService(databaseRecipe.definition, {
id: "database",
config: databaseRecipe.creation,
});
yield* database.start;
yield* database.ready;
const databaseRelay = yield* makeDockerTcpRelay(databaseRecipe.endpoint("sql"));
const databaseUrl = `postgresql://supabase_admin:postgres@${databaseRelay.host}:${databaseRelay.port}/postgres`;
const authRecipe = yield* makeServiceRecipe(
{
service: "auth",
Expand Down Expand Up @@ -100,7 +116,24 @@ describe("service catalog", () => {
Schema.fromJsonString(Schema.Struct({ access_token: Schema.String })),
)(loginBody);
expect(loginToken.access_token.length).toBeGreaterThan(0);
yield* auth.stop;
}),
).pipe(Effect.provide(Layer.merge(NodeServices.layer, NodeHttpClient.layerNodeHttp))),
{ timeout: 120_000 },
);

it.live(
"serves Storage objects and imgproxy transforms against the owned database",
() =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const client = yield* HttpClient.HttpClient;
// Ownership is by location: Storage's filePath is a caller path and must live outside
// the stack's data root, not merely outside the service's own instance root.
const callerRoot = yield* fs.makeTempDirectoryScoped({
prefix: "catalog-auth-storage-caller-",
});
const storageRoot = `${callerRoot}/storage`;
yield* fs.makeDirectory(storageRoot, { recursive: true });
const imgproxyRecipe = yield* makeServiceRecipe(
Expand Down Expand Up @@ -191,10 +224,8 @@ describe("service catalog", () => {
);
expect(transformedImage.status).toBe(200);
expect(transformedImage.headers["content-type"]).toContain("image/");
yield* imgproxy.stop;
yield* storage.stop;
yield* auth.stop;
yield* database.stop;
yield* imgproxy.stop;
}),
).pipe(Effect.provide(Layer.merge(NodeServices.layer, NodeHttpClient.layerNodeHttp))),
{ timeout: 120_000 },
Expand Down
5 changes: 3 additions & 2 deletions packages/stack/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export default defineConfig({
include: ["**/*.integration.test.ts"],
hookTimeout: 120_000,
testTimeout: 30_000,
// Integration workers start real service processes and containers.
maxWorkers: 4,
// Most files start real containers, so the Docker engine bounds throughput; more
// workers only stretch each test's duration toward its timeout.
maxWorkers: 2,
sequence: { groupOrder: 1 },
globalSetup: ["tests/docker-volume-run.ts"],
},
Expand Down
Loading