Skip to content

Commit fde6646

Browse files
authored
Merge pull request #23 from stac-utils/pgtaptests
PgTAP Tests
2 parents 16c222c + 88d9e5e commit fde6646

File tree

7 files changed

+68
-219
lines changed

7 files changed

+68
-219
lines changed

docker-compose.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ services:
2424
- POSTGRES_USER=username
2525
- POSTGRES_PASSWORD=password
2626
- POSTGRES_DB=postgis
27+
- PGUSER=username
28+
- PGPASSWORD=password
29+
- PGDATABASE=postgis
2730
ports:
2831
- "5432:5432"
2932
volumes:

scripts/test

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,10 @@ Runs tests for the project.
1616

1717
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
1818
echo "Running database tests..."
19-
# TODO: Fix these tests
20-
# scripts/server --detach;
21-
# docker-compose \
22-
# run --rm \
23-
# -e PGUSER=username \
24-
# -e PGPASSWORD=password \
25-
# -e PGHOST=database \
26-
# database /opt/src/test/test.sh;
19+
scripts/server --detach;
20+
docker-compose \
21+
exec -T \
22+
database /opt/src/test/test.sh;
2723

2824
echo "Running pypgstac tests..."
2925
docker-compose \

sql/002_collections.sql

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,3 @@ CREATE OR REPLACE FUNCTION all_collections() RETURNS jsonb AS $$
4747
SELECT jsonb_agg(content) FROM collections;
4848
;
4949
$$ LANGUAGE SQL SET SEARCH_PATH TO pgstac, public;
50-
51-
52-
53-
54-
55-
56-
/* CREATE OR REPLACE FUNCTION collections_trigger_func()
57-
RETURNS TRIGGER AS $$
58-
BEGIN
59-
IF pg_trigger_depth() = 1 THEN
60-
PERFORM create_collection(NEW.content);
61-
RETURN NULL;
62-
END IF;
63-
RETURN NEW;
64-
END;
65-
$$ LANGUAGE PLPGSQL SET SEARCH_PATH TO pgstac, public;
66-
67-
CREATE TRIGGER collections_trigger
68-
BEFORE INSERT ON collections
69-
FOR EACH ROW EXECUTE PROCEDURE collections_trigger_func();
70-
*/

sql/003_items.sql

