* refact: Changes required for gorm v2 * refact: Add db.DB wrapper and refact all test fixtures to use it Stop leaking the gorm abstraction within our unit tests. * refact: Migrate direct calls to pq to pgx driver The refactor will remove the remaining direct dependencies on the pq driver which has been deprecated in favor of the pgx driver. It includes the addition of common.SqlOpen which is a wrapper around sql.Open, which is needed to deal with the driver name changing from "postgres" to "pgx" but in our code base the dialect and driver are synonyms.
1110 lines
26 KiB
Go
1110 lines
26 KiB
Go
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)
|
|
})
|
|
}
|
|
}
|