supabase-testcontainers-modules 1.0.3

Testcontainers modules for Supabase services used in integration testing.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# Integration Testing Implementation Plan

This document outlines the integration test scenarios for each Supabase service module. Use the checkboxes to track implementation progress.

---

## Overview

Each service requires Docker containers and follows a similar testing pattern:
1. Start required dependencies (usually PostgreSQL)
2. Configure and start the service container
3. Verify the service is healthy and functional
4. Test service-specific functionality
5. Cleanup (automatic via testcontainers)

### Common Testing Infrastructure

All integration tests share:
- `tokio::test` for async test execution
- `testcontainers::runners::AsyncRunner` for container management
- Unique network names per test for isolation
- `anyhow::Result` for error handling

---

## 1. PostgREST Integration Tests

**File:** `tests/postgrest_integration.rs`

**Dependencies:**
- PostgreSQL container (for database)
- PostgREST container

**Run command:** `cargo test --features postgrest,const --test postgrest_integration`

### Test Scenarios

- [x] **test_containers_start** - Verify PostgreSQL and PostgREST containers start successfully
  - Start PostgreSQL with test schema
  - Start PostgREST connected to PostgreSQL
  - Assert both containers have valid ports assigned

- [x] **test_health_endpoint_returns_200** - Verify PostgREST health/ready endpoint
  - Start containers
  - GET request to root endpoint `/`
  - Assert 200 status code

- [x] **test_openapi_schema_available** - Verify OpenAPI schema generation
  - Start containers
  - GET request to `/` with Accept: application/openapi+json
  - Assert response contains OpenAPI schema structure

- [x] **test_table_crud_operations** - Verify basic CRUD via REST API
  - Create a test table in PostgreSQL
  - POST to create a row
  - GET to retrieve the row
  - PATCH to update the row
  - DELETE to remove the row
  - Assert each operation succeeds

- [x] **test_anonymous_role_access** - Verify anon role restrictions
  - Create table with RLS policies
  - Make request without JWT
  - Assert request uses anon role correctly

- [x] **test_jwt_authentication** - Verify JWT-based authentication
  - Configure PostgREST with JWT secret
  - Create authenticated role in PostgreSQL
  - Make request with valid JWT
  - Assert role switching works correctly

- [x] **test_max_rows_limit** - Verify row limiting works
  - Configure PostgREST with max_rows=10
  - Insert 20 rows into test table
  - GET all rows
  - Assert only 10 rows returned

### Setup Requirements

```sql
-- Required PostgreSQL setup for PostgREST tests
CREATE ROLE anon NOLOGIN;
CREATE ROLE authenticator LOGIN PASSWORD 'testpass' NOINHERIT;
GRANT anon TO authenticator;

CREATE SCHEMA api;
CREATE TABLE api.todos (id SERIAL PRIMARY KEY, task TEXT, done BOOLEAN DEFAULT false);
GRANT USAGE ON SCHEMA api TO anon;
GRANT SELECT, INSERT, UPDATE, DELETE ON api.todos TO anon;
GRANT USAGE ON SEQUENCE api.todos_id_seq TO anon;
```

---

## 2. Storage Integration Tests

**File:** `tests/storage_integration.rs`

**Dependencies:**
- PostgreSQL container (for metadata storage)
- Storage container

**Run command:** `cargo test --features storage,const --test storage_integration`

**Note:** The storage-api container requires the complete Supabase PostgreSQL schema for full functionality. The tests below verify container setup patterns and basic connectivity. Full bucket/file operations require additional schema setup beyond what testcontainers can easily provide.

### Test Scenarios

- [x] **test_containers_start** - Verify containers start successfully
  - Start PostgreSQL with required roles
  - Start Storage connected to PostgreSQL
  - Assert both containers have valid ports

- [x] **test_health_endpoint_returns_200** - Verify health endpoint
  - Start containers
  - GET request to `/status`
  - Assert 200 status code

- [x] **test_file_size_limit_configuration** - Verify size limit configuration
  - Configure Storage with custom file size limit
  - Verify container starts with configuration
  - Assert health endpoint works

### Setup Requirements

Storage requires:
- PostgreSQL roles: `anon`, `authenticated`, `service_role`, `supabase_storage_admin`
- JWT tokens for authentication:
  - `ANON_KEY` - For public bucket access
  - `SERVICE_KEY` - For administrative operations

---

## 3. Analytics (Logflare) Integration Tests

**File:** `tests/analytics_integration.rs`

**Dependencies:**
- PostgreSQL container (for analytics storage)
- Analytics container

**Run command:** `cargo test --features analytics,const --test analytics_integration`