Lines changed: 0 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,6 @@ CREATE TABLE items_template (
1919

2020
ALTER TABLE items_template ADD PRIMARY KEY (id);
2121

22-
/*
23-
CREATE TABLE IF NOT EXISTS items_search (
24-
id text NOT NULL,
25-
geometry geometry NOT NULL,
26-
properties jsonb,
27-
collection_id text NOT NULL,
28-
datetime timestamptz NOT NULL
29-
)
30-
PARTITION BY RANGE (datetime)
31-
;
32-
33-
CREATE TABLE IF NOT EXISTS items_search_template (
34-
LIKE items_search
35-
)
36-
;
37-
ALTER TABLE items_search_template ADD PRIMARY KEY (id);
38-
*/
3922

4023
DELETE from partman.part_config WHERE parent_table = 'pgstac.items';
4124
SELECT partman.create_parent(
@@ -79,55 +62,6 @@ CREATE TYPE item AS (
7962
);
8063

8164

82-
/*
83-
Converts single feature into an items row
84-
*/
85-
86-
/*
87-
CREATE OR REPLACE FUNCTION feature_to_item(value jsonb) RETURNS item AS $$
88-
SELECT
89-
value->>'id' as id,
90-
CASE
91-
WHEN value->>'geometry' IS NOT NULL THEN
92-
ST_GeomFromGeoJSON(value->>'geometry')
93-
WHEN value->>'bbox' IS NOT NULL THEN
94-
ST_MakeEnvelope(
95-
(value->'bbox'->>0)::float,
96-
(value->'bbox'->>1)::float,
97-
(value->'bbox'->>2)::float,
98-
(value->'bbox'->>3)::float,
99-
4326
100-
)
101-
ELSE NULL
102-
END as geometry,
103-
properties_idx(value ->'properties') as properties,
104-
value->>'collection' as collection_id,
105-
(value->'properties'->>'datetime')::timestamptz as datetime
106-
;
107-
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE SET SEARCH_PATH TO pgstac,public;
108-
*/
109-
/*
110-
Takes a single feature, an array of features, or a feature collection
111-
and returns a set up individual items rows
112-
*/
113-
/*
114-
CREATE OR REPLACE FUNCTION features_to_items(value jsonb) RETURNS SETOF item AS $$
115-
WITH features AS (
116-
SELECT
117-
jsonb_array_elements(
118-
CASE
119-
WHEN jsonb_typeof(value) = 'array' THEN value
120-
WHEN value->>'type' = 'Feature' THEN '[]'::jsonb || value
121-
WHEN value->>'type' = 'FeatureCollection' THEN value->'features'
122-
ELSE NULL
123-
END
124-
) as value
125-
)
126-
SELECT feature_to_item(value) FROM features
127-
;
128-
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE SET SEARCH_PATH TO pgstac,public;
129-
*/
130-
13165
CREATE OR REPLACE FUNCTION get_item(_id text) RETURNS jsonb AS $$
13266
SELECT content FROM items WHERE id=_id;
13367
$$ LANGUAGE SQL SET SEARCH_PATH TO pgstac,public;
@@ -186,62 +120,6 @@ END LOOP;
186120
END;
187121
$$ LANGUAGE PLPGSQL;
188122

189-
/* Trigger Function to cascade inserts/updates/deletes
190-
from items table to items_search table */
191-
/*
192-
ALTER TABLE items_search ADD CONSTRAINT items_search_fk
193-
FOREIGN KEY (id) REFERENCES items(id)
194-
ON DELETE CASCADE DEFERRABLE;
195-
196-
CREATE OR REPLACE FUNCTION items_trigger_func()
197-
RETURNS TRIGGER AS $$
198-
DECLARE
199-
BEGIN
200-
IF TG_OP = 'UPDATE' THEN
201-
RAISE NOTICE 'DELETING % BEFORE UPDATE', OLD;
202-
DELETE FROM items_search WHERE id = OLD.id AND datetime = (OLD.content->'properties'->>'datetime')::timestamptz;
203-
END IF;
204-
205-
INSERT INTO items_search SELECT * FROM feature_to_item(NEW.content);
206-
RETURN NEW;
207-
END;
208-
$$ LANGUAGE PLPGSQL SET SEARCH_PATH TO pgstac,public;
209-
210-
DROP TRIGGER IF EXISTS items_insert_trigger ON items;
211-
CREATE TRIGGER items_insert_trigger
212-
AFTER INSERT ON items
213-
FOR EACH ROW EXECUTE PROCEDURE items_trigger_func();
214-
215-
DROP TRIGGER IF EXISTS items_update_trigger ON items;
216-
CREATE TRIGGER items_update_trigger
217-
AFTER UPDATE ON items
218-
FOR EACH ROW
219-
WHEN (NEW.content IS DISTINCT FROM OLD.content)
220-
EXECUTE PROCEDURE items_trigger_func();
221-
*/
222-
223-
/* Trigger Function to cascade inserts/updates/deletes
224-
from items table to items_search table */
225-
/*
226-
CREATE OR REPLACE FUNCTION items_search_trigger_delete_func()
227-
RETURNS TRIGGER AS $$
228-
DECLARE
229-
BEGIN
230-
RAISE NOTICE 'Deleting from items_search: % Depth: %', OLD, pg_trigger_depth();
231-
IF pg_trigger_depth()<3 THEN
232-
RAISE NOTICE 'DELETING WITH datetime';
233-
DELETE FROM items_search WHERE id=OLD.id AND datetime=OLD.datetime;
234-
RETURN NULL;
235-
END IF;
236-
RETURN OLD;
237-
END;
238-
$$ LANGUAGE PLPGSQL SET SEARCH_PATH TO pgstac,public;
239-
240-
DROP TRIGGER IF EXISTS items_search_delete_trigger ON items_search;
241-
CREATE TRIGGER items_search_delete_trigger
242-
BEFORE DELETE ON items_search
243-
FOR EACH ROW EXECUTE PROCEDURE items_search_trigger_delete_func();
244-
*/
245123
CREATE OR REPLACE FUNCTION backfill_partitions()
246124
RETURNS VOID AS $$
247125
DECLARE

sql/004_search.sql

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,5 @@
11
SET SEARCH_PATH TO pgstac, public;
22

3-
/*
4-
View to get a table of available items partitions
5-
with date ranges
6-
*/
7-
DROP VIEW IF EXISTS items_partitions;
8-
CREATE VIEW items_partitions AS
9-
WITH base AS
10-
(SELECT
11-
c.oid::pg_catalog.regclass::text as partition,
12-
pg_catalog.pg_get_expr(c.relpartbound, c.oid) as _constraint,
13-
regexp_matches(
14-
pg_catalog.pg_get_expr(c.relpartbound, c.oid),
15-
E'\\(''\([0-9 :+-]*\)''\\).*\\(''\([0-9 :+-]*\)''\\)'
16-
) as t,
17-
reltuples::bigint as est_cnt
18-
FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i
19-
WHERE c.oid = i.inhrelid AND i.inhparent = 'items'::regclass)
20-
SELECT partition, tstzrange(
21-
t[1]::timestamptz,
22-
t[2]::timestamptz
23-
), est_cnt
24-
FROM base
25-
WHERE est_cnt >0
26-
ORDER BY 2 desc;
27-
283

294
CREATE OR REPLACE FUNCTION items_by_partition(
305
IN _where text DEFAULT 'TRUE',

test/pgtap.sql

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
\pset format unaligned
77
\pset tuples_only true
88
\pset pager off
9+
\timing off
910

1011
-- Revert all changes on failure.
1112
\set ON_ERROR_ROLLBACK 1
@@ -17,15 +18,23 @@ CREATE EXTENSION IF NOT EXISTS pgtap;
1718
SET SEARCH_PATH TO pgstac, pgtap, public;
1819

1920
-- Plan the tests.
20-
SELECT plan(50);
21+
SELECT plan(62);
2122
--SELECT * FROM no_plan();
2223

2324
-- Run the tests.
2425

2526
-- Core
27+
28+
-- Check that schema exists
2629
SELECT has_schema('pgstac'::name);
30+
31+
-- Check that PostGIS and PG_Partman extensions are installed and available on the path
2732
SELECT has_extension('postgis');
2833
SELECT has_extension('pg_partman');
34+
35+
SELECT has_table('pgstac'::name, 'migrations'::name);
36+
37+
2938
SELECT has_function('pgstac'::name, 'textarr', ARRAY['jsonb']);
3039
SELECT results_eq(
3140
$$ SELECT textarr('["a","b","c"]'::jsonb) $$,
@@ -46,48 +55,67 @@ SELECT results_eq(
4655
$$ SELECT '{"a":1,"b":"b"}'::jsonb $$,
4756
'properties_idx returns slimmed lower case jsonb'
4857
);
58+
59+
SELECT has_function('pgstac'::name, 'stac_geom', ARRAY['jsonb']);
60+
SELECT has_function('pgstac'::name, 'stac_datetime', ARRAY['jsonb']);
61+
SELECT has_function('pgstac'::name, 'jsonb_paths', ARRAY['jsonb']);
62+
SELECT has_function('pgstac'::name, 'jsonb_obj_paths', ARRAY['jsonb']);
63+
SELECT has_function('pgstac'::name, 'jsonb_val_paths', ARRAY['jsonb']);
64+
SELECT has_function('pgstac'::name, 'path_includes', ARRAY['text[]','text[]']);
65+
SELECT has_function('pgstac'::name, 'path_excludes', ARRAY['text[]','text[]']);
66+
SELECT has_function('pgstac'::name, 'jsonb_obj_paths_filtered', ARRAY['jsonb','text[]','text[]']);
67+
SELECT has_function('pgstac'::name, 'empty_arr', ARRAY['anyarray']);
68+
SELECT has_function('pgstac'::name, 'filter_jsonb', ARRAY['jsonb','text[]','text[]']);
69+
70+
4971
-- Collections
5072
SELECT has_table('pgstac'::name, 'collections'::name);
5173
SELECT col_is_pk('pgstac'::name, 'collections'::name, 'id', 'collections has primary key');
74+
5275
SELECT has_function('pgstac'::name, 'create_collection', ARRAY['jsonb']);
76+
SELECT has_function('pgstac'::name, 'update_collection', ARRAY['jsonb']);
77+
SELECT has_function('pgstac'::name, 'upsert_collection', ARRAY['jsonb']);
5378
SELECT has_function('pgstac'::name, 'get_collection', ARRAY['text']);
79+
SELECT has_function('pgstac'::name, 'delete_collection', ARRAY['text']);
5480
SELECT has_function('pgstac'::name, 'all_collections', NULL);
55-
SELECT has_function('pgstac'::name, 'collection_bbox', ARRAY['text']);
56-
SELECT has_function('pgstac'::name, 'collection_temporal_extent', ARRAY['text']);
57-
SELECT has_function('pgstac'::name, 'update_collection_extents', NULL);
58-
59-
SELECT has_function('pgstac'::name, 'collections_trigger_func', 'collections trigger function exists');
60-
SELECT has_trigger('pgstac'::name, 'collections', 'collections_trigger', 'trigger exists on collections table');
6181

6282

6383

6484

6585

6686
-- Items
6787
SELECT has_table('pgstac'::name, 'items'::name);
68-
SELECT col_is_pk('pgstac'::name, 'items', 'id', NULL);
6988

70-
SELECT has_table('pgstac'::name, 'items_search'::name);
71-
--SELECT col_is_pk('pgstac'::name, 'items_search'::name, 'id', 'id should be primary key');
72-
SELECT is_indexed('pgstac'::name, 'items_search'::name, ARRAY['datetime','id']);
73-
SELECT is_indexed('pgstac'::name, 'items_search'::name, 'properties');
74-
SELECT is_indexed('pgstac'::name, 'items_search'::name, 'geometry');
75-
SELECT is_indexed('pgstac'::name, 'items_search'::name, 'collection_id');
89+
SELECT is_indexed('pgstac'::name, 'items'::name, ARRAY['datetime','id']);
90+
SELECT is_indexed('pgstac'::name, 'items'::name, 'properties');
91+
SELECT is_indexed('pgstac'::name, 'items'::name, 'geometry');
92+
SELECT is_indexed('pgstac'::name, 'items'::name, 'collection_id');
7693

7794
SELECT has_type('pgstac'::name, 'item'::name);
78-
SELECT is_partitioned('pgstac'::name,'items_search'::name);
95+
SELECT is_partitioned('pgstac'::name,'items'::name);
7996

8097

81-
SELECT has_function('pgstac'::name, 'feature_to_item', ARRAY['jsonb']);
82-
SELECT has_function('pgstac'::name, 'features_to_items', ARRAY['jsonb']);
8398
SELECT has_function('pgstac'::name, 'get_item', ARRAY['text']);
8499
SELECT has_function('pgstac'::name, 'delete_item', ARRAY['text']);
85100
SELECT has_function('pgstac'::name, 'create_item', ARRAY['jsonb']);
101+
SELECT has_function('pgstac'::name, 'update_item', ARRAY['jsonb']);
102+
SELECT has_function('pgstac'::name, 'upsert_item', ARRAY['jsonb']);
103+
86104

87-
SELECT has_function('pgstac'::name, 'items_trigger_func', 'items trigger function exists');
88-
SELECT has_trigger('pgstac'::name, 'items'::name, 'items_trigger', 'items table has trigger');
89105

90-
SELECT has_view('pgstac'::name, 'items_search_partitions'::name, 'items_search_partitions view exists');
106+
SELECT has_function('pgstac'::name, 'analyze_empty_partitions', NULL);
107+
SELECT has_function('pgstac'::name, 'backfill_partitions', NULL);
108+
SELECT has_function('pgstac'::name, 'items_trigger_stmt_func', NULL);
109+
110+
111+
SELECT has_view('pgstac'::name, 'all_items_partitions'::name, 'all_items_partitions view exists');
112+
SELECT has_view('pgstac'::name, 'items_partitions'::name, 'items_partitions view exists');
113+
114+
-- tools to update collection extents based on extents in items
115+
SELECT has_function('pgstac'::name, 'collection_bbox', ARRAY['text']);
116+
SELECT has_function('pgstac'::name, 'collection_temporal_extent', ARRAY['text']);
117+
SELECT has_function('pgstac'::name, 'update_collection_extents', NULL);
118+
91119

92120

93121
-- Search
@@ -107,7 +135,6 @@ SELECT has_function('pgstac'::name, 'filter_by_order', ARRAY['item','jsonb','tex
107135
SELECT has_function('pgstac'::name, 'search_dtrange', ARRAY['jsonb']);
108136
SELECT has_function('pgstac'::name, 'search', ARRAY['jsonb']);
109137

110-
111138
-- Finish the tests and clean up.
112139
SELECT * FROM finish();
113-
ROLLBACK;
140+
ROLLBACK;

test/test.sh

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
11
#!/bin/bash
2-
tempid=$(cat /dev/urandom | tr -dc 'a-zA-Z' | fold -w 8 | head -n 1)
3-
tempdb="pgstac_tst_${tmpid}"
4-
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
5-
6-
7-
createdb $tempdb;
8-
export PGDATABASE=$tempdb
9-
10-
cd $DIR/..
11-
psql -f pgstac.sql
12-
13-
14-
cat test/testdata/collections.ndjson | psql -c "copy pgstac.collections_staging FROM stdin"
15-
cat test/testdata/items.ndjson | psql -c "copy pgstac.items_staging FROM stdin"
16-
17-
psql -X -f test/test.sql >/tmp/$tempdb.out
18-
19-
cmp --silent /tmp/$tempdb.out test/test.out && echo '### SUCCESS: Files Tests Pass! ###' || echo '### WARNING: Tests did not pass! ###' && diff /tmp/$tempdb.out test/test.out
20-
21-
dropdb $tempdb;
22-
rm /tmp/$tempdb.out
2+
TESTOUTPUT=$(psql -X -f $(dirname $0)/pgtap.sql)
3+
if [ $? != 0 ]; then
4+
echo "Problem connecting to database to run tests."
5+
exit 1
6+
fi
7+
echo "$TESTOUTPUT" | grep '^not'
8+
if [ $? == 0 ]; then
9+
exit 1
10+
else
11+
echo "All PGTap Tests Passed!"
12+
exit 0
13+
fi

0 commit comments

Comments
 (0)