Files
threshold/internal/db/domains_test.go
T
hashicorp-copywrite[bot]andJohan Brandhorst-Satzkorn 29da0bcb92 [COMPLIANCE] License changes (#3567)
* Adding explicit MPL license for sub-package.

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Adding explicit MPL license for sub-package

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Updating the license from MPL to Business Source License

Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl.

* Update copyright file headers to BUS-1.1

* Rerun make gen

This will pick up the last of the license changes

* Revert "Rerun make gen"

This reverts commit dbe0968bffd92745d8663c6940debae098395a6b.

* Remove copywrite from generation script

The current version of copywrite is not sophisticated enough
to only apply the copywrite changes to certain subdirectories,
so to avoid accidentally relicensing our api and sdk modules,
we will stop running the copywrite script until such time
that it can do the right thing.

* License protobuf API as MPL

The protobuf API files are used to generate the SDK,
since we want the SDK to be MPL, the protobuf files
must also be MPL. This extends to all protobuf files
whose sources end up in the SDK directory, including:

- internal/proto/controller/api
- internal/proto/controller/custom_options
- internal/proto/plugin

It also includes the generated service directory in
internal/gen/controller/api/services, since they are
generated from the protobuf sources used for the SDK.

* Change website license file name

This makes the naming scheme consistent with the rest
of the repository.

* Add note on licensing to README

* Set copywrite license to BUSL

* Revert "Add note on licensing to README"

This reverts commit 4d865a91a7a4f11605f0dc4609355d7e3c3cfffe.

---------

Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
2023-08-11 10:31:53 -07:00

1114 lines
26 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package db
import (
"context"
"strings"
"testing"
"time"
"github.com/golang-sql/civil"
"github.com/hashicorp/boundary/globals"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDomain_Ids(t *testing.T) {
const (
createTableBase = `
create table if not exists test_table_{{rep}}_id (
id bigint generated always as identity primary key,
{{rep}}_id wt_{{rep}}_id
);
`
insertBase = `
insert into test_table_{{rep}}_id ({{rep}}_id)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
for _, typ := range []string{"public", "private", "role", "scope"} {
createTable := strings.Replace(createTableBase, "{{rep}}", typ, -1)
insert := strings.Replace(insertBase, "{{rep}}", typ, -1)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
failTests := []struct {
value string
exception string
}{
{
" ",
"",
},
{
"bar",
"",
},
{
"00000009",
"",
},
{
"global",
"scope",
},
}
for _, tt := range failTests {
t.Run(tt.value, func(t *testing.T) {
t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
switch {
case err == nil && tt.exception != typ:
t.Errorf("want error, got no error for inserting public_id: %s", tt.value)
case err == nil && tt.exception == typ:
// All good
case err != nil && tt.exception != typ:
// All good
default:
t.Fatal("unhandled")
}
})
}
okTests := []string{
"l1Ocw0TpHn800CekIxIXlmQqRDgFDfYl",
"00000000010000000002000000000312",
"00000000010000000002000000000032",
"12345678901234567890123456789012",
"ec2_12345678901234567890123456789012",
"prj_12345678901234567890123456789012",
}
for _, tt := range okTests {
value := tt
t.Run(tt, func(t *testing.T) {
t.Logf("insert value: %q", value)
if _, err := db.Query(insert, value); err != nil {
t.Errorf("%s: want no error, got error %v", value, err)
}
})
}
}
}
func TestDomain_TagPairs(t *testing.T) {
const (
createTable = `
create table if not exists test_table (
pair wt_tagpair primary key
);
`
insert = `
insert into test_table
values ($1);
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
tests := []struct {
value string
fail bool
}{
{
" ",
true,
},
{
"00000009",
false,
},
{
"ABC123",
true,
},
{
"092h3oiuansdfh98wh3piornasiopudhfp98aw384rhfaouisdhnfios",
false,
},
{
strings.Repeat("1234567890", 51),
false,
},
{
strings.Repeat("1234567890", 52),
true,
},
}
for _, tt := range tests {
t.Run(tt.value, func(t *testing.T) {
// t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
switch {
case err == nil && tt.fail:
t.Errorf("want error, got no error for inserting value: %s", tt.value)
case err == nil && !tt.fail:
// All good
case err != nil && tt.fail:
// All good
default:
t.Errorf("expected no error, got error: %s", err)
}
})
}
t.Run("null", func(t *testing.T) {
_, err := db.Query("insert into test_table values (null);")
assert.Contains(t, err.Error(), "violates check constraint")
})
}
func TestDomain_Bexprfilter(t *testing.T) {
const (
createTable = `
create table if not exists test_table (
filter wt_bexprfilter
);
`
insert = `
insert into test_table
values ($1);
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
tests := []struct {
value string
fail bool
}{
{
" ",
true,
},
{
"00000009",
false,
},
{
"ABC123",
false,
},
{
`"/foo/bar" in "/values"`,
false,
},
{
strings.Repeat("1234567890", 204),
false,
},
{
strings.Repeat("1234567890", 205),
true,
},
}
for _, tt := range tests {
t.Run(tt.value, func(t *testing.T) {
// t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
switch {
case err == nil && tt.fail:
t.Errorf("want error, got no error for inserting value: %s", tt.value)
case err == nil && !tt.fail:
// All good
case err != nil && tt.fail:
// All good
default:
t.Errorf("expected no error, got error: %s", err)
}
})
}
t.Run("null", func(t *testing.T) {
_, err := db.Query("insert into test_table values (null);")
assert.NoError(t, err)
})
}
func TestDomain_Timestamp(t *testing.T) {
const (
createTable = `
create table if not exists test_table_timestamp (
id bigint generated always as identity primary key,
name text,
good_time wt_timestamp,
bad_time timestamp default current_timestamp
);
`
insert = `
insert into test_table_timestamp (name)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
if _, err := db.Exec(insert, "foo"); err != nil {
t.Fatalf("want no error, got error %v", err)
}
if _, err := db.Query("select extract(timezone from good_time) from test_table_timestamp;"); err != nil {
t.Errorf("want no error, got error %v", err)
}
if _, err := db.Query("select extract(timezone from bad_time) from test_table_timestamp;"); err == nil {
t.Errorf("want error, got no error")
}
}
func TestDomain_update_time_column(t *testing.T) {
assert := assert.New(t)
const (
createTable = `
create table if not exists test_update_time_column (
id bigint generated always as identity primary key,
name text,
update_time wt_timestamp
);
`
addTriggers = `
create trigger
test_update_time_column
before
update on test_update_time_column
for each row execute procedure update_time_column();
`
countQuery = `
select count(*) from test_update_time_column
`
query = `
select update_time from test_update_time_column where id = $1
`
insert = `
insert into test_update_time_column (name)
values ('bob')
returning id;
`
// no where clause intentionally, since it's not needed for the test
update = `
update test_update_time_column
set name = 'alice';
`
// no where clause intentionally, since it's not needed for the test
bad_update = `
update test_update_time_column
set update_time = now() - interval '3 days';
`
// no where clause intentionally, since it's not needed for the test
bad_update_null = `
update test_update_time_column
set update_time = null;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
_, err = db.Exec(createTable)
assert.NoError(err)
_, err = db.Exec(addTriggers)
assert.NoError(err)
var id int
err = db.QueryRow(insert).Scan(&id)
assert.NoError(err)
var origTime time.Time
err = db.QueryRow(query, id).Scan(&origTime)
assert.NoError(err)
orig := civil.DateTimeOf(origTime)
var count int
err = db.QueryRow(countQuery).Scan(&count)
assert.NoError(err)
assert.Equal(1, count)
_, err = db.Exec(update)
assert.NoError(err)
_, err = db.Exec(bad_update)
assert.NoError(err)
var updateTime time.Time
err = db.QueryRow(query, id).Scan(&updateTime)
assert.NoError(err)
updated := civil.DateTimeOf(updateTime)
assert.True(updated.After(orig))
_, err = db.Exec(bad_update_null)
assert.NoError(err)
var nextUpdateTime time.Time
err = db.QueryRow(query, id).Scan(&nextUpdateTime)
assert.NoError(err)
nextUpdated := civil.DateTimeOf(nextUpdateTime)
assert.True(nextUpdated.After(updated))
}
func TestDomain_wt_version(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_version(
public_id bigint generated always as identity primary key,
name text,
version wt_version
);
`
addTrigger = `
create trigger
update_version_column
after update on test_table_wt_version
for each row execute procedure update_version_column();
`
insert = `
insert into test_table_wt_version (name)
values ($1)
returning public_id;
`
update = `update test_table_wt_version set name = $1 where public_id = $2;`
updateVersion = `update test_table_wt_version set version = $1 where public_id = $2;`
search = `select version from test_table_wt_version where public_id = $1`
)
conn, _ := TestSetup(t, "postgres")
assert, require := assert.New(t), require.New(t)
ctx := context.Background()
db, err := conn.SqlDB(ctx)
require.NoError(err)
_, err = db.Exec(createTable)
require.NoError(err)
_, err = db.Exec(addTrigger)
require.NoError(err)
var id int
err = db.QueryRow(insert, "alice").Scan(&id)
require.NoError(err)
require.NotEmpty(id)
var v int
err = db.QueryRow(search, id).Scan(&v)
require.NoError(err)
assert.Equal(1, v)
_, err = db.Exec(update, "bob", id)
require.NoError(err)
err = db.QueryRow(search, id).Scan(&v)
require.NoError(err)
assert.Equal(2, v)
_, err = db.Exec(updateVersion, 22, id)
require.NoError(err)
err = db.QueryRow(search, id).Scan(&v)
require.NoError(err)
assert.Equal(3, v)
}
func TestDomain_wt_version_with_private_id(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_version(
private_id bigint generated always as identity primary key,
name text,
version wt_version
);
`
addTrigger = `
create trigger
update_version_column
after update on test_table_wt_version
for each row execute procedure update_version_column('private_id');
`
insert = `
insert into test_table_wt_version (name)
values ($1)
returning private_id;
`
update = `update test_table_wt_version set name = $1 where private_id = $2;`
updateVersion = `update test_table_wt_version set version = $1 where private_id = $2;`
search = `select version from test_table_wt_version where private_id = $1`
)
conn, _ := TestSetup(t, "postgres")
assert, require := assert.New(t), require.New(t)
ctx := context.Background()
db, err := conn.SqlDB(ctx)
require.NoError(err)
_, err = db.Exec(createTable)
require.NoError(err)
_, err = db.Exec(addTrigger)
require.NoError(err)
var id int
err = db.QueryRow(insert, "alice").Scan(&id)
require.NoError(err)
require.NotEmpty(id)
var v int
err = db.QueryRow(search, id).Scan(&v)
require.NoError(err)
assert.Equal(1, v)
_, err = db.Exec(update, "bob", id)
require.NoError(err)
err = db.QueryRow(search, id).Scan(&v)
require.NoError(err)
assert.Equal(2, v)
_, err = db.Exec(updateVersion, 22, id)
require.NoError(err)
err = db.QueryRow(search, id).Scan(&v)
require.NoError(err)
assert.Equal(3, v)
}
func TestDomain_DefaultUsersExist(t *testing.T) {
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
for _, val := range []string{globals.AnonymousUserId, globals.AnyAuthenticatedUserId} {
rows, err := db.Query(`select from iam_user where public_id = $1`, val)
require.NoError(t, err)
var count int
for rows.Next() {
count++
}
assert.Equal(t, 1, count)
}
}
func TestDomain_immutable_columns_func(t *testing.T) {
const (
createTable = `
create table if not exists test_immutable_columns (
id bigint generated always as identity primary key,
name text not null,
create_time wt_timestamp not null,
updatable text not null
);
`
addTriggers = `
create trigger
test_update_immutable_columns
before
update on test_immutable_columns
for each row execute procedure immutable_columns('id', 'name', 'create_time');
`
dropTriggers = `drop trigger test_update_immutable_columns on test_immutable_columns`
addBadTriggers = `
create trigger
test_update_bad_immutable_columns
before
update on test_immutable_columns
for each row execute procedure immutable_columns('id', 'bad_column_name', 'create_time');
`
dropBadTriggers = `drop trigger test_update_bad_immutable_columns on test_immutable_columns`
query = `
select id, name, create_time, updatable from test_immutable_columns where id = $1
`
countQuery = `
select count(*) from test_immutable_columns
`
insert = `
insert into test_immutable_columns (name, updatable)
values ('alice', 'update alice')
returning id;
`
// no where clause intentionally, since it's not needed for the test
update_updatable = `
update test_immutable_columns
set updatable = 'updated bob';
`
// no where clause intentionally, since it's not needed for the test
bad_update_create_time = `
update test_immutable_columns
set create_time = now();
`
// no where clause intentionally, since it's not needed for the test
bad_update_null_create_time = `
update test_immutable_columns
set create_time = null;
`
// no where clause intentionally, since it's not needed for the test
bad_update_id = `
update test_immutable_columns
set id = 22;
`
// no where clause intentionally, since it's not needed for the test
bad_update_null_id = `
update test_immutable_columns
set id = null;
`
)
type rowData struct {
Id int
CreateTime time.Time
Name string
Updatable string
}
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
_, err = db.Exec(createTable)
assert.NoError(t, err)
_, err = db.Exec(addTriggers)
assert.NoError(t, err)
var id int
err = db.QueryRow(insert).Scan(&id)
assert.NoError(t, err)
var orig rowData
err = db.QueryRow(query, id).Scan(&orig.Id, &orig.Name, &orig.CreateTime, &orig.Updatable)
assert.NoError(t, err)
var count int
err = db.QueryRow(countQuery).Scan(&count)
assert.NoError(t, err)
assert.Equal(t, 1, count)
tests := []struct {
name string
stmt string
}{
{
name: "update create time",
stmt: bad_update_create_time,
},
{
name: "null create time",
stmt: bad_update_null_create_time,
},
{
name: "update id",
stmt: bad_update_id,
},
{
name: "null id",
stmt: bad_update_null_id,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
_, err = db.Exec(tt.stmt)
assert.Error(err)
var found rowData
err = db.QueryRow(query, id).Scan(&found.Id, &found.Name, &found.CreateTime, &found.Updatable)
assert.NoError(err)
assert.Equal(orig.Id, found.Id)
assert.Equal(orig.Name, found.Name)
assert.Equal(orig.CreateTime, found.CreateTime)
})
}
t.Run("updatable", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
_, err = db.Exec(update_updatable)
require.NoError(err)
var found rowData
err = db.QueryRow(query, id).Scan(&found.Id, &found.Name, &found.CreateTime, &found.Updatable)
require.NoError(err)
assert.NotEqual(orig.Updatable, found.Updatable)
})
t.Run("bad column", func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
t.Cleanup(func() {
// reset the update trigger to what they were before this test
// started.
_, err = db.Exec(dropBadTriggers)
require.NoError(err)
_, err = db.Exec(addTriggers)
assert.NoError(err)
})
_, err = db.Exec(dropTriggers)
require.NoError(err)
_, err = db.Exec(addBadTriggers)
require.NoError(err)
_, err = db.Exec(update_updatable)
require.Error(err)
assert.Containsf(err.Error(), `SQLSTATE 42703`, "unexpected error msg: %s", err.Error())
var found rowData
err = db.QueryRow(query, id).Scan(&found.Id, &found.Name, &found.CreateTime, &found.Updatable)
assert.NoError(err)
assert.Equal(orig.Id, found.Id)
assert.Equal(orig.Name, found.Name)
assert.Equal(orig.CreateTime, found.CreateTime)
})
}
func TestDomain_wt_url(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_url (
id bigint generated always as identity primary key,
url wt_url
);
`
insert = `
insert into test_table_wt_url(url)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
failTests := []struct {
value string
exception string
}{
{"http://", ""},
{"htt://", "wt_url_invalid_protocol"},
{"ht", "wt_url_invalid_protocol"},
{"http://" + strings.Repeat("a", 4001), "wt_url_too_long"},
}
for _, tt := range failTests {
t.Run(tt.value, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
if tt.exception != "" {
require.Error(err)
assert.Containsf(err.Error(), tt.exception, "missing %s from err: %s", tt.exception, err.Error())
return
}
require.NoError(err)
})
}
}
func TestDomain_wt_email(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_email (
id bigint generated always as identity primary key,
email wt_email
);
`
insert = `
insert into test_table_wt_email(email)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
failTests := []struct {
value string
exception string
}{
{" ", "wt_email_too_short"},
{"1" + strings.Repeat("1", 320), "wt_email_too_long"},
{"alice@bob.com", ""},
}
for _, tt := range failTests {
t.Run(tt.value, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
if tt.exception != "" {
require.Error(err)
assert.Containsf(err.Error(), tt.exception, "missing %s from err: %s", tt.exception, err.Error())
return
}
require.NoError(err)
})
}
}
func TestDomain_wt_full_name(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_full_name (
id bigint generated always as identity primary key,
full_name wt_full_name
);
`
insert = `
insert into test_table_wt_full_name(full_name)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
failTests := []struct {
value string
exception string
}{
{" ", "wt_full_name_too_short"},
{"1" + strings.Repeat("1", 512), "wt_full_name_too_long"},
{"alice and bob's dinner", ""},
}
for _, tt := range failTests {
t.Run(tt.value, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
if tt.exception != "" {
require.Error(err)
assert.Containsf(err.Error(), tt.exception, "missing %s from err: %s", tt.exception, err.Error())
return
}
require.NoError(err)
})
}
}
func TestDomain_wt_name(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_name (
id bigint generated always as identity primary key,
name wt_name
);
`
insert = `
insert into test_table_wt_name(name)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
failTests := []struct {
value string
exception string
}{
{" ", "wt_name_too_short"},
{"1" + strings.Repeat("1", 512), "wt_name_too_long"},
{"alice and bob's dinner", ""},
}
for _, tt := range failTests {
t.Run(tt.value, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
if tt.exception != "" {
require.Error(err)
assert.Containsf(err.Error(), tt.exception, "missing %s from err: %s", tt.exception, err.Error())
return
}
require.NoError(err)
})
}
}
func TestDomain_wt_description(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_description (
id bigint generated always as identity primary key,
description wt_description
);
`
insert = `
insert into test_table_wt_description(description)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
failTests := []struct {
value string
exception string
}{
{" ", "wt_description_too_short"},
{"1" + strings.Repeat("1", 1024), "wt_description_too_long"},
{"alice and bob's dinner has delicious pancakes", ""},
}
for _, tt := range failTests {
t.Run(tt.value, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
if tt.exception != "" {
require.Error(err)
assert.Containsf(err.Error(), tt.exception, "missing %s from err: %s", tt.exception, err.Error())
return
}
require.NoError(err)
})
}
}
func TestDomain_wt_sentinel(t *testing.T) {
const (
createTable = `
create table if not exists test_table_wt_sentinel (
id bigint generated always as identity primary key,
sentinel wt_sentinel
);
`
insert = `
insert into test_table_wt_sentinel(sentinel)
values ($1)
returning id;
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
if _, err := db.Exec(createTable); err != nil {
t.Fatalf("query: \n%s\n error: %s", createTable, err)
}
tests := []struct {
name string
value string
wantErr bool
}{
{"normal", "\ufffefoo\uffff", false},
{"normal non-sentinel", "foo", false},
{"empty-with-sentinel", "\ufffe\uffff", false},
{"trailing sentinel", "\ufffefoo\ufffe", false},
{"only start sentinel", "\ufffe", true},
{"only end sentinel", "\uffff", true},
{"sentinel with space before word", "\ufffe foo\uffff", false},
{"sentinel with space after word", "\ufffefoo \uffff", false},
{"start sentinel with empty string", "\ufffe ", true},
{"multiple sentinels with empty string", "\ufffe\ufffe \uffff\uffff", false},
{"multiple sentinels", "\ufffe\ufffefoo\uffff\uffff", false},
{"multiple sentinels inverted", "\uffff\ufffffoo\ufffe\ufffe", false},
{"sentinel space sentinel space string", "\ufffe \ufffe foo ", false},
{"only spaces string", " ", true},
{"empty string", "", true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
t.Logf("insert value: %q", tt.value)
_, err := db.Query(insert, tt.value)
if tt.wantErr {
assert.Error(err)
return
}
assert.NoError(err)
})
}
}
func TestDomain_wt_is_sentinel(t *testing.T) {
const (
query = `
select wt_is_sentinel($1);
`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
require.NoError(t, err)
tests := []struct {
name string
value string
want bool
}{
{"normal", "\ufffefoo\uffff", true},
{"non-sentinel", "foo", false},
{"only start sentinel", "\ufffefoo", false},
{"only end sentinel", "foo\uffff", false},
{"trailing start sentinel", "\ufffefoo\ufffe", false},
{"leading end sentinel", "\ufffffoo\uffff", false},
{"sentinel with space before word", "\ufffe foo\uffff", true},
{"sentinel with empty string", "\ufffe \uffff", true},
{"multiple start sentinels with empty string", "\ufffe\ufffe \uffff", true},
{"multiple start sentinels", "\ufffe\ufffefoo\uffff", true},
{"only spaces", " ", false},
{"empty string", "", false},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
t.Logf("query value: %q", tt.value)
var got bool
rows, err := db.Query(query, tt.value)
require.NoError(err)
defer rows.Close()
require.True(rows.Next())
require.NoError(rows.Scan(&got))
assert.Equal(tt.want, got)
require.False(rows.Next())
require.NoError(rows.Err())
})
}
}
func TestDomain_not_null_columns_func(t *testing.T) {
const (
createTable = `
create table if not exists test_not_null_columns (
id bigint generated always as identity primary key,
one text,
two text,
three text
);
`
addTriggers = `
create trigger
test_insert_not_null_columns
before
insert on test_not_null_columns
for each row execute procedure not_null_columns('one', 'two');
`
dropTriggers = `drop trigger test_insert_not_null_columns on test_not_null_columns`
)
ctx := context.Background()
conn, _ := TestSetup(t, "postgres")
db, err := conn.SqlDB(ctx)
assert.NoError(t, err)
_, err = db.Exec(createTable)
assert.NoError(t, err)
tests := []struct {
name string
stmt string
wantErr bool
}{
{
name: "null one",
stmt: "insert into test_not_null_columns (one, two, three) values (null, 'two', 'three');",
wantErr: true,
},
{
name: "null two",
stmt: "insert into test_not_null_columns (one, two, three) values ('one', null, 'three');",
wantErr: true,
},
{
name: "all null",
stmt: "insert into test_not_null_columns (one, two, three) values (null, null, null);",
wantErr: true,
},
{
name: "null three",
stmt: "insert into test_not_null_columns (one, two, three) values ('one', 'two', null);",
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
require, assert := require.New(t), assert.New(t)
_, err = db.Exec(addTriggers)
require.NoError(err)
_, err = db.Exec(tt.stmt)
if !tt.wantErr {
assert.NoError(err)
return
}
require.Error(err)
// Drop trigger and run insert again, it should now insert successfully
_, err = db.Exec(dropTriggers)
assert.NoError(err)
_, err = db.Exec(tt.stmt)
assert.NoError(err)
})
}
}