**Note:** The Logflare container's HTTP server only starts after migrations complete successfully. These tests verify container setup patterns and database connectivity.

### Test Scenarios

- [x] **test_containers_start** - Verify containers start successfully
  - Start PostgreSQL
  - Start Analytics with PostgreSQL backend
  - Assert containers have valid ports

- [x] **test_postgres_connection_works** - Verify PostgreSQL connectivity
  - Start containers
  - Connect directly to PostgreSQL
  - Verify query execution works

- [x] **test_analytics_schema_check** - Verify database schema
  - Connect to PostgreSQL directly
  - Check for `_analytics` schema presence
  - Log schema status

### Setup Requirements

Analytics requires:
- PostgreSQL backend URL
- Public access token (for log ingestion)
- Private access token (for management API)
- Base64 encryption key for sensitive data

---

## 4. Functions (Edge Runtime) Integration Tests

**File:** `tests/functions_integration.rs`

**Dependencies:**
- Functions container
- (Optional) PostgreSQL container for database access

**Run command:** `cargo test --features functions,const --test functions_integration`

**Note:** The edge-runtime container requires a functions directory to be mounted at startup. On SELinux-enabled systems (like Fedora), bind mounts require the `:Z` flag which testcontainers doesn't natively support. The tests below verify configuration patterns work correctly. Full function invocation tests require additional infrastructure setup.

### Test Scenarios

- [x] **test_default_configuration** - Verify default configuration is correct
  - Create Functions instance with defaults
  - Assert image name and tag are correct

- [x] **test_jwt_secret_configuration** - Verify JWT secret configuration
  - Configure Functions with JWT secret
  - Assert configuration is accepted

- [x] **test_full_configuration** - Verify all configuration options work
  - Configure Functions with all available options
  - Assert configuration is accepted

- [x] **test_exposed_port** - Verify correct port is exposed
  - Check exposed ports
  - Assert FUNCTIONS_PORT (9000) is exposed

- [x] **test_ready_conditions** - Verify ready conditions are correct
  - Check ready conditions
  - Assert waiting for "Listening on" message

- [x] **test_command** - Verify command is correctly set
  - Check container command
  - Assert "start --main-service /home/deno/functions"

- [x] **test_custom_main_service_path** - Verify custom path is respected
  - Configure with custom main service path
  - Assert path is included in command

### Setup Requirements

Functions require:
- Functions directory mounted into container at `/home/deno/functions`
- Each function in its own subdirectory with `index.ts`

Example test function structure:
```
tests/fixtures/functions/
├── hello/
│   └── index.ts
├── echo/
│   └── index.ts
└── db-query/
    └── index.ts
```

---

## 5. GraphQL (pg_graphql) Integration Tests

**File:** `tests/graphql_integration.rs`

**Dependencies:**
- PostgreSQL container (standard postgres image)
- PostgREST container (for HTTP access)

**Run command:** `cargo test --features graphql,postgrest,const --test graphql_integration`

**Note:** The `supabase/postgres` image (which includes pg_graphql) has known compatibility issues with testcontainers. The integration tests use standard PostgreSQL to verify the setup patterns work correctly. Full pg_graphql functionality requires the supabase/postgres image in a different testing environment (e.g., Docker Compose).

### Test Scenarios

- [x] **test_postgres_container_starts** - Verify PostgreSQL container starts
  - Start PostgreSQL container
  - Connect and execute simple query
  - Assert connection succeeds

- [x] **test_postgrest_connects_to_postgres** - Verify PostgREST connects to PostgreSQL
  - Start PostgreSQL and PostgREST containers
  - GET request to PostgREST root endpoint
  - Assert 200 status code

- [x] **test_rest_api_query** - Verify REST API query works
  - Create test table with data
  - GET request to table endpoint
  - Assert data is returned correctly

- [x] **test_rest_api_insert** - Verify REST API insert works
  - Create test table
  - POST request to insert data
  - Assert row is created

- [x] **test_direct_db_access** - Verify direct database access works
  - Start PostgreSQL and PostgREST
  - Connect directly to PostgreSQL
  - Assert can query alongside PostgREST

- [x] **test_openapi_schema** - Verify OpenAPI schema generation
  - Start PostgreSQL and PostgREST
  - GET request with OpenAPI accept header
  - Assert schema is returned

### Setup Requirements

The tests create roles and schema automatically:
```sql
-- Create roles for PostgREST
CREATE ROLE anon NOLOGIN;
CREATE ROLE authenticator LOGIN PASSWORD 'testpass' NOINHERIT;
GRANT anon TO authenticator;

-- Create API schema with test data
CREATE SCHEMA api;
CREATE TABLE api.todos (id SERIAL PRIMARY KEY, task TEXT, done BOOLEAN);
GRANT USAGE ON SCHEMA api TO anon;
GRANT SELECT, INSERT, UPDATE, DELETE ON api.todos TO anon;
```

