Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to freeze now, move things around for cleaner testing #12 #17

Merged
merged 14 commits into from
Dec 11, 2023
Merged
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
6 changes: 0 additions & 6 deletions .github/workflows/pg_tap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@ jobs:
version: latest
- name: Supabase Start
run: supabase init && supabase start
- name: Enable pgtle
run: psql -v ON_ERROR_STOP=1 -U postgres -d postgres -h localhost -p 54322 -c "CREATE EXTENSION pg_tle;"
env:
PGPASSWORD: postgres
- name: Install supabase_test_helpers extension using dbdev cli
run: dbdev install --connection postgres://postgres:postgres@localhost:54322/postgres --path .
- name: Move files into supabase tests directory
run: mkdir ./supabase/tests && mv ./tests/* ./supabase/tests/
- name: Run Tests
run: supabase test db
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.idea
.DS_Store
supabase_test_helpers_pglet.sql
supabase_test_helpers_pglet.sql
supabase/config.toml
supabase/functions
supabase/seed.sql
47 changes: 44 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ The following is auto-generated off of comments in the `supabase_test_helpers--0
- [tests.clear_authentication()](#testsclear_authentication)
- [tests.rls_enabled(testing_schema text)](#testsrls_enabledtesting_schema-text)
- [tests.rls_enabled(testing_schema text, testing_table text)](#testsrls_enabledtesting_schema-text-testing_table-text)
- [tests.freeze_time(frozen_time timestamp with time zone)](#testsfreeze_timefrozen_time-timestamp-with-time-zone)
- [tests.unfreeze_time()](#testsunfreeze_time)
- [Contributing](#contributing)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

<!-- include: supabase_test_helpers--0.0.2.sql -->
<!-- include: supabase_test_helpers--0.0.4.sql -->

### tests.create_supabase_user(identifier text, email text, phone text)

Expand Down Expand Up @@ -196,7 +198,43 @@ Example:
ROLLBACK;
```

<!-- /include: supabase_test_helpers--0.0.2.sql -->
### tests.freeze_time(frozen_time timestamp with time zone)

Overwrites the current time from now() to the provided time.

Works out of the box for any normal usage of now(), if you have a function that sets its own search path, such as security definers, then you will need to alter the function to set the search path to include test_overrides BEFORE pg_catalog.
**ONLY do this inside of a pgtap test transaction.**
Example:

```sql
ALTER FUNCTION auth.your_function() SET search_path = test_overrides, public, pg_temp, pg_catalog;
```
View a test example in 05-frozen-time.sql: https://github.com/usebasejump/supabase-test-helpers/blob/main/supabase/tests/05-frozen-time.sql

Parameters:
- `frozen_time` - The time to freeze to. Supports timestamp with time zone, without time zone, date or any other value that can be coerced into a timestamp with time zone.

Returns:
- void

Example:
```sql
SELECT tests.freeze_time('2020-01-01 00:00:00');
```

### tests.unfreeze_time()

Unfreezes the time and restores the original now() function.

Returns:
- void

Example:
```sql
SELECT tests.unfreeze_time();
```

<!-- /include: supabase_test_helpers--0.0.4.sql -->

## Contributing
Yes, please! Anything you've found helpful for testing Supabase projects is welcome. To contribute:
Expand All @@ -206,5 +244,8 @@ Yes, please! Anything you've found helpful for testing Supabase projects is welc
* Add [pgTAP compliant test functions](https://pgtap.org/documentation.html#composeyourself) to the new version
* Comments should be added above each function, follow the examples in the file.
* Create a migration file `supabase_test_helpers--{oldMajor}-{oldMinor}-{oldPatch}--{newMajor}-{newMinor}-{newPatch}.sql` to upgrade to the new version. Include ONLY your migration code, not the entire contents of the new version.
* Add tests for your functions in `tests/XX-your-function-name.sql`
* Add tests for your functions in `supabase/tests/XX-your-function-name.sql`
* You can verify tests work by running `supabase init` to create a config file, `supabase start` to launch it
* Install your updated version with `dbdev install --connection postgres://postgres:postgres@localhost:54322/postgres --path .`
* Run `supabase test db` to run the tests.
* Submit a PR
4 changes: 4 additions & 0 deletions supabase/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Supabase
.branches
.temp
.env
1 change: 1 addition & 0 deletions supabase/migrations/20231210185106_enable_pg_tle.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE EXTENSION IF NOT EXISTS pg_tle;
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
BEGIN;

CREATE EXTENSION supabase_test_helpers;

select plan(16);
select plan(18);

-- test creating a user
select tests.create_supabase_user('testuser');
Expand All @@ -14,6 +15,8 @@ select is((select count(*)::integer from auth.users), 4, 'create_supabase_user s
select is((select tests.get_supabase_uid('testuser')), (select id from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser'), 'get_supabase_uid should return a user');
select is((select (tests.get_supabase_user('testuser') ->> 'id')::uuid), (select id from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser'), 'get_supabase_user should return a user id');
select is(auth.users.raw_app_meta_data, '{}'::jsonb, 'raw_app_meta_data should not be null') from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser';
select ok((select auth.users.created_at IS NOT NULL), 'created_at should not be null') from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser';
select ok((select auth.users.updated_at IS NOT NULL), 'updated_at should not be null') from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser';
select is((select tests.get_supabase_user('testuser2') ->> 'email'), (select email::text from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser2'), 'get_supabase_user should return a user email');
select is((select tests.get_supabase_user('testuser3') ->> 'phone'), (select phone::text from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser3'), 'get_supabase_user should return a user phone');
select is((select tests.get_supabase_user('testuser4') -> 'raw_user_meta_data' ->> 'has'), (select raw_user_meta_data ->> 'has' from auth.users where raw_user_meta_data ->> 'test_identifier' = 'testuser4'), 'get_supabase_user should return custom metadata');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
BEGIN;

CREATE EXTENSION supabase_test_helpers;

select plan(9);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
BEGIN;

CREATE EXTENSION supabase_test_helpers;

select plan(8);
Expand Down
135 changes: 135 additions & 0 deletions supabase/tests/05-frozen-time.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
--- function that specifically sets the search path so we can test how it handles overriden functions
CREATE OR REPLACE FUNCTION search_path_setting_function()
RETURNS timestamp with time zone
AS $$
SELECT now()
$$ LANGUAGE sql
SECURITY DEFINER
SET search_path = public, pg_catalog;


BEGIN;
CREATE EXTENSION supabase_test_helpers;

select plan(11);

-- freeze the time
SELECT tests.freeze_time('2020-01-01 00:00:00');

-- search_path now include test_overrides at the front
select ok(
(SELECT current_setting('search_path')::text LIKE 'test_overrides,%'),
'search_path includes test_overrides at the front'
);

-- verify frozen time
select is(
(SELECT now()),
'2020-01-01 00:00:00'::timestamp with time zone,
'now() is frozen in time'
);


-- create a test table to verify that now() is overwritten on tables
CREATE TABLE test_table (
id int,
key text,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now()
);

-- add a trigger to update updated_at when the row is updated
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS trigger
AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END
$$ LANGUAGE plpgsql;

CREATE TRIGGER update_updated_at
BEFORE UPDATE ON test_table
FOR EACH ROW
EXECUTE PROCEDURE update_updated_at();

-- insert a row and verify that the created_at and updated_at are frozen in time
INSERT INTO test_table (id, key) VALUES (1, 'test');
select is(
(SELECT created_at FROM test_table WHERE id = 1),
'2020-01-01 00:00:00'::timestamp with time zone,
'created_at is frozen in time'
);
select is(
(SELECT updated_at FROM test_table WHERE id = 1),
'2020-01-01 00:00:00'::timestamp with time zone,
'updated_at is frozen in time'
);

-- change frozen time to test updated_at timestamp
SELECT tests.freeze_time('2021-01-01 00:00:00');

-- update the row and verify that the updated_at is frozen in time
UPDATE test_table SET key = 'test2' WHERE id = 1;

select is(
(SELECT updated_at FROM test_table WHERE id = 1),
'2021-01-01 00:00:00'::timestamp with time zone,
'updated_at is frozen in time'
);

-- verify supports many different inputs correctly
SELECT tests.freeze_time('2020-02-02 00:00:00'::timestamp without time zone);
select is(
(SELECT now()),
'2020-02-02 00:00:00'::timestamp with time zone,
'Supports timestamp without time zone'
);

SELECT tests.freeze_time('2020-03-03'::date);
select is(
(SELECT now()),
'2020-03-03 00:00:00'::timestamp with time zone,
'Supports date'
);

SELECT tests.freeze_time(CURRENT_DATE);
select is(
(SELECT now()),
CURRENT_DATE::timestamp with time zone,
'Supports CURRENT_DATE'
);

SELECT tests.unfreeze_time();

select is(
(SELECT now()),
(SELECT pg_catalog.now()),
'unfreeze_time() restores now() to the original function'
);


---- working with functions that have set their own search_path

SELECT tests.freeze_time('2020-01-01 00:00:00');

-- function still returns the non frozen time
select is(
(SELECT search_path_setting_function()),
(SELECT pg_catalog.now()),
'function still returns the non frozen time'
);

-- we can run an alter command to alter it specifically
ALTER FUNCTION search_path_setting_function()
SET search_path = test_overrides, public, pg_catalog;

-- now it returns the frozen time
select is(
(SELECT search_path_setting_function()),
'2020-01-01 00:00:00'::timestamp with time zone,
'function returns the frozen time'
);

SELECT * FROM finish();
ROLLBACK;
25 changes: 25 additions & 0 deletions supabase/tests/06-frozen-time-cleanup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--- secondary test to confirm that the search_path is restored after a rollback
BEGIN;
CREATE EXTENSION supabase_test_helpers;

select plan(2);

-- confirm test_overrides no longer in search path
select ok(
(SELECT current_setting('search_path') NOT LIKE 'test_overrides,%'),
'test_overrides no longer in search path'
);


-- freeze the time
SELECT tests.freeze_time('2020-01-01 00:00:00');

-- function still returns the non frozen time
select is(
(SELECT search_path_setting_function()),
(SELECT pg_catalog.now()),
'function still returns the non frozen time'
);

SELECT * FROM finish();
ROLLBACK;
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
BEGIN;
CREATE EXTENSION supabase_test_helpers;

select plan(12);

-- create a posts table that references the auth.users table
Expand Down
Loading
Loading