-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
CreateTableChangeTest.groovy
327 lines (276 loc) · 13.6 KB
/
CreateTableChangeTest.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
package liquibase.change.core
import liquibase.change.ChangeStatus
import liquibase.change.ColumnConfig
import liquibase.change.ConstraintsConfig
import liquibase.change.StandardChangeTest
import liquibase.database.core.MSSQLDatabase
import liquibase.database.core.MockDatabase
import liquibase.database.core.PostgresDatabase
import liquibase.parser.core.ParsedNode
import liquibase.parser.core.ParsedNodeException
import liquibase.snapshot.MockSnapshotGeneratorFactory
import liquibase.snapshot.SnapshotGeneratorFactory
import liquibase.sqlgenerator.SqlGeneratorFactory
import liquibase.statement.DatabaseFunction
import liquibase.statement.ForeignKeyConstraint
import liquibase.statement.SequenceNextValueFunction
import liquibase.statement.core.CreateTableStatement
import liquibase.structure.core.Column
import liquibase.structure.core.DataType
import liquibase.structure.core.PrimaryKey
import liquibase.structure.core.Table
import spock.lang.Unroll
import static org.junit.Assert.assertTrue
import static org.junit.Assert.fail
public class CreateTableChangeTest extends StandardChangeTest {
def getConfirmationMessage() throws Exception {
when:
def change = new CreateTableChange()
change.setTableName("TAB_NAME")
then:
change.getConfirmationMessage() == "Table TAB_NAME created"
}
@Unroll("statements have correct default values after #method(#defaultValue)")
def "statements have correct default values"() throws Exception {
when:
def change = new CreateTableChange()
def columnConfig = new ColumnConfig()
columnConfig.setName("id")
columnConfig.setType("int")
change.addColumn(columnConfig)
if (method == "defaultValue") {
columnConfig.setDefaultValue(defaultValue)
} else if (method == "defaultValueBoolean") {
columnConfig.setDefaultValueBoolean(defaultValue)
} else if (method == "defaultValueNumeric") {
columnConfig.setDefaultValueNumeric(defaultValue)
} else if (method == "defaultValueDate") {
columnConfig.setDefaultValueDate(defaultValue)
} else if (method == "defaultValueComputed") {
columnConfig.setDefaultValueComputed(defaultValue)
} else if (method == "defaultValueSequenceNext") {
columnConfig.setDefaultValueSequenceNext(defaultValue)
} else {
fail "Unknown method ${method}"
}
then:
def statement = (CreateTableStatement) change.generateStatements(new MockDatabase())[0]
if (expectedValue == "SAME") {
assert statement.getDefaultValue("id") == defaultValue
} else {
assert statement.getDefaultValue("id") == expectedValue
}
where:
defaultValue | method | expectedValue
null | "defaultValue" | "SAME"
"DEFAULTVALUE" | "defaultValue" | "SAME"
Boolean.TRUE | "defaultValueBoolean" | "SAME"
Boolean.FALSE | "defaultValueBoolean" | "SAME"
"true" | "defaultValueBoolean" | Boolean.TRUE
"false" | "defaultValueBoolean" | Boolean.FALSE
42L | "defaultValueNumeric" | "SAME"
15.23 | "defaultValueNumeric" | 15.23
"52" | "defaultValueNumeric" | 52L
"382.3131" | "defaultValueNumeric" | 382.3131
"2007-01-02" | "defaultValueDate" | new java.sql.Date(107, 0, 2)
"2008-03-04T13:14:15" | "defaultValueDate" | new java.sql.Timestamp(108, 2, 4, 13, 14, 15, 0)
new DatabaseFunction("NOW()") | "defaultValueComputed" | "SAME"
new SequenceNextValueFunction("seq_name") | "defaultValueSequenceNext" | "SAME"
}
def createInverse() {
when:
def change = new CreateTableChange()
change.setTableName("TestTable")
then:
def inverses = change.createInverses()
inverses.length == 1
assert inverses[0] instanceof DropTableChange
((DropTableChange) inverses[0]).tableName == "TestTable"
}
def "tablespace defaults to null"() {
when:
def change = new CreateTableChange()
then:
CreateTableStatement statement = (CreateTableStatement) change.generateStatements(new MockDatabase())[0]
statement.getTablespace() == null
}
def "tablespace can be set"() throws Exception {
when:
def change = new CreateTableChange()
change.setTablespace(tablespace)
then:
def statement = (CreateTableStatement) change.generateStatements(new MockDatabase())[0]
statement.getTablespace() == tablespace
where:
tablespace << [null, "TESTTABLESPACE"]
}
def "foreign key deferrability sets correctly"() {
when:
def change = new CreateTableChange()
ColumnConfig columnConfig = new ColumnConfig()
columnConfig.setName("id")
columnConfig.setType("int")
ConstraintsConfig constraints = new ConstraintsConfig()
constraints.setForeignKeyName("fk_test")
constraints.setReferences("test(id)")
constraints.setDeferrable(deferrable)
constraints.setInitiallyDeferred(initiallyDeferred)
columnConfig.setConstraints(constraints)
change.addColumn(columnConfig)
then:
CreateTableStatement statement = (CreateTableStatement) change.generateStatements(new MockDatabase())[0]
ForeignKeyConstraint keyConstraint = statement.getForeignKeyConstraints().iterator().next()
keyConstraint.isDeferrable() == deferrable
keyConstraint.isInitiallyDeferred() == initiallyDeferred
where:
deferrable | initiallyDeferred
true | true
false | true
true | false
false | false
}
def "foreign keys default not deferrable"() throws Exception {
when:
def change = new CreateTableChange()
ColumnConfig columnConfig = new ColumnConfig()
columnConfig.setName("id")
columnConfig.setType("int")
ConstraintsConfig constraints = new ConstraintsConfig()
constraints.setReferences("test(id)")
constraints.setForeignKeyName("fk_test")
columnConfig.setConstraints(constraints)
change.addColumn(columnConfig)
then:
def statement = (CreateTableStatement) change.generateStatements(new MockDatabase())[0]
ForeignKeyConstraint keyConstraint = statement.getForeignKeyConstraints().iterator().next()
assert !keyConstraint.isDeferrable()
assert !keyConstraint.isInitiallyDeferred()
}
def "checkStatus"() {
when:
def table = new Table(null, null, "test_table")
def column1 = new Column(Table.class, table.schema.catalogName, table.schema.name, table.name, "column_1").setType(new DataType("int")).setRelation(table)
def column2 = new Column(Table.class, table.schema.catalogName, table.schema.name, table.name, "column_2").setType(new DataType("boolean")).setRelation(table)
def column3 = new Column(Table.class, table.schema.catalogName, table.schema.name, table.name, "column_3").setType(new DataType("varchar(10)")).setRelation(table)
def change = new CreateTableChange()
change.tableName = table.name
change.addColumn(new ColumnConfig(column1).setType(column1.type.toString()))
change.addColumn(new ColumnConfig(column2).setType(column2.type.toString()))
change.addColumn(new ColumnConfig(column3).setType(column3.type.toString()))
def database = new MockDatabase()
def snapshotFactory = new MockSnapshotGeneratorFactory()
SnapshotGeneratorFactory.instance = snapshotFactory
then: "when no tables"
assert change.checkStatus(database).status == ChangeStatus.Status.notApplied
when: "another table exists but not the target table"
snapshotFactory.addObjects(new Table(null, null, "other_table"))
then:
assert change.checkStatus(database).status == ChangeStatus.Status.notApplied
when: "expected table exists but is missing columns"
table.getColumns().add(column1)
table.getColumns().add(column2)
snapshotFactory.addObjects(table)
then:
assert change.checkStatus(database).status == ChangeStatus.Status.incorrect
when: "all columns exist"
table.getColumns().add(column3)
snapshotFactory.addObjects(column3)
then:
assert change.checkStatus(database).status == ChangeStatus.Status.complete
when: "column is supposed to be primary key but table is not"
change.getColumns().get(0).setConstraints(new ConstraintsConfig().setPrimaryKey(true))
then:
assert change.checkStatus(database).status == ChangeStatus.Status.incorrect
when: "table has primary key as expected"
def pk = new PrimaryKey("pk_test", table.schema.catalogName, table.schema.name, table.name, new Column(column1.name))
table.setPrimaryKey(pk)
snapshotFactory.addObjects(pk)
then:
assert change.checkStatus(database).status == ChangeStatus.Status.complete
when: "nullability is different"
change.getColumns().get(1).setConstraints(new ConstraintsConfig().setNullable(false))
then:
assert change.checkStatus(database).status == ChangeStatus.Status.incorrect
when: "column nullability matches"
table.getColumns().get(1).nullable = false
then:
assert change.checkStatus(database).status == ChangeStatus.Status.complete
}
def "load can take nested 'column' nodes, not just 'columns' nodes"() {
when:
def node = new ParsedNode(null, "createTable").addChildren([tableName: "table_name"])
.addChildren([column: [name: "column1", type: "type1"]])
.addChildren([column: [name: "column2", type: "type2"]])
def change = new CreateTableChange()
try {
change.load(node, resourceSupplier.simpleResourceAccessor)
} catch (ParsedNodeException e) {
e.printStackTrace()
}
then:
change.tableName == "table_name"
change.columns.size() == 2
change.columns[0].name == "column1"
change.columns[0].type == "type1"
change.columns[1].name == "column2"
change.columns[1].type == "type2"
}
def "load can take a nested 'columns' collection nodes"() {
when:
def node = new ParsedNode(null, "createTable").addChildren([tableName: "table_name"])
.addChild(null, "columns", [[column: [name: "column1", type: "type1"]], [column: [name: "column2", type: "type2"]]])
def change = new CreateTableChange()
try {
change.load(node, resourceSupplier.simpleResourceAccessor)
} catch (ParsedNodeException e) {
e.printStackTrace()
}
then:
change.tableName == "table_name"
change.columns.size() == 2
change.columns[0].name == "column1"
change.columns[0].type == "type1"
change.columns[1].name == "column2"
change.columns[1].type == "type2"
}
@Unroll("validate autoincrement type statements")
def "generateStatements"() {
when:
def change = new CreateTableChange(tableName: "test_table")
def columnConfig = new ColumnConfig()
columnConfig.setName("id")
columnConfig.setType(type)
columnConfig.setAutoIncrement(autoinc)
change.addColumn(columnConfig)
then:
SqlGeneratorFactory.getInstance().generateSql(change, database)[0].toSql() == expected
where:
type | autoinc | database | expected
"int" | true | new MockDatabase() | "CREATE TABLE test_table (id INT null)"
"SERIAL" | false | new PostgresDatabase() | "CREATE TABLE test_table (id INTEGER GENERATED BY DEFAULT AS IDENTITY)"
"SMALLSERIAL" | false | new PostgresDatabase() | "CREATE TABLE test_table (id SMALLSERIAL)"
"BIGSERIAL" | false | new PostgresDatabase() | "CREATE TABLE test_table (id BIGINT GENERATED BY DEFAULT AS IDENTITY)"
}
def "computed columns can be created"() throws Exception {
when:
def change = new CreateTableChange()
change.setTableName("test_table")
change.addColumn(new ColumnConfig().setName("regular_col").setType("int"))
change.addColumn(new ColumnConfig().setName("value_id AS JSON_VALUE(value,'\$.id')", true))
then:
!change.validate(new MSSQLDatabase()).hasErrors()
SqlGeneratorFactory.instance.generateSql(change, new MSSQLDatabase())*.toSql() == ["CREATE TABLE test_table (regular_col int, value_id AS JSON_VALUE(value,'\$.id'))"]
}
def "column remarks can be set with createTable"() throws Exception {
when:
def change = new CreateTableChange()
ColumnConfig columnConfig = new ColumnConfig()
columnConfig.setName("id")
columnConfig.setType("int")
columnConfig.setRemarks("test remark")
change.addColumn(columnConfig)
then:
def statement = (CreateTableStatement) change.generateStatements(new MockDatabase())[0]
assertTrue(statement.getColumnRemarks("id").equals("test remark"))
}
}