Skip to content

Commit 03c5d8f

Browse files
committed
tests
1 parent 6dffef9 commit 03c5d8f

File tree

15 files changed

+820
-94
lines changed

15 files changed

+820
-94
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -86,28 +86,10 @@ jobs:
8686
fail-fast: false
8787
matrix:
8888
package:
89-
- utils/verify
90-
- utils/utils
91-
- utils/inflection
92-
- utils/faker
93-
- utils/base32
94-
- security/totp
95-
- security/jwt-claims
96-
- security/encrypted-secrets-table
97-
- security/encrypted-secrets
98-
- security/defaults
99-
- security/default-roles
100-
- metrics/measurements
101-
- metrics/achievements
102-
- meta/db_meta_test
103-
- meta/db_meta_modules
104-
- meta/db_meta
105-
- jobs/jobs
106-
- jobs/database-jobs
107-
- data-types/uuid
108-
- data-types/types
109-
- data-types/stamps
110-
- data-types/geotypes
89+
- verify
90+
- base32
91+
- totp
92+
- rls-demo
11193

11294
env:
11395
PGHOST: pg_db
@@ -176,75 +158,3 @@ jobs:
176158
- name: Test ${{ matrix.package }}
177159
run: cd ./packages/${{ matrix.package }} && pnpm test
178160

