From 246efa124f991b3bffc4ebca13865e626a33033c Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Wed, 10 Jan 2024 09:28:18 +0000 Subject: [PATCH] Add tests for tables/columns with comments Cover the cases: * a column with a comment is added via a create table migration * a column with a comment is added via an add column migration. * A new table is added with a comment on the table itself. --- pkg/migrations/op_add_column_test.go | 57 ++++++++++++++++++++++++++ pkg/migrations/op_common_test.go | 48 ++++++++++++++++++++++ pkg/migrations/op_create_table_test.go | 42 +++++++++++++++++++ 3 files changed, 147 insertions(+) diff --git a/pkg/migrations/op_add_column_test.go b/pkg/migrations/op_add_column_test.go index b17975546..b9b085442 100644 --- a/pkg/migrations/op_add_column_test.go +++ b/pkg/migrations/op_add_column_test.go @@ -47,6 +47,7 @@ func TestAddColumn(t *testing.T) { Type: "integer", Nullable: false, Default: ptr("0"), + Comment: ptr("the age of the user"), }, }, }, @@ -751,3 +752,59 @@ func TestAddColumnWithCheckConstraint(t *testing.T) { }, }}) } + +func TestAddColumnWithComment(t *testing.T) { + t.Parallel() + + ExecuteTests(t, TestCases{{ + name: "add column", + migrations: []migrations.Migration{ + { + Name: "01_add_table", + Operations: migrations.Operations{ + &migrations.OpCreateTable{ + Name: "users", + Columns: []migrations.Column{ + { + Name: "id", + Type: "serial", + Pk: true, + }, + { + Name: "name", + Type: "varchar(255)", + Unique: true, + }, + }, + }, + }, + }, + { + Name: "02_add_column", + Operations: migrations.Operations{ + &migrations.OpAddColumn{ + Table: "users", + Column: migrations.Column{ + Name: "age", + Type: "integer", + Nullable: false, + Default: ptr("0"), + Comment: ptr("the age of the user"), + }, + }, + }, + }, + }, + afterStart: func(t *testing.T, db *sql.DB) { + // The comment has been added to the underlying column. + columnName := migrations.TemporaryName("age") + ColumnMustHaveComment(t, db, "public", "users", columnName, "the age of the user") + }, + afterRollback: func(t *testing.T, db *sql.DB) { + }, + afterComplete: func(t *testing.T, db *sql.DB) { + // The comment is still present on the underlying column. + ColumnMustHaveComment(t, db, "public", "users", "age", "the age of the user") + }, + }}) +} diff --git a/pkg/migrations/op_common_test.go b/pkg/migrations/op_common_test.go index 7e3d41d86..164511b88 100644 --- a/pkg/migrations/op_common_test.go +++ b/pkg/migrations/op_common_test.go @@ -146,6 +146,20 @@ func ColumnMustHaveType(t *testing.T, db *sql.DB, schema, table, column, expecte } } +func ColumnMustHaveComment(t *testing.T, db *sql.DB, schema, table, column, expectedComment string) { + t.Helper() + if !columnHasComment(t, db, schema, table, column, expectedComment) { + t.Fatalf("Expected column %q to have comment %q", column, expectedComment) + } +} + +func TableMustHaveComment(t *testing.T, db *sql.DB, schema, table, expectedComment string) { + t.Helper() + if !tableHasComment(t, db, schema, table, expectedComment) { + t.Fatalf("Expected table %q to have comment %q", table, expectedComment) + } +} + func TableMustHaveColumnCount(t *testing.T, db *sql.DB, schema, table string, n int) { t.Helper() if !tableMustHaveColumnCount(t, db, schema, table, n) { @@ -400,6 +414,40 @@ func columnHasType(t *testing.T, db *sql.DB, schema, table, column, expectedType return expectedType == actualType } +func columnHasComment(t *testing.T, db *sql.DB, schema, table, column, expectedComment string) bool { + t.Helper() + + var actualComment string + err := db.QueryRow(fmt.Sprintf(` + SELECT col_description( + %[1]s::regclass, + (SELECT attnum FROM pg_attribute WHERE attname=%[2]s and attrelid=%[1]s::regclass) + )`, + pq.QuoteLiteral(fmt.Sprintf("%s.%s", schema, table)), + pq.QuoteLiteral(column)), + ).Scan(&actualComment) + if err != nil { + t.Fatal(err) + } + + return expectedComment == actualComment +} + +func tableHasComment(t *testing.T, db *sql.DB, schema, table, expectedComment string) bool { + t.Helper() + + var actualComment string + err := db.QueryRow(fmt.Sprintf(` + SELECT obj_description(%[1]s::regclass, 'pg_class')`, + pq.QuoteLiteral(fmt.Sprintf("%s.%s", schema, table))), + ).Scan(&actualComment) + if err != nil { + t.Fatal(err) + } + + return expectedComment == actualComment +} + func MustInsert(t *testing.T, db *sql.DB, schema, version, table string, record map[string]string) { t.Helper() diff --git a/pkg/migrations/op_create_table_test.go b/pkg/migrations/op_create_table_test.go index ae7dc5054..c336404e5 100644 --- a/pkg/migrations/op_create_table_test.go +++ b/pkg/migrations/op_create_table_test.go @@ -230,6 +230,48 @@ func TestCreateTable(t *testing.T) { }) }, }, + { + name: "create table with column and table comments", + migrations: []migrations.Migration{ + { + Name: "01_create_table", + Operations: migrations.Operations{ + &migrations.OpCreateTable{ + Name: "users", + Comment: ptr("the users table"), + Columns: []migrations.Column{ + { + Name: "id", + Type: "serial", + Pk: true, + }, + { + Name: "name", + Type: "varchar(255)", + Unique: true, + Comment: ptr("the username"), + }, + }, + }, + }, + }, + }, + afterStart: func(t *testing.T, db *sql.DB) { + tableName := migrations.TemporaryName("users") + // The comment has been added to the underlying table. + TableMustHaveComment(t, db, "public", tableName, "the users table") + // The comment has been added to the underlying column. + ColumnMustHaveComment(t, db, "public", tableName, "name", "the username") + }, + afterRollback: func(t *testing.T, db *sql.DB) { + }, + afterComplete: func(t *testing.T, db *sql.DB) { + // The comment is still present on the underlying table. + TableMustHaveComment(t, db, "public", "users", "the users table") + // The comment is still present on the underlying column. + ColumnMustHaveComment(t, db, "public", "users", "name", "the username") + }, + }, }) }