test(db): Add baseline tests for wh_user_dimension (#1454)

This sets up the configuration for running a new suite of tests that are
written in sql, to test the sql logic implemented in plpgsql functions
and triggers. It is primarily designed to provides tests for the data
warehouse functionality that is implemented purely in sql.

The infrastructure to run these tests leverages docker. It creates one
docker container using the `library/postgres` image and provisions the
database with the boundary sql migrations and test helper functions.  A
separate docker container is run that has the pgtap extension and
pg_prove cli to execute the tests.

As noted, pgtap is used for the tests. This postgresql extension
provides a number of helpful assertion functions to make writing sql
tests easier. It also, along with the pg_prove cli, provides readable
test output.

Along with the new testing infrastructure this commit establishes a
baseline of tests for the wh_user_dimension:

- Unit tests for individual views and functions:
    - whx_user_dimension_source
    - whx_user_dimension_target
    - wh_upsert_user
- Integration tests for that verify that the wh_user_dimension gets
  populated correctly when sessions are inserted or updated. This
  ensures that:
    - the trigger runs on session insert
    - the trigger results in the correct changes to the
      wh_user_dimension.

This commit provides a `Makefile` to run the tests locally that provides
support for:

- Setting the postgres docker image to easily test multiple versions.
- Passing through options to pg_prove
- Passing the test list to run individual tests
- Additional targets to separately startup the database image to quickly
  re-run tests while developing new tests.

Lastly configures circleci to run this test suite as a matrix build
in parallel with the other tests. The matrix build tests multiple
versions of postgres:

- latest
- 13-alpine
- 12-alpine
- 11-alpine

See:
    https://pgtap.org/
This commit is contained in:
Timothy Messier authored and GitHub committed 2021-08-11 13:25:32 -04:00
1 parent 248e1f36b5
commit 624bdbf0c2
24 files changed
+1238

No files matched your search

+44
View File
@@ -5,6 +5,16 @@
# Orb 'circleci/slack@3.4.2' resolved to 'circleci/slack@3.4.2'
version: 2
jobs:
test-sql-13-alpine:
machine:
image: ubuntu-1604:201903-01
steps:
- checkout
- run:
command: |
make test-sql POSTGRES_DOCKER_IMAGE_BASE=docker.mirror.hashicorp.services/postgres PG_DOCKER_TAG=13-alpine
name: Run SQL PgTap Tests
working_directory: ~/boundary
bundle-releases:
docker:
- image: docker.mirror.hashicorp.services/circleci/buildpack-deps
@@ -237,6 +247,16 @@ jobs:
name: Save package cache
paths:
- .buildcache/packages/store
test-sql-11-alpine:
machine:
image: ubuntu-1604:201903-01
steps:
- checkout
- run:
command: |
make test-sql POSTGRES_DOCKER_IMAGE_BASE=docker.mirror.hashicorp.services/postgres PG_DOCKER_TAG=11-alpine
name: Run SQL PgTap Tests
working_directory: ~/boundary
build-common-layers:
machine:
image: ubuntu-1604:202007-01
@@ -865,6 +885,16 @@ jobs:
name: Save package cache
paths:
- .buildcache/packages/store
test-sql-12-alpine:
machine:
image: ubuntu-1604:201903-01
steps:
- checkout
- run:
command: |
make test-sql POSTGRES_DOCKER_IMAGE_BASE=docker.mirror.hashicorp.services/postgres PG_DOCKER_TAG=12-alpine
name: Run SQL PgTap Tests
working_directory: ~/boundary
solaris_amd64_package:
docker:
- image: docker.mirror.hashicorp.services/circleci/buildpack-deps
@@ -1435,6 +1465,16 @@ jobs:
name: Save package cache
paths:
- .buildcache/packages/store
test-sql-latest:
machine:
image: ubuntu-1604:201903-01
steps:
- checkout
- run:
command: |
make test-sql POSTGRES_DOCKER_IMAGE_BASE=docker.mirror.hashicorp.services/postgres PG_DOCKER_TAG=latest
name: Run SQL PgTap Tests
working_directory: ~/boundary
workflows:
build-7cb7957a6e75af58:
jobs:
@@ -1504,6 +1544,10 @@ workflows:
default:
jobs:
- build
- test-sql-latest
- test-sql-11-alpine
- test-sql-12-alpine
- test-sql-13-alpine
- algolia-index:
filters:
branches:
+12
View File
@@ -0,0 +1,12 @@
machine:
image: 'ubuntu-1604:201903-01'
working_directory: ~/boundary
parameters:
postgres-version:
type: string
steps:
- checkout
- run:
name: "Run SQL PgTap Tests"
command: |
make test-sql POSTGRES_DOCKER_IMAGE_BASE=docker.mirror.hashicorp.services/postgres PG_DOCKER_TAG=<< parameters.postgres-version >>
+4
View File
@@ -1,5 +1,9 @@
jobs:
- build
- test-sql:
matrix:
parameters:
postgres-version: ["latest", "11-alpine", "12-alpine", "13-alpine"]
- algolia-index:
filters:
branches:
+3
View File
@@ -155,6 +155,9 @@ website-start:
test-ci: install-go
~/.go/bin/go test ./... -v $(TESTARGS) -timeout 120m
test-sql:
$(MAKE) -C internal/db/sqltest/ test
test:
~/.go/bin/go test ./... -timeout 30m
+81
View File
@@ -0,0 +1,81 @@
all: test
CWD := $(shell pwd)
# Version of postgres docker image for test database
PG_DOCKER_TAG ?= 13-alpine
# Version of pg_tap docker image
PG_TAP_DOCKER_TAG ?= pg13
# Pass through options to pg_prove
# See: https://pgtap.org/pg_prove.html
PROVE_OPTS ?=
TESTS ?= tests/setup/*.sql \
tests/wh/*/*.sql
POSTGRES_DOCKER_IMAGE_BASE ?= postgres
POSTGRES_DOCKER_IMAGE := $(POSTGRES_DOCKER_IMAGE_BASE):$(PG_DOCKER_TAG)
PG_TAP_DOCKER_IMAGE_BASE ?= subzerocloud/pgtap
PG_TAP_DOCKER_IMAGE := $(PG_TAP_DOCKER_IMAGE_BASE):$(PG_TAP_DOCKER_TAG)
# re-write paths for docker
dockerized_tests = $(patsubst tests/%,/test/%,$(TESTS))
test:
@echo Using $(POSTGRES_DOCKER_IMAGE)
@echo Using $(PG_TAP_DOCKER_IMAGE)
@docker run -d \
--name boundary-sql-tests \
-e POSTGRES_PASSWORD=boundary \
-e POSTGRES_USER=boundary \
-e POSTGRES_DB=boundary \
-v "$(CWD)/../schema/migrations/postgres":/migrations \
-v "$(CWD)/initdb.d":/docker-entrypoint-initdb.d/ \
$(POSTGRES_DOCKER_IMAGE)
@docker run -it --rm \
--name test \
--link boundary-sql-tests:db \
-e DATABASE=boundary \
-e HOST=db \
-e PORT=5432 \
-e USER=boundary \
-e PASSWORD=boundary \
-e TESTS="$(PROVE_OPTS) $(dockerized_tests)" \
-v "$(CWD)/tests":/test \
$(PG_TAP_DOCKER_IMAGE); \
(ret=$$?; docker stop boundary-sql-tests &>/dev/null && docker rm -v boundary-sql-tests &>/dev/null && exit $$ret)
database-up:
@echo Using $(POSTGRES_DOCKER_IMAGE)
@docker run -d \
--name boundary-sql-tests \
-e POSTGRES_PASSWORD=boundary \
-e POSTGRES_USER=boundary \
-e POSTGRES_DB=boundary \
-v "$(CWD)/../schema/migrations/postgres":/migrations \
-v "$(CWD)/initdb.d":/docker-entrypoint-initdb.d/ \
$(POSTGRES_DOCKER_IMAGE)
run-tests:
@echo Using $(PG_TAP_DOCKER_IMAGE)
@docker run -it --rm \
--name test \
--link boundary-sql-tests:db \
-e DATABASE=boundary \
-e HOST=db \
-e PORT=5432 \
-e USER=boundary \
-e PASSWORD=boundary \
-e TESTS="$(PROVE_OPTS) $(dockerized_tests)" \
-v "$(CWD)/tests":/test \
$(PG_TAP_DOCKER_IMAGE)
clean:
docker stop boundary-sql-tests || true
docker rm -v boundary-sql-tests || true
.PHONY: all clean test database-up run-tests
+73
View File
@@ -0,0 +1,73 @@
# SQL Tests
This test suite is used to test behavior of the database logic.
In particular the data warehouse implementation is
completely in sql via plpgsql, functions, and triggers.
This test suite is also implemented directly in sql.
## Organization
- `initdb.d`: contains init scripts/sql that is run on the test database
when it starts. It ensures the sql migrations are run and creates test helper
functions.
- `tests`: contains the tests. Each file can contain only a single test that
runs in a transaction so it can rollback.
The tests leverage the
[pgTap](https://pgtap.org/documentation.html)
postgres extension to make assertions and provide
more readable test output.
## Usage
To run the test run `make` or `make test`. This will:
- Start a docker `postgres` container and initialize it.
- Start a docker `pgtap` container to execute the tests.
When writing new tests
it can be faster to keep the database up
and just re-run the tests.
This can be done by running:
```bash
# starts database docker image in the background
make database-up
# runs the tests, call this multiple times while implementing new tests.
make run-tests
# to clean up
make clean
```
You can also run individual tests:
```bash
# run a single test file
make TEST=tests/setup/wtt_load.sql
# run a single test file with the database already created.
make run-tests TEST=tests/setup/wtt_load.sql
# run a directory of tests
make TEST=tests/setup/*.sql
```
You can pass through options to `pg_prove`.
See [the docs](https://pgtap.org/pg_prove.html)
for available options, i.e:
```bash
# run tests in parallel with verbose output
make PROVE_OPTS='-j9 -v'
```
Different versions of postgres can easily be tested:
```bash
make PG_DOCKER_TAG=latest
make PG_DOCKER_TAG=13-alpine
make PG_DOCKER_TAG=12-alpine
make PG_DOCKER_TAG=11-alpine
```
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# This script is designed to run as an init script in a postgres docker container.
# The docker-entrypoint.sh script does not traverse a nested directory
# structue to load sql files at container start. However, it does allow for
# running .sh files. This script should run first to execute the boundary sql
# migration files in the correct order.
#
# See Initialization Scripts https://hub.docker.com/_/postgres
set -e
shopt -s globstar
## Taken from postgres docker image's docker-entrypoint.sh
## See: https://github.com/docker-library/postgres/blob/517c64f87e6661366b415df3f2273c76cea428b0/docker-entrypoint.sh#L175-L187
# Execute sql script, passed via stdin (or -f flag of pqsl)
# usage: docker_process_sql [psql-cli-args]
# ie: docker_process_sql --dbname=mydb <<<'INSERT ...'
# ie: docker_process_sql -f my-file.sql
# ie: docker_process_sql <my-file.sql
docker_process_sql() {
local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
if [ -n "$POSTGRES_DB" ]; then
query_runner+=( --dbname "$POSTGRES_DB" )
fi
PGHOST= PGHOSTADDR= "${query_runner[@]}" "$@"
}
# Run migrations in order.
for file in $(ls -v /migrations/**/*.sql); do
echo running "$file"
docker_process_sql -f "$file"
done
@@ -0,0 +1,30 @@
begin;
-- wtt_load populates tables for the given test persona and set of aggregates.
-- Valid personas are:
-- * colors
-- * widgets
--
-- Valid aggregates:
-- * iam
-- * auth
-- * hosts
-- * targets
--
-- Note that some aggregates depend on data from other aggretates, so the order
-- that they are passed to this function matters.
create function wtt_load(persona text, variadic aggregates text[])
returns void
as $$
declare
agg text;
q text;
begin
foreach agg in array aggregates
loop
q = format('select _wtt_load_%I_%I()', persona, agg);
execute q;
end loop;
end;
$$ language plpgsql;
commit;
@@ -0,0 +1,216 @@
begin;
-- _wtt_load_colors_iam populates all iam_ tables for the colors persona.
-- iam does not depend on any other aggregates, but others depend on it,
-- as such is it should be first in the list.
create function _wtt_load_colors_iam()
returns void
as $$
begin
-- Add organizations
insert into iam_scope
(parent_id, type, public_id, name)
values
('global', 'org', 'o_____colors', 'Colors R Us');
-- Add projects to the organizations
insert into iam_scope
(parent_id, type, public_id, name)
values
('o_____colors', 'project', 'p____bcolors', 'Blue Color Mill'),
('o_____colors', 'project', 'p____rcolors', 'Red Color Mill');
-- Add global users
insert into iam_user
(scope_id, public_id, name)
values
('global', 'u_______gary', 'Gary'),
('global', 'u_______gina', 'Gina'),
('global', 'u______nancy', 'Nancy');
-- Add organization users
insert into iam_user
(scope_id, public_id, name)
values
('o_____colors', 'u______clare', 'Clare'),
('o_____colors', 'u______cindy', 'Cindy'),
('o_____colors', 'u______carly', 'Carly'),
('o_____colors', 'u______ciara', 'Ciara');
insert into iam_group
(scope_id, public_id, name)
values
('global', 'g___gg-group', 'Global Group'),
('o_____colors', 'g___oc-group', 'Colors R Us Group'),
('p____bcolors', 'g___cb-group', 'Blue Color Group'),
('p____rcolors', 'g___cr-group', 'Red Color Group');
insert into iam_group_member_user
(group_id, member_id)
values
('g___gg-group', 'u_______gary'),
('g___oc-group', 'u______clare'),
('g___cb-group', 'u______cindy'),
('g___cr-group', 'u______carly');
insert into iam_role
(scope_id, grant_scope_id, public_id, name)
values
('p____bcolors', 'p____bcolors', 'r_pp_bc__mix', 'Color Mixer'),
('p____rcolors', 'p____rcolors', 'r_pp_rc__mix', 'Color Mixer'),
('o_____colors', 'p____bcolors', 'r_op_bc__art', 'Blue Color Artist'),
('o_____colors', 'p____rcolors', 'r_op_rc__art', 'Red Color Artist'),
('o_____colors', 'o_____colors', 'r_oo_____art', 'Color Artist'),
('global', 'o_____colors', 'r_go____name', 'Color Namer'),
('global', 'p____bcolors', 'r_gp____spec', 'Blue Color Inspector'),
('global', 'global', 'r_gg_____buy', 'Purchaser'),
('global', 'global', 'r_gg____shop', 'Shopper');
insert into iam_role_grant
(role_id, canonical_grant, raw_grant)
values
('r_gg_____buy', 'type=*;action=purchase', 'purchase anything'),
('r_gg____shop', 'type=*;action=view', 'view anything'),
('r_go____name', 'type=color;action=name', 'name colors'),
('r_gp____spec', 'type=color;action=inspect', 'inspect colors'),
('r_oo_____art', 'type=color;action=create', 'create color'),
('r_op_bc__art', 'type=color;action=create', 'create color'),
('r_op_rc__art', 'type=color;action=create', 'create color'),
('r_pp_bc__mix', 'type=color;action=mix', 'mix color'),
('r_pp_rc__mix', 'type=color;action=mix', 'mix color');
insert into iam_group_role
(role_id, principal_id)
values
('r_op_rc__art', 'g___oc-group'), -- color
('r_pp_bc__mix', 'g___cb-group'), -- color
('r_pp_rc__mix', 'g___cr-group'); -- color
insert into iam_user_role
(role_id, principal_id)
values
('r_go____name', 'u_______gary'),
('r_gp____spec', 'u_______gina'),
('r_gg_____buy', 'u_auth'),
('r_gg____shop', 'u_anon');
end;
$$ language plpgsql;
-- _wtt_load_kms populates all kms_ tables for the colors persona.
-- kms depends on iam.
create function _wtt_load_colors_kms()
returns void
as $$
begin
end;
$$ language plpgsql;
-- _wtt_load_colors_auth populates all auth_ tables for the colors persona.
-- auth depends on iam, and kms.
create function _wtt_load_colors_auth()
returns void
as $$
begin
insert into auth_password_conf
(password_method_id, private_id)
values
('apm___colors', 'apmc__colors');
-- Add password auth method to organizations
insert into auth_password_method
(scope_id, public_id, password_conf_id, name)
values
('o_____colors', 'apm___colors', 'apmc__colors', 'Colors Auth Password');
insert into auth_password_account
(auth_method_id, public_id, login_name)
values
('apm___colors', 'apa____clare', 'clare'),
('apm___colors', 'apa____cindy', 'cindy'),
('apm___colors', 'apa____carly', 'carly'),
('apm___colors', 'apa____ciara', 'ciara');
update auth_account set iam_user_id = 'u______clare' where public_id = 'apa____clare';
update auth_account set iam_user_id = 'u______cindy' where public_id = 'apa____cindy';
update auth_account set iam_user_id = 'u______carly' where public_id = 'apa____carly';
update auth_account set iam_user_id = 'u______ciara' where public_id = 'apa____ciara';
end;
$$ language plpgsql;
-- _wtt_load_colors_hosts populates all host_ tables for the colors persona.
-- hosts depend on iam.
create function _wtt_load_colors_hosts()
returns void
as $$
begin
insert into static_host_catalog
(scope_id, public_id, name)
values
('p____bcolors', 'c___cb-sthcl', 'Blue Color Static Catalog'),
('p____rcolors', 'c___cr-sthcl', 'Red Color Static Catalog');
insert into static_host
(catalog_id, public_id, address)
values
('c___cb-sthcl', 'h_____cb__01', '1.blue.color'),
('c___cb-sthcl', 'h_____cb__02', '2.blue.color'),
('c___cb-sthcl', 'h_____cb__03', '3.blue.color'),
('c___cb-sthcl', 'h_____cb__04', '4.blue.color'),
('c___cb-sthcl', 'h_____cb__05', '5.blue.color'),
('c___cb-sthcl', 'h_____cb__06', '6.blue.color'),
('c___cb-sthcl', 'h_____cb__07', '7.blue.color'),
('c___cb-sthcl', 'h_____cb__08', '8.blue.color'),
('c___cb-sthcl', 'h_____cb__09', '9.blue.color'),
('c___cr-sthcl', 'h_____cr__01', '1.red.color'),
('c___cr-sthcl', 'h_____cr__02', '2.red.color'),
('c___cr-sthcl', 'h_____cr__03', '3.red.color'),
('c___cr-sthcl', 'h_____cr__04', '4.red.color'),
('c___cr-sthcl', 'h_____cr__05', '5.red.color'),
('c___cr-sthcl', 'h_____cr__06', '6.red.color'),
('c___cr-sthcl', 'h_____cr__07', '7.red.color'),
('c___cr-sthcl', 'h_____cr__08', '8.red.color'),
('c___cr-sthcl', 'h_____cr__09', '9.red.color');
insert into static_host_set
(catalog_id, public_id, name)
values
('c___cb-sthcl', 's___1cb-sths', 'Blue Color Static Set 1'),
('c___cb-sthcl', 's___2cb-sths', 'Blue Color Static Set 2'),
('c___cr-sthcl', 's___1cr-sths', 'Red Color Static Set 1'),
('c___cr-sthcl', 's___2cr-sths', 'Red Color Static Set 2');
insert
into static_host_set_member
( host_id, set_id, catalog_id)
select h.public_id, s.public_id, s.catalog_id
from static_host as h,
static_host_set as s
where h.catalog_id = s.catalog_id;
end;
$$ language plpgsql;
-- _wtt_load_colors_targets populates all target_ tables for the colors persona.
-- targets depend on iam, auth, hosts.
create function _wtt_load_colors_targets()
returns void
as $$
begin
insert into target_tcp
(scope_id, public_id, name)
values
('p____bcolors', 't_________cb', 'Blue Color Target'),
('p____rcolors', 't_________cr', 'Red Color Target');
insert into target_host_set
(target_id, host_set_id)
values
('t_________cb', 's___1cb-sths'),
('t_________cb', 's___2cb-sths'),
('t_________cr', 's___1cr-sths'),
('t_________cr', 's___2cr-sths');
end;
$$ language plpgsql;
commit;
@@ -0,0 +1,261 @@
begin;
-- _wtt_load_widgets_iam populates all iam_ tables for the widgets persona.
-- iam does not depend on any other aggregates, but others depend on it,
-- as such is it should be first in the list.
create function _wtt_load_widgets_iam()
returns void
as $$
begin
-- Add organizations
insert into iam_scope
(parent_id, type, public_id, name)
values
('global', 'org', 'o_____widget', 'Widget Inc');
-- Add projects to the organizations
insert into iam_scope
(parent_id, type, public_id, name)
values
('o_____widget', 'project', 'p____bwidget', 'Big Widget Factory'),
('o_____widget', 'project', 'p____swidget', 'Small Widget Factory');
-- Add global users
insert into iam_user
(scope_id, public_id, name)
values
('global', 'u_______gary', 'Gary'),
('global', 'u_______gina', 'Gina'),
('global', 'u______nancy', 'Nancy');
-- Add organization users
insert into iam_user
(scope_id, public_id, name)
values
('o_____widget', 'u_____walter', 'Walter'),
('o_____widget', 'u_____warren', 'Warren'),
('o_____widget', 'u_____waylon', 'Waylon'),
('o_____widget', 'u_____wilson', 'Wilson');
insert into iam_group
(scope_id, public_id, name)
values
('global', 'g___gg-group', 'Global Group'),
('o_____widget', 'g___ow-group', 'Widget Inc Group'),
('p____bwidget', 'g___wb-group', 'Big Widget Group'),
('p____swidget', 'g___ws-group', 'Small Widget Group');
insert into iam_group_member_user
(group_id, member_id)
values
('g___gg-group', 'u_______gary'),
('g___ow-group', 'u_____walter'),
('g___wb-group', 'u_____warren'),
('g___ws-group', 'u_____waylon');
insert into iam_role
(scope_id, grant_scope_id, public_id, name)
values
('p____bwidget', 'p____bwidget', 'r_pp_bw__bld', 'Widget Builder'),
('p____swidget', 'p____swidget', 'r_pp_sw__bld', 'Widget Builder'),
('o_____widget', 'p____swidget', 'r_op_sw__eng', 'Small Widget Engineer'),
('o_____widget', 'o_____widget', 'r_oo_____eng', 'Widget Engineer'),
('global', 'global', 'r_gg_____buy', 'Purchaser'),
('global', 'global', 'r_gg____shop', 'Shopper');
insert into iam_role_grant
(role_id, canonical_grant, raw_grant)
values
('r_gg_____buy', 'type=*;action=purchase', 'purchase anything'),
('r_gg____shop', 'type=*;action=view', 'view anything'),
('r_oo_____eng', 'type=widget;action=design', 'design widget'),
('r_op_sw__eng', 'type=widget;action=design', 'design widget'),
('r_op_sw__eng', 'type=widget;action=tune', 'tune widget'),
('r_op_sw__eng', 'type=widget;action=clean', 'clean widget'),
('r_pp_bw__bld', 'type=widget;action=build', 'build widget'),
('r_pp_sw__bld', 'type=widget;action=build', 'build widget');
insert into iam_group_role
(role_id, principal_id)
values
('r_oo_____eng', 'g___ow-group'), -- widget
('r_pp_bw__bld', 'g___wb-group'), -- widget
('r_pp_sw__bld', 'g___ws-group'); -- widget
insert into iam_user_role
(role_id, principal_id)
values
('r_gg_____buy', 'u_auth'),
('r_gg____shop', 'u_anon');
end;
$$ language plpgsql;
-- _wtt_load_kms populates all kms_ tables for the widgets persona.
-- kms depends on iam.
create function _wtt_load_widgets_kms()
returns void
as $$
begin
insert into kms_root_key
(private_id, scope_id)
values
('krk___widget', 'o_____widget');
insert into kms_root_key_version
(private_id, root_key_id, key)
values
('krkv___widget', 'krk___widget', 'krk___widget'::bytea);
insert into kms_database_key
(private_id, root_key_id)
values
('kdk____widget', 'krk___widget');
insert into kms_database_key_version
(private_id, database_key_id, root_key_version_id, key)
values
('kdkv___widget', 'kdk____widget', 'krkv___widget', 'kdk____widget'::bytea);
end;
$$ language plpgsql;
-- _wtt_load_widgets_auth populates all auth_ tables for the widgets persona.
-- auth depends on iam, and kms.
create function _wtt_load_widgets_auth()
returns void
as $$
begin
insert into auth_password_conf
(password_method_id, private_id)
values
('apm___widget', 'apmc__widget'),
('apm1__widget', 'apmc1_widget');
-- Add password auth method to organizations
insert into auth_password_method
(scope_id, public_id, password_conf_id, name)
values
('o_____widget', 'apm___widget', 'apmc__widget', 'Widget Auth Password'),
('o_____widget', 'apm1__widget', 'apmc1_widget', 'Widget Auth Password 1');
insert into auth_password_account
(auth_method_id, public_id, login_name)
values
('apm___widget', 'apa___walter', 'walter'),
('apm1__widget', 'apa1__walter', 'walter'),
('apm___widget', 'apa___warren', 'warren'),
('apm___widget', 'apa___waylon', 'waylon'),
('apm___widget', 'apa___wilson', 'wilson');
update auth_account set iam_user_id = 'u_____walter' where public_id = 'apa___walter';
update auth_account set iam_user_id = 'u_____walter' where public_id = 'apa1__walter';
update auth_account set iam_user_id = 'u_____warren' where public_id = 'apa___warren';
update auth_account set iam_user_id = 'u_____waylon' where public_id = 'apa___waylon';
update auth_account set iam_user_id = 'u_____wilson' where public_id = 'apa___wilson';
insert into auth_token
(key_id, auth_account_id, public_id, token)
values
('key', 'apa___walter', 'tok___walter', 'tok___walter'::bytea),
('key', 'apa1__walter', 'tok1__walter', 'tok1__walter'::bytea),
('key', 'apa___warren', 'tok___warren', 'tok___warren'::bytea),
('key', 'apa___waylon', 'tok___waylon', 'tok___waylon'::bytea),
('key', 'apa___wilson', 'tok___wilson', 'tok___wilson'::bytea);
insert into auth_oidc_method
(scope_id, public_id, client_id, name, state, key_id)
values
('o_____widget', 'aom___widget', 'aomc__widget', 'Widget OIDC', 'active-private', 'kdkv___widget');
insert into auth_oidc_account
(auth_method_id, public_id, full_name, email, issuer, subject)
values
('aom___widget', 'aoa___walter', 'Walter', 'walter@widget.test', 'https://widget.test', 'aoa___widget');
update auth_account set iam_user_id = 'u_____walter' where public_id = 'aoa___walter';
insert into auth_token
(key_id, auth_account_id, public_id, token)
values
('key', 'aoa___walter', 'oidc__walter', 'oidc__walter'::bytea);
end;
$$ language plpgsql;
-- _wtt_load_widgets_hosts populates all host_ tables for the widgets persona.
-- hosts depend on iam.
create function _wtt_load_widgets_hosts()
returns void
as $$
begin
insert into static_host_catalog
(scope_id, public_id, name)
values
('p____bwidget', 'c___wb-sthcl', 'Big Widget Static Catalog'),
('p____swidget', 'c___ws-sthcl', 'Small Widget Static Catalog');
insert into static_host
(catalog_id, public_id, address)
values
('c___wb-sthcl', 'h_____wb__01', '1.big.widget'),
('c___wb-sthcl', 'h_____wb__02', '2.big.widget'),
('c___wb-sthcl', 'h_____wb__03', '3.big.widget'),
('c___wb-sthcl', 'h_____wb__04', '4.big.widget'),
('c___wb-sthcl', 'h_____wb__05', '5.big.widget'),
('c___wb-sthcl', 'h_____wb__06', '6.big.widget'),
('c___wb-sthcl', 'h_____wb__07', '7.big.widget'),
('c___wb-sthcl', 'h_____wb__08', '8.big.widget'),
('c___wb-sthcl', 'h_____wb__09', '9.big.widget'),
('c___ws-sthcl', 'h_____ws__01', '1.small.widget'),
('c___ws-sthcl', 'h_____ws__02', '2.small.widget'),
('c___ws-sthcl', 'h_____ws__03', '3.small.widget'),
('c___ws-sthcl', 'h_____ws__04', '4.small.widget'),
('c___ws-sthcl', 'h_____ws__05', '5.small.widget'),
('c___ws-sthcl', 'h_____ws__06', '6.small.widget'),
('c___ws-sthcl', 'h_____ws__07', '7.small.widget'),
('c___ws-sthcl', 'h_____ws__08', '8.small.widget'),
('c___ws-sthcl', 'h_____ws__09', '9.small.widget');
insert into static_host_set
(catalog_id, public_id, name)
values
('c___wb-sthcl', 's___1wb-sths', 'Big Widget Static Set 1'),
('c___wb-sthcl', 's___2wb-sths', 'Big Widget Static Set 2'),
('c___ws-sthcl', 's___1ws-sths', 'Small Widget Static Set 1'),
('c___ws-sthcl', 's___2ws-sths', 'Small Widget Static Set 2');
insert
into static_host_set_member
( host_id, set_id, catalog_id)
select h.public_id, s.public_id, s.catalog_id
from static_host as h,
static_host_set as s
where h.catalog_id = s.catalog_id;
end;
$$ language plpgsql;
-- _wtt_load_widgets_targets populates all target_ tables for the widgets persona.
-- targets depend on iam, auth, hosts.
create function _wtt_load_widgets_targets()
returns void
as $$
begin
insert into target_tcp
(scope_id, public_id, name)
values
('p____bwidget', 't_________wb', 'Big Widget Target'),
('p____swidget', 't_________ws', 'Small Widget Target');
insert into target_host_set
(target_id, host_set_id)
values
('t_________wb', 's___1wb-sths'),
('t_________wb', 's___2wb-sths'),
('t_________ws', 's___1ws-sths'),
('t_________ws', 's___2ws-sths');
end;
$$ language plpgsql;
commit;
@@ -0,0 +1,18 @@
-- wtt_load tests the wtt_load test helper function.
begin;
select plan(6);
-- invalid or missing args
select throws_ok($$select wtt_load('unknown', 'iam')$$);
select throws_ok($$select wtt_load('colors', 'unknown')$$);
select throws_ok($$select wtt_load('colors')$$);
select throws_ok($$select wtt_load()$$);
-- incorrect order since auth depends on iam
select throws_ok($$select wtt_load('colors', 'auth', 'iam')$$);
-- missing a dependancy, auth depends on iam
select throws_ok($$select wtt_load('colors', 'auth')$$);
select * from finish();
rollback;
@@ -0,0 +1,7 @@
-- wtt_load_colors tests the wtt_load test helper function for the colors persona.
begin;
select plan(1);
select lives_ok($$select wtt_load('colors', 'iam', 'kms', 'auth', 'hosts', 'targets')$$);
select * from finish();
rollback;
@@ -0,0 +1,8 @@
-- wtt_load_widgets tests the wtt_load test helper function for the widgets persona.
begin;
select plan(1);
select lives_ok($$select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets')$$);
select * from finish();
rollback;
@@ -0,0 +1,18 @@
-- errors tests that the wh_upsert_user function throws errors under certain conditions.
begin;
select plan(3);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- missing args
select throws_ok($$select wh_upsert_user()$$);
select throws_ok($$select wh_upsert_user('u_____walter')$$);
-- non-existant user
-- select throws_ok($$select wh_upsert_user('u_____retlaw', 'tok___walter')$$);
-- non-existant token
select throws_ok($$select wh_upsert_user('u_____walter', 'tok___retlaw')$$);
select * from finish();
rollback;
@@ -0,0 +1,17 @@
-- insert tests that the wh_upsert_user function will do an insert when
-- no existing source wh_user_dimension exists.
begin;
select plan(3);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
select lives_ok($$select wh_upsert_user('u_____walter', 'tok___walter')$$);
-- upsert should insert a user_dimension
select is(count(*), 1::bigint) from wh_user_dimension;
select * from finish();
rollback;
@@ -0,0 +1,37 @@
-- upsert tests that the wh_upsert_user function will do an update when
-- an existing source wh_user_dimension exists.
begin;
select plan(4);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
insert into wh_user_dimension
(
id,
user_id, user_name, user_description,
auth_account_id, auth_account_type, auth_account_name, auth_account_description,
auth_method_id, auth_method_type, auth_method_name, auth_method_description,
user_organization_id, user_organization_name, user_organization_description,
current_row_indicator, row_effective_time, row_expiration_time
)
values
(
'wud_____1',
'u_____walter', 'Walter', 'This is Walter',
'apa___walter', 'password auth account', 'walter', 'Account for Walter',
'apm___widget', 'password auth method', 'Widget Auth Password', 'None',
'o_____widget', 'Widget Inc', 'None',
'Current', '2021-07-21T12:01'::timestamptz, 'infinity'::timestamptz
);
select lives_ok($$select wh_upsert_user('u_____walter', 'tok___walter')$$);
-- upsert should insert a user_dimension
select is(count(*), 2::bigint) from wh_user_dimension;
select is(count(*), 1::bigint) from wh_user_dimension where current_row_indicator = 'Current';
select * from finish();
rollback;
@@ -0,0 +1,39 @@
-- oidc_auth_new_session tests the wh_user_dimesion when
-- a new session is created using the oidc auth method.
begin;
select plan(17);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
-- insert first session, should result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'oidc__walter' , 'abc'::bytea , 'ep1' , 's1____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
select is(user_id, 'u_____walter') from wh_user_dimension;
select is(user_name, 'Walter') from wh_user_dimension;
select is(user_description, 'None') from wh_user_dimension;
select is(auth_account_id, 'aoa___walter') from wh_user_dimension;
select is(auth_account_type, 'password auth account') from wh_user_dimension;
select is(auth_account_name, 'None') from wh_user_dimension;
select is(auth_account_description, 'None') from wh_user_dimension;
select is(auth_method_id, 'aom___widget') from wh_user_dimension;
select is(auth_method_type, 'password auth method') from wh_user_dimension;
select is(auth_method_name, 'None') from wh_user_dimension;
select is(auth_method_description, 'None') from wh_user_dimension;
select is(user_organization_id, 'o_____widget') from wh_user_dimension;
select is(user_organization_name, 'Widget Inc') from wh_user_dimension;
select is(user_organization_description, 'None') from wh_user_dimension;
select is(current_row_indicator, 'Current') from wh_user_dimension;
select * from finish();
rollback;
@@ -0,0 +1,76 @@
-- password_auth_description_change tests the wh_user_dimesion when
-- sessions are created using the password auth method
-- after the auth_password_account has its description change.
begin;
select plan(32);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
-- insert first session, should result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
select is(user_id, 'u_____walter') from wh_user_dimension;
select is(user_name, 'Walter') from wh_user_dimension;
select is(user_description, 'None') from wh_user_dimension;
select is(auth_account_id, 'apa___walter') from wh_user_dimension;
select is(auth_account_type, 'password auth account') from wh_user_dimension;
select is(auth_account_name, 'None') from wh_user_dimension;
select is(auth_account_description, 'None') from wh_user_dimension;
select is(auth_method_id, 'apm___widget') from wh_user_dimension;
select is(auth_method_type, 'password auth method') from wh_user_dimension;
select is(auth_method_name, 'Widget Auth Password') from wh_user_dimension;
select is(auth_method_description, 'None') from wh_user_dimension;
select is(user_organization_id, 'o_____widget') from wh_user_dimension;
select is(user_organization_name, 'Widget Inc') from wh_user_dimension;
select is(user_organization_description, 'None') from wh_user_dimension;
select is(current_row_indicator, 'Current') from wh_user_dimension;
-- change auth description
update auth_password_account set
description = 'Walter Password Account'
where
public_id = 'apa___walter';
-- another session with:
-- * same user
-- * same auth
-- * same host
-- should result in a new user dimension due to auth change.
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
select is(count(*), 2::bigint) from wh_user_dimension;
select is(user_id, 'u_____walter') from wh_user_dimension where current_row_indicator = 'Current';
select is(user_name, 'Walter') from wh_user_dimension where current_row_indicator = 'Current';
select is(user_description, 'None') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_account_id, 'apa___walter') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_account_type, 'password auth account') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_account_name, 'None') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_account_description, 'Walter Password Account') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_method_id, 'apm___widget') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_method_type, 'password auth method') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_method_name, 'Widget Auth Password') from wh_user_dimension where current_row_indicator = 'Current';
select is(auth_method_description, 'None') from wh_user_dimension where current_row_indicator = 'Current';
select is(user_organization_id, 'o_____widget') from wh_user_dimension where current_row_indicator = 'Current';
select is(user_organization_name, 'Widget Inc') from wh_user_dimension where current_row_indicator = 'Current';
select is(user_organization_description, 'None') from wh_user_dimension where current_row_indicator = 'Current';
select * from finish();
rollback;
@@ -0,0 +1,39 @@
-- password_auth_new_session tests the wh_user_dimesion when
-- a new session is created using the password auth method.
begin;
select plan(17);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
-- insert first session, should result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
select is(user_id, 'u_____walter') from wh_user_dimension;
select is(user_name, 'Walter') from wh_user_dimension;
select is(user_description, 'None') from wh_user_dimension;
select is(auth_account_id, 'apa___walter') from wh_user_dimension;
select is(auth_account_type, 'password auth account') from wh_user_dimension;
select is(auth_account_name, 'None') from wh_user_dimension;
select is(auth_account_description, 'None') from wh_user_dimension;
select is(auth_method_id, 'apm___widget') from wh_user_dimension;
select is(auth_method_type, 'password auth method') from wh_user_dimension;
select is(auth_method_name, 'Widget Auth Password') from wh_user_dimension;
select is(auth_method_description, 'None') from wh_user_dimension;
select is(user_organization_id, 'o_____widget') from wh_user_dimension;
select is(user_organization_name, 'Widget Inc') from wh_user_dimension;
select is(user_organization_description, 'None') from wh_user_dimension;
select is(current_row_indicator, 'Current') from wh_user_dimension;
select * from finish();
rollback;
@@ -0,0 +1,44 @@
-- session_multiple_sessions tests the wh_user_dimesion when
-- multiple sessions are created using the same user and auth method.
begin;
select plan(4);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
-- insert first session, should result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
-- another session with:
-- * same user
-- * same auth
-- * same host
-- should not result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's2____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
-- another session with:
-- * same user
-- * same auth
-- * different host
-- should not result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__02' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's3____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
select * from finish();
rollback;
@@ -0,0 +1,55 @@
-- session_multiple_sessions_differnt_auth tests the wh_user_dimesion when
-- multiple sessions are created using the same user
-- but different auth accounts.
begin;
select plan(19);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
-- insert first session, should result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
-- another session with:
-- * same user
-- * different auth account
-- * same host
-- should result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok1__walter' , 'abc'::bytea , 'ep1' , 's4____walter');
select is(count(*), 2::bigint) from wh_user_dimension;
select is(count(*), 1::bigint) from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(user_id, 'u_____walter') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(user_name, 'Walter') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(user_description, 'None') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_account_id, 'apa1__walter') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_account_type, 'password auth account') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_account_name, 'None') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_account_description, 'None') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_method_id, 'apm1__widget') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_method_type, 'password auth method') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_method_name, 'Widget Auth Password 1') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(auth_method_description, 'None') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(user_organization_id, 'o_____widget') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(user_organization_name, 'Widget Inc') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(user_organization_description, 'None') from wh_user_dimension where auth_account_id = 'apa1__walter';
select is(current_row_indicator, 'Current') from wh_user_dimension where auth_account_id = 'apa1__walter';
select * from finish();
rollback;
@@ -0,0 +1,28 @@
-- session_update tests the wh_user_dimesion when
-- a session is inserted and then updated.
begin;
select plan(3);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- ensure no existing dimensions
select is(count(*), 0::bigint) from wh_user_dimension;
-- insert first session, should result in a new user dimension
insert into session
( scope_id , target_id , host_set_id , host_id , user_id , auth_token_id , certificate , endpoint , public_id)
values
('p____bwidget' , 't_________wb' , 's___1wb-sths' , 'h_____wb__01' , 'u_____walter' , 'tok___walter' , 'abc'::bytea , 'ep1' , 's1____walter');
select is(count(*), 1::bigint) from wh_user_dimension;
-- update session, should not impact wh_user_dimension
update session set
version = 2
where
public_id = 's1____walter';
select is(count(*), 1::bigint) from wh_user_dimension;
select * from finish();
rollback;
@@ -0,0 +1,49 @@
-- source tests teh whx_user_dimension_source view.
begin;
select plan(4);
select wtt_load('widgets', 'iam', 'kms', 'auth', 'hosts', 'targets');
-- auth_password_account
select is(s.*, row(
'u_____walter', 'Walter', 'None',
'apa___walter', 'password auth account', 'None', 'None',
'apm___widget', 'password auth method', 'Widget Auth Password', 'None',
'o_____widget', 'Widget Inc', 'None'
)::whx_user_dimension_source)
from whx_user_dimension_source as s
where s.user_id = 'u_____walter'
and s.auth_account_id = 'apa___walter';
select is(s.*, row(
'u_____walter', 'Walter', 'None',
'apa1__walter', 'password auth account', 'None', 'None',
'apm1__widget', 'password auth method', 'Widget Auth Password 1', 'None',
'o_____widget', 'Widget Inc', 'None'
)::whx_user_dimension_source)
from whx_user_dimension_source as s
where s.user_id = 'u_____walter'
and s.auth_account_id = 'apa1__walter';
select is(s.*, row(
'u_____warren', 'Warren', 'None',
'apa___warren', 'password auth account', 'None', 'None',
'apm___widget', 'password auth method', 'Widget Auth Password', 'None',
'o_____widget', 'Widget Inc', 'None'
)::whx_user_dimension_source)
from whx_user_dimension_source as s
where s.user_id = 'u_____warren'
and s.auth_account_id = 'apa___warren';
-- auth_oidc_account
select is(s.*, row(
'u_____walter', 'Walter', 'None',
'aoa___walter', 'password auth account', 'None', 'None',
'aom___widget', 'password auth method', 'None', 'None',
'o_____widget', 'Widget Inc', 'None'
)::whx_user_dimension_source)
from whx_user_dimension_source as s
where s.user_id = 'u_____walter'
and s.auth_account_id = 'aoa___walter';
select * from finish();
rollback;
@@ -0,0 +1,46 @@
-- target tests teh whx_user_dimension_target view.
begin;
select plan(2);
select is_empty($$select * from whx_user_dimension_target where user_id = 'u_____walter' and auth_account_id = 'apa___walter'$$);
insert into wh_user_dimension
(
id,
user_id, user_name, user_description,
auth_account_id, auth_account_type, auth_account_name, auth_account_description,
auth_method_id, auth_method_type, auth_method_name, auth_method_description,
user_organization_id, user_organization_name, user_organization_description,
current_row_indicator, row_effective_time, row_expiration_time
)
values
(
'wud_____1',
'u_____walter', 'Walter', 'None',
'apa___walter', 'password auth account', 'None', 'None',
'apm___widget', 'password auth method', 'Widget Auth Password', 'None',
'o_____widget', 'Widget Inc', 'None',
'Expired', '2021-07-21T11:01'::timestamptz, '2021-07-21T12:01'::timestamptz
),
(
'wud_____2',
'u_____walter', 'Walter', 'This is Walter',
'apa___walter', 'password auth account', 'walter', 'Account for Walter',
'apm___widget', 'password auth method', 'Widget Auth Password', 'None',
'o_____widget', 'Widget Inc', 'None',
'Current', '2021-07-21T12:01'::timestamptz, 'infinity'::timestamptz
);
select is(t.*, row(
'wud_____2',
'u_____walter', 'Walter', 'This is Walter',
'apa___walter', 'password auth account', 'walter', 'Account for Walter',
'apm___widget', 'password auth method', 'Widget Auth Password', 'None',
'o_____widget', 'Widget Inc', 'None'
)::whx_user_dimension_target)
from whx_user_dimension_target as t
where t.user_id = 'u_____walter'
and t.auth_account_id = 'apa___walter';
select * from finish();
rollback;