mirror of https://github.com/hashicorp/boundary
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1110 lines
26 KiB
1110 lines
26 KiB
package db
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang-sql/civil"
|
|
"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{"u_anon", "u_auth"} {
|
|
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)
|
|
})
|
|
}
|
|
}
|