---

## 6. Realtime Integration Tests

**File:** `tests/realtime_integration.rs`

**Dependencies:**
- PostgreSQL container (with logical replication enabled)
- Realtime container

**Run command:** `cargo test --features realtime,const --test realtime_integration`

**Note:** Full Realtime functionality (WebSocket connections, CDC) requires PostgreSQL with logical replication enabled (wal_level=logical). The Realtime container runs migrations on startup and requires additional configuration including `APP_NAME` and `RLIMIT_NOFILE`. The tests below verify configuration patterns work correctly. Full container startup tests require additional infrastructure setup.

### Test Scenarios

- [x] **test_default_configuration** - Verify default configuration is correct
  - Create Realtime instance with defaults
  - Assert image name and tag are correct

- [x] **test_postgres_connection_configuration** - Verify PostgreSQL connection config
  - Configure Realtime with connection string
  - Assert configuration is accepted

- [x] **test_individual_db_configuration** - Verify individual DB parameters
  - Configure with host, port, name, user, password, ssl
  - Assert configuration is accepted

- [x] **test_full_configuration** - Verify all configuration options
  - Configure with all available options
  - Assert configuration is accepted

- [x] **test_exposed_port** - Verify correct port is exposed
  - Check exposed ports
  - Assert REALTIME_PORT (4000) is exposed

- [x] **test_ready_conditions** - Verify ready conditions are correct
  - Check ready conditions
  - Assert waiting for "Realtime has started" message

- [x] **test_required_env_vars** - Verify required env vars are set
  - Check APP_NAME, RLIMIT_NOFILE, PORT, SLOT_NAME, etc.
  - Assert all required variables are set by default

- [x] **test_constructors** - Verify constructors work
  - Test new() and new_with_env() methods
  - Assert both work correctly

- [x] **test_slot_configuration** - Verify slot configuration options
  - Configure slot_name, temporary_slot, max_record_bytes
  - Assert configuration is accepted

- [x] **test_security_configuration** - Verify security configuration
  - Configure JWT secrets and secure_channels
  - Assert configuration is accepted

### Setup Requirements

PostgreSQL must have logical replication enabled:
```
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
```

For testing, use a PostgreSQL image that supports logical replication or configure via `postgresql.conf`.

Realtime requires:
- `DB_URL` or individual DB connection parameters
- `JWT_SECRET` for authentication
- `SECRET_KEY_BASE` for Phoenix (at least 64 chars)
- `APP_NAME` - required by Phoenix runtime config
- `RLIMIT_NOFILE` - required to avoid startup script error

---

## Implementation Notes

### Test Isolation

Each test should:
1. Generate unique network name using timestamp + counter
2. Use unique container names
3. Not depend on other tests' state

### Shared Test Utilities

Consider creating `tests/common/mod.rs` with:
- `unique_test_id()` function
- JWT generation helpers
- Common setup functions

### WebSocket Testing

For Realtime tests, add `tokio-tungstenite` as a dev dependency:
```toml
[dev-dependencies]
tokio-tungstenite = { version = "0.21", features = ["native-tls"] }
```

### Test Fixtures

Create `tests/fixtures/` directory for:
- SQL setup scripts
- Edge Functions code
- Sample files for Storage tests

---

## Dependencies to Add

```toml
[dev-dependencies]
testcontainers = { version = "0.25.2", features = ["default"] }
tokio = { version = "1.48.0", features = ["full", "test-util"] }
reqwest = { version = "0.12", features = ["json", "multipart"] }
serde_json = "1.0"
tokio-tungstenite = { version = "0.21", features = ["native-tls"] }
jsonwebtoken = "9.3"  # For JWT generation in tests
base64 = "0.22"       # For encoding test data
```

---

## Test Execution Order

Recommended order for implementation (simplest to most complex):

1. **GraphQL** - Just PostgreSQL, simple queries
2. **PostgREST** - PostgreSQL + REST API
3. **Storage** - PostgreSQL + file operations
4. **Analytics** - PostgreSQL + log ingestion
5. **Functions** - Standalone, needs function fixtures
6. **Realtime** - PostgreSQL + WebSocket (most complex)

---

## Success Criteria

All tests should:
- [ ] Pass independently (no shared state)
- [ ] Complete within reasonable timeout (< 60s each)
- [ ] Clean up resources automatically
- [ ] Provide clear failure messages
- [ ] Work in CI/CD environment with Docker