179-
integration-test:
180-
needs: setup
181-
runs-on: ubuntu-latest
182-
container: pyramation/node-sqitch:20.12.0
183-
184-
env:
185-
PGHOST: pg_db
186-
PGPORT: 5432
187-
PGUSER: postgres
188-
PGPASSWORD: password
189-
190-
services:
191-
pg_db:
192-
image: pyramation/pgvector:13.3-alpine
193-
env:
194-
POSTGRES_USER: postgres
195-
POSTGRES_PASSWORD: password
196-
options: >-
197-
--health-cmd pg_isready
198-
--health-interval 10s
199-
--health-timeout 5s
200-
--health-retries 5
201-
ports:
202-
- 5432:5432
203-
204-
minio_cdn:
205-
image: minio/minio:edge-cicd
206-
env:
207-
MINIO_ROOT_USER: minioadmin
208-
MINIO_ROOT_PASSWORD: minioadmin
209-
ports:
210-
- 9000:9000
211-
- 9001:9001
212-
options: >-
213-
--health-cmd "curl -f http://localhost:9000/minio/health/live || exit 1"
214-
--health-interval 10s
215-
--health-timeout 5s
216-
--health-retries 5
217-
218-
steps:
219-
- name: Configure Git (for tests)
220-
run: |
221-
git config --global user.name "CI Test User"
222-
git config --global user.email "[email protected]"
223-
224-
- name: Checkout
225-
uses: actions/checkout@v4
226-
227-
- name: Enable corepack and pnpm
228-
run: |
229-
corepack enable
230-
corepack prepare pnpm@9 --activate
231-
pnpm -v
232-
node -v
233-
234-
- name: Install
235-
run: pnpm install
236-
237-
- name: Install LaunchQL CLI globally
238-
run: npm install -g @launchql/[email protected]
239-
240-
- name: Build
241-
run: pnpm -r build
242-
243-
- name: Seed app_user
244-
run: |
245-
lql admin-users bootstrap --yes
246-
lql admin-users add --test --yes
247-
248-
- name: Run Integration Tests
249-
run: ./scripts/test-all-packages.sh
250-

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ export PGPORT=54322
1212
export PGHOST=localhost
1313
export PGUSER=postgres
1414
export PGPASSWORD=postgres
15+
16+
pnpm test
1517
```
1618

packages/rls-demo/LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2025 Dan Lynch <[email protected]>
4+
Copyright (c) 2025 Interweb, Inc.
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

packages/rls-demo/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
EXTENSION = launchql-rls-demo
2+
DATA = sql/launchql-rls-demo--0.0.1.sql
3+
4+
PG_CONFIG = pg_config
5+
PGXS := $(shell $(PG_CONFIG) --pgxs)
6+
include $(PGXS)

packages/rls-demo/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# @lql-pg/rls-demo
2+
3+
RLS (Row Level Security) demo extension for PostgreSQL.
4+
5+
Provides a demonstration of Row Level Security implementation with users and products tables, including:
6+
- `rls_test` schema with proper RLS policies
7+
- `users` table with RLS policies for user data access
8+
- `products` table with RLS policies for product ownership
9+
- Foreign key relationships and proper indexing
10+
- Automatic `updated_at` timestamp triggers
11+
12+
## Sample Data
13+
14+
This package includes sample data to demonstrate RLS functionality:
15+
16+
### Users
17+
- Alice Johnson ([email protected])
18+
- Bob Smith ([email protected])
19+
- Charlie Brown ([email protected])
20+
- Diana Prince ([email protected])
21+
22+
### Products
23+
- Alice owns: Laptop Pro ($1299.99), Wireless Mouse ($49.99)
24+
- Bob owns: Mechanical Keyboard ($149.99), Monitor 4K ($399.99)
25+
- Charlie owns: Webcam HD ($89.99), Headphones ($199.99)
26+
- Diana owns: Standing Desk ($599.99), Desk Lamp ($79.99)
27+
28+
## Data Insertion
29+
30+
### Using SQL File
31+
```bash
32+
psql -d your_database -f seed-data.sql
33+
```
34+
35+
### Using Node.js Script
36+
```bash
37+
node insert-data.js
38+
```
39+
40+
### Using pgsql-test
41+
The test suite includes comprehensive data insertion and RLS testing examples.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { getConnections, PgTestClient } from 'pgsql-test';
2+
3+
let pg: PgTestClient;
4+
let db: PgTestClient;
5+
let teardown: () => Promise<void>;
6+
7+
beforeAll(async () => {
8+
({ pg, db, teardown } = await getConnections());
9+
});
10+
11+
afterAll(async () => {
12+
await teardown();
13+
});
14+
15+
beforeEach(async () => {
16+
await db.beforeEach();
17+
});
18+
19+
afterEach(async () => {
20+
await db.afterEach();
21+
});
22+
23+
describe('RLS Demo - Data Insertion', () => {
24+
it('should insert users and products', async () => {
25+
// Insert users
26+
const user1 = await pg.one(
27+
`INSERT INTO rls_test.users (email, name)
28+
VALUES ($1, $2)
29+
RETURNING id, email, name`,
30+
['[email protected]', 'Alice Johnson']
31+
);
32+
33+
const user2 = await pg.one(
34+
`INSERT INTO rls_test.users (email, name)
35+
VALUES ($1, $2)
36+
RETURNING id, email, name`,
37+
['[email protected]', 'Bob Smith']
38+
);
39+
40+
// Insert products
41+
const product1 = await pg.one(
42+
`INSERT INTO rls_test.products (name, description, price, owner_id)
43+
VALUES ($1, $2, $3, $4)
44+
RETURNING id, name, price, owner_id`,
45+
['Laptop Pro', 'High-performance laptop', 1299.99, user1.id]
46+
);
47+
48+
const product2 = await pg.one(
49+
`INSERT INTO rls_test.products (name, description, price, owner_id)
50+
VALUES ($1, $2, $3, $4)
51+
RETURNING id, name, price, owner_id`,
52+
['Wireless Mouse', 'Ergonomic mouse', 49.99, user1.id]
53+
);
54+
55+
expect(user1.email).toBe('[email protected]');
56+
expect(product1.name).toBe('Laptop Pro');
57+
expect(product1.owner_id).toBe(user1.id);
58+
});
59+
60+
it('should query user products with joins', async () => {
61+
const result = await pg.many(
62+
`SELECT u.name, p.name as product_name, p.price
63+
FROM rls_test.users u
64+
JOIN rls_test.products p ON u.id = p.owner_id
65+
ORDER BY u.name, p.name`
66+
);
67+
68+
expect(result.length).toBeGreaterThan(0);
69+
expect(result[0]).toHaveProperty('name');
70+
expect(result[0]).toHaveProperty('product_name');
71+
});
72+
73+
it('should test RLS context switching', async () => {
74+
// Get a user ID for context
75+
const user = await pg.one(`SELECT id FROM rls_test.users LIMIT 1`);
76+
77+
// Set context to simulate authenticated user with JWT claims
78+
db.setContext({
79+
role: 'authenticated',
80+
'jwt.claims.user_id': user.id
81+
});
82+
83+
// Test auth.uid() function
84+
const uid = await db.one(`SELECT auth.uid() as uid`);
85+
expect(uid.uid).toBe(user.id);
86+
87+
// Test auth.role() function
88+
const role = await db.one(`SELECT auth.role() as role`);
89+
expect(role.role).toBe('authenticated');
90+
91+
// Query should work with RLS policies
92+
const userData = await db.one(
93+
`SELECT id, email FROM rls_test.users WHERE id = $1`,
94+
[user.id]
95+
);
96+
97+
expect(userData.id).toBe(user.id);
98+
});
99+
});

0 commit comments

Comments
 (0)