gitlab.com/beacon-software/gadget@v0.0.0-20181217202115-54565ea1ed5e/database/model_test.go (about) 1 package database 2 3 import ( 4 "fmt" 5 "strconv" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 11 "gitlab.com/beacon-software/gadget/generator" 12 "gitlab.com/beacon-software/gadget/log" 13 ) 14 15 func TestNewPrimaryKey(t *testing.T) { 16 assert := assert.New(t) 17 18 pk := NewPrimaryKey(1) 19 assert.Equal(1, pk.Value()) 20 21 pk = NewPrimaryKey("foo") 22 assert.Equal("foo", pk.Value()) 23 } 24 25 func TestNewListOptions(t *testing.T) { 26 assert := assert.New(t) 27 28 data := []struct { 29 Expected *ListOptions 30 Limit uint 31 Offset uint 32 }{ 33 {&ListOptions{Limit: 1, Offset: 0}, 0, 0}, 34 {&ListOptions{Limit: MaxLimit, Offset: 10}, MaxLimit + 1, 10}, 35 {&ListOptions{Limit: 5, Offset: 5}, 5, 5}, 36 } 37 for _, test := range data { 38 actual := NewListOptions(test.Limit, test.Offset) 39 assert.Equal(test.Expected, actual) 40 } 41 } 42 43 func TestBadConnection(t *testing.T) { 44 assert := assert.New(t) 45 _, err := connect("mysql", "baduser:badpassword@tcp(localhost:3306)/foo", log.NewStackLogger()) 46 assert.EqualError(err, NewDatabaseConnectionError().Error()) 47 } 48 49 func TestBadRecordImplementation(t *testing.T) { 50 assert := assert.New(t) 51 spec := newSpecification() 52 53 record := &DetailsTestRecord{} 54 55 err := spec.DB.Create(record) 56 assert.IsType(&SQLExecutionError{}, err) 57 assert.IsType(&SQLExecutionError{}, spec.DB.Read(record, NewPrimaryKey("foo"))) 58 options := NewListOptions(10, 0) 59 assert.IsType(&SQLExecutionError{}, spec.DB.List(record, []DetailsTestRecord{}, options)) 60 assert.IsType(&SQLExecutionError{}, spec.DB.Update(record)) 61 assert.IsType(&SQLExecutionError{}, spec.DB.Delete(record)) 62 } 63 64 func TestCreate(t *testing.T) { 65 assert := assert.New(t) 66 spec := newSpecification() 67 68 name := generator.Name() 69 record := &TestRecord{Name: name} 70 assert.NoError(spec.DB.Create(record)) 71 assert.Equal(name, record.Name) 72 assert.Equal("tst", record.ID[:3]) 73 assert.Equal(record.PrimaryKey().Value(), record.ID) 74 } 75 76 func TestCreateDuplicate(t *testing.T) { 77 assert := assert.New(t) 78 spec := newSpecification() 79 80 name := generator.Name() 81 record := &TestRecord{Name: name} 82 assert.NoError(spec.DB.Create(record)) 83 assert.Equal(name, record.Name) 84 assert.Equal("tst", record.ID[:3]) 85 86 record = &TestRecord{Name: name} 87 err := spec.DB.Create(record) 88 assert.IsType(&UniqueConstraintError{}, err) 89 } 90 91 func TestRead(t *testing.T) { 92 assert := assert.New(t) 93 spec := newSpecification() 94 95 expected := &TestRecord{Name: generator.Name()} 96 assert.NoError(spec.DB.Create(expected)) 97 98 actual := &TestRecord{} 99 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 100 assert.Equal(expected, actual) 101 } 102 103 func TestReadOneWhere(t *testing.T) { 104 assert := assert.New(t) 105 spec := newSpecification() 106 107 expected := &TestRecord{Name: generator.Name()} 108 assert.NoError(spec.DB.Create(expected)) 109 110 actual := &TestRecord{} 111 assert.NoError(spec.DB.ReadOneWhere(actual, TestMeta.Name.Equal(expected.Name))) 112 assert.Equal(expected, actual) 113 } 114 115 func TestList(t *testing.T) { 116 assert := assert.New(t) 117 spec := newSpecification() 118 119 records := make([]TestRecord, 5) 120 for i := range records { 121 record := &TestRecord{Name: fmt.Sprintf("Test %s", strconv.Itoa(i))} 122 assert.NoError(spec.DB.Create(record)) 123 records[i] = *record 124 } 125 126 lookup := &[]TestRecord{} 127 options := NewListOptions(3, 0) 128 assert.NoError(spec.DB.List(&TestRecord{}, lookup, options)) 129 assert.Equal(3, len(*lookup)) 130 } 131 132 func TestWhere(t *testing.T) { 133 assert := assert.New(t) 134 spec := newSpecification() 135 136 records := make([]*TestRecord, 5) 137 for i := range records { 138 record := &TestRecord{Name: generator.Name()} 139 assert.NoError(spec.DB.Create(record)) 140 records[i] = record 141 } 142 143 where := TestMeta.Name.Equal(records[0].Name) 144 actual := []*TestRecord{} 145 err := spec.DB.ListWhere(&TestRecord{}, &actual, where) 146 if assert.NoError(err) { 147 assert.Equal(records[0], actual[0]) 148 assert.Equal(1, len(actual)) 149 } 150 where = TestMeta.Name.Equal(records[0]) 151 err = spec.DB.ListWhere(&TestRecord{}, &actual, where) 152 assert.Error(err) 153 } 154 155 func TestWhereTx(t *testing.T) { 156 assert := assert.New(t) 157 spec := newSpecification() 158 159 tx := spec.DB.MustBegin() 160 defer tx.Commit() 161 records := make([]*TestRecord, 5) 162 for i := range records { 163 record := &TestRecord{Name: generator.Name()} 164 assert.NoError(spec.DB.CreateTx(record, tx)) 165 records[i] = record 166 } 167 168 where := TestMeta.Name.Equal(records[0].Name) 169 actual := []*TestRecord{} 170 err := spec.DB.ListWhere(&TestRecord{}, &actual, where) 171 if assert.NoError(err) { 172 assert.Equal(0, len(actual)) 173 } 174 175 err = spec.DB.ListWhereTx(tx, &TestRecord{}, &actual, where) 176 if assert.NoError(err) { 177 assert.Equal(records[0], actual[0]) 178 assert.Equal(1, len(actual)) 179 } 180 where = TestMeta.Name.Equal(records[0]) 181 err = spec.DB.ListWhereTx(tx, &TestRecord{}, &actual, where) 182 assert.Error(err) 183 } 184 185 func TestWhereIn(t *testing.T) { 186 assert := assert.New(t) 187 spec := newSpecification() 188 189 records := make([]*TestRecord, 5) 190 for i := range records { 191 record := &TestRecord{Name: generator.Name()} 192 assert.NoError(spec.DB.Create(record)) 193 records[i] = record 194 time.Sleep(time.Second) 195 } 196 197 where := TestMeta.Name.In(records[0].Name, records[1].Name) 198 199 actual := []*TestRecord{} 200 err := spec.DB.ListWhere(&TestRecord{}, &actual, where) 201 if assert.NoError(err) { 202 assert.Equal(records[0], actual[0]) 203 assert.Equal(records[1], actual[1]) 204 assert.Equal(2, len(actual)) 205 } 206 where = TestMeta.Name.In(records[0]) 207 assert.Error(spec.DB.ListWhere(&TestRecord{}, &actual, where)) 208 209 where = TestMeta.Name.In(records[0].Name, records[1].Name).And(TestMeta.ID.Equal(records[0].ID)) 210 actual = []*TestRecord{} 211 err = spec.DB.ListWhere(&TestRecord{}, &actual, where) 212 if assert.NoError(err) { 213 assert.Equal(records[0], actual[0]) 214 assert.Equal(1, len(actual)) 215 } 216 217 where = TestMeta.ID.Equal(records[1].ID).And(TestMeta.Name.In(records[0].Name, records[1].Name)) 218 actual = []*TestRecord{} 219 err = spec.DB.ListWhere(&TestRecord{}, &actual, where) 220 if assert.NoError(err) { 221 assert.Equal(records[1], actual[0]) 222 assert.Equal(1, len(actual)) 223 } 224 } 225 226 func TestDelete(t *testing.T) { 227 assert := assert.New(t) 228 spec := newSpecification() 229 230 expected := &TestRecord{Name: generator.Name()} 231 assert.NoError(spec.DB.Create(expected)) 232 233 actual := &TestRecord{} 234 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 235 assert.Equal(expected, actual) 236 237 assert.NoError(spec.DB.Delete(actual)) 238 assert.IsType(&NotFoundError{}, spec.DB.Read(actual, expected.PrimaryKey())) 239 assert.NoError(spec.DB.Delete(actual)) 240 } 241 242 func TestDeleteTx(t *testing.T) { 243 assert := assert.New(t) 244 spec := newSpecification() 245 246 expected := &TestRecord{Name: generator.Name()} 247 assert.NoError(spec.DB.Create(expected)) 248 249 actual := &TestRecord{} 250 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 251 assert.Equal(expected, actual) 252 253 tx := spec.DB.MustBegin() 254 assert.NoError(spec.DB.DeleteTx(actual, tx)) 255 tx.Rollback() 256 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 257 258 tx = spec.DB.MustBegin() 259 assert.NoError(spec.DB.DeleteTx(actual, tx)) 260 tx.Commit() 261 assert.IsType(&NotFoundError{}, spec.DB.Read(actual, expected.PrimaryKey())) 262 } 263 264 func TestDeleteWhere(t *testing.T) { 265 assert := assert.New(t) 266 spec := newSpecification() 267 268 expected := &TestRecord{Name: generator.Name()} 269 assert.NoError(spec.DB.Create(expected)) 270 271 actual := &TestRecord{} 272 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 273 assert.Equal(expected, actual) 274 275 assert.NoError(spec.DB.DeleteWhere(actual, TestMeta.Name.Equal(expected.Name))) 276 assert.IsType(&NotFoundError{}, spec.DB.Read(actual, expected.PrimaryKey())) 277 assert.NoError(spec.DB.DeleteWhere(actual, TestMeta.Name.Equal(expected.Name))) 278 } 279 280 func TestDeleteWhereTx(t *testing.T) { 281 assert := assert.New(t) 282 spec := newSpecification() 283 284 expected := &TestRecord{Name: "DeleteWhereMe"} 285 assert.NoError(spec.DB.Create(expected)) 286 287 actual := &TestRecord{} 288 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 289 assert.Equal(expected, actual) 290 291 tx := spec.DB.MustBegin() 292 assert.NoError(spec.DB.DeleteWhereTx(actual, tx, TestMeta.Name.Equal(expected.Name))) 293 tx.Rollback() 294 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 295 296 tx = spec.DB.MustBegin() 297 assert.NoError(spec.DB.DeleteWhereTx(actual, tx, TestMeta.Name.Equal(expected.Name))) 298 tx.Commit() 299 assert.IsType(&NotFoundError{}, spec.DB.Read(actual, expected.PrimaryKey())) 300 } 301 302 func TestUpdate(t *testing.T) { 303 assert := assert.New(t) 304 spec := newSpecification() 305 306 expected := &TestRecord{Name: "Update Me"} 307 assert.NoError(spec.DB.Create(expected)) 308 309 actual := &TestRecord{} 310 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 311 assert.Equal(expected, actual) 312 313 expected.Name = "Updated" 314 assert.NoError(spec.DB.Update(expected)) 315 assert.NoError(spec.DB.Read(actual, expected.PrimaryKey())) 316 assert.Equal(expected, actual) 317 } 318 319 func TestUpsertTx(t *testing.T) { 320 assert := assert.New(t) 321 spec := newSpecification() 322 323 recordID := generator.ID("tst") 324 record := &TestRecord{ 325 ID: recordID, 326 Name: generator.Name(), 327 CreatedOn: time.Now(), 328 UpdatedOn: time.Now(), 329 } 330 tx := spec.DB.MustBegin() 331 updatedOn := record.UpdatedOn 332 assert.NoError(spec.DB.UpsertTx(record, tx)) 333 assert.Equal(recordID, record.ID) 334 assert.NotEqual(updatedOn, record.UpdatedOn) 335 336 updatedOn = record.UpdatedOn 337 err := spec.DB.UpsertTx(record, tx) 338 assert.NoError(err) 339 assert.Equal(updatedOn, record.UpdatedOn) 340 341 time.Sleep(2 * time.Second) 342 expected := generator.Name() 343 assert.NotEqual(expected, record.Name) 344 record.Name = expected 345 assert.NoError(spec.DB.UpsertTx(record, tx)) 346 assert.Equal(updatedOn, record.UpdatedOn) 347 assert.Equal(expected, record.Name) 348 tx.Rollback() 349 } 350 351 func TestTransaction(t *testing.T) { 352 assert := assert.New(t) 353 spec := newSpecification() 354 355 name := generator.Name() 356 record := &TestRecord{Name: name} 357 tx, err := spec.DB.Beginx() 358 assert.NoError(err) 359 360 assert.NoError(spec.DB.CreateTx(record, tx)) 361 assert.Equal(name, record.Name) 362 assert.Equal("tst", record.ID[:3]) 363 assert.Equal(record.PrimaryKey().Value(), record.ID) 364 365 actual := &TestRecord{} 366 err = spec.DB.ReadTx(actual, record.PrimaryKey(), tx) 367 assert.NoError(err) 368 tx.Rollback() 369 370 err = spec.DB.Read(actual, record.PrimaryKey()) 371 assert.EqualError(err, NewNotFoundError().Error()) 372 } 373 374 type initDupe struct { 375 i int 376 base string 377 } 378 379 func (id *initDupe) id() string { 380 defer func() { id.base = generator.ID("nodupe") }() 381 return id.base 382 } 383 384 func TestDuplicateID(t *testing.T) { 385 assert := assert.New(t) 386 spec := newSpecification() 387 388 record := NewTestDuper() 389 assert.NoError(spec.DB.Create(record)) 390 assert.Equal("dup", record.ID[:3]) 391 392 record2 := NewTestDuper() 393 assert.NoError(spec.DB.Create(record2)) 394 assert.Equal("dup", record2.ID[:3]) 395 assert.NotEqual(record2.ID, record.ID) 396 397 record3 := NewTestDuper() 398 record3.intializer = func() string { return record.ID } 399 assert.Error(spec.DB.Create(record3)) 400 401 record3 = NewTestDuper() 402 initDuper := &initDupe{base: record.ID} 403 record3.intializer = func() string { return initDuper.id() } 404 405 assert.NoError(spec.DB.Create(record3)) 406 assert.Equal("nodupe", record3.ID[:6]) 407 assert.NotEqual(record3.ID, record.ID) 408 }