ducky/devices

Paddy 2015-11-29 Parent:683050b4546b Child:c24a6c5fcd8c

14:1ae5bae472c1 Go to Latest

ducky/devices/storer_test.go

Set up DeleteDevices in Memstore. Implement the DeleteDevices method for our Memstore, removing the Devices specified by the passed IDs. Also, create a simple test that verifies that when Devices are deleted, only the Devices you intend to delete are actually deleted. Further tests should be written to verify that this extends to ListDevicesByOwner (e.g., deleted devices will not be returned when listing them), CreateDevices (e.g., will not result in an ErrDeviceAlreadyExists error), and UpdateDevice (e.g., will return an ErrDeviceNotFound error after the Device is deleted). But for now, we're confident that it works in the simplest possible case.

History
paddy@2 1 package devices
paddy@2 2
paddy@2 3 import (
paddy@10 4 "fmt"
paddy@2 5 "testing"
paddy@2 6 "time"
paddy@2 7
paddy@2 8 "code.secondbit.org/uuid.hg"
paddy@2 9 "golang.org/x/net/context"
paddy@2 10 )
paddy@2 11
paddy@9 12 type StorerFactory interface {
paddy@9 13 NewStorer(ctx context.Context) (Storer, error)
paddy@9 14 TeardownStorer(storer Storer, ctx context.Context) error
paddy@9 15 }
paddy@9 16
paddy@9 17 var storerFactories []StorerFactory
paddy@2 18
paddy@10 19 const (
paddy@10 20 changeName = 1 << iota
paddy@10 21 changeOwner
paddy@10 22 changeType
paddy@10 23 changeCreated
paddy@10 24 changeLastSeen
paddy@10 25 changePushToken
paddy@10 26 changeVariations
paddy@10 27 )
paddy@10 28
paddy@2 29 func compareDevices(device1, device2 Device) (ok bool, field string, expected, result interface{}) {
paddy@2 30 if !device1.ID.Equal(device2.ID) {
paddy@2 31 return false, "ID", device1.ID, device2.ID
paddy@2 32 }
paddy@2 33 if device1.Name != device2.Name {
paddy@2 34 return false, "Name", device1.Name, device2.Name
paddy@2 35 }
paddy@2 36 if !device1.Owner.Equal(device2.Owner) {
paddy@2 37 return false, "Owner", device1.Owner, device2.Owner
paddy@2 38 }
paddy@2 39 if device1.Type != device2.Type {
paddy@2 40 return false, "Type", device1.Type, device2.Type
paddy@2 41 }
paddy@2 42 if !device1.Created.Equal(device2.Created) {
paddy@2 43 return false, "Created", device1.Created, device2.Created
paddy@2 44 }
paddy@2 45 if !device1.LastSeen.Equal(device2.LastSeen) {
paddy@2 46 return false, "LastSeen", device1.LastSeen, device2.LastSeen
paddy@2 47 }
paddy@2 48 if device1.PushToken != device2.PushToken {
paddy@2 49 return false, "PushToken", device1.PushToken, device2.PushToken
paddy@2 50 }
paddy@2 51 return true, "", nil, nil
paddy@2 52 }
paddy@2 53
paddy@5 54 func TestCreateAndGetDevices(t *testing.T) {
paddy@9 55 for _, factory := range storerFactories {
paddy@10 56 ctx := context.Background()
paddy@10 57 storer, err := factory.NewStorer(ctx)
paddy@2 58 if err != nil {
paddy@9 59 t.Fatalf("Fatal error creating Storer from %T: %+v\n", factory, err)
paddy@2 60 }
paddy@2 61
paddy@2 62 devices := []Device{
paddy@2 63 {ID: uuid.NewID(), Name: "Test 1", Owner: uuid.NewID(), Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@2 64 {ID: uuid.NewID(), Name: "Test 2", Owner: uuid.NewID(), Type: TypeAndroidTablet, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@2 65 {ID: uuid.NewID(), Name: "Test 3", Owner: uuid.NewID(), Type: TypeChromeExtension, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@2 66 }
paddy@3 67
paddy@10 68 err = storer.CreateDevices(devices, ctx)
paddy@3 69 if err != nil {
paddy@5 70 t.Errorf("Error creating devices in %T: %+v\n", storer, err)
paddy@3 71 }
paddy@3 72
paddy@2 73 ids := make([]uuid.ID, 0, len(devices))
paddy@2 74 for _, device := range devices {
paddy@2 75 ids = append(ids, device.ID)
paddy@2 76 }
paddy@2 77
paddy@10 78 results, err := storer.GetDevices(ids, ctx)
paddy@2 79 if err != nil {
paddy@2 80 t.Errorf("Unexpected error retrieving devices from %T: %+v\n", storer, err)
paddy@2 81 }
paddy@2 82 for _, device := range devices {
paddy@2 83 d, returned := results[device.ID.String()]
paddy@2 84 if !returned {
paddy@2 85 t.Errorf("Expected device %s to be in results from %T, but wasn't present\n", device.Name, storer)
paddy@2 86 }
paddy@2 87 ok, field, expected, result := compareDevices(device, d)
paddy@2 88 if !ok {
paddy@2 89 t.Errorf("Expected %s of %s to be %v, got %v from %T\n", field, device.Name, expected, result, storer)
paddy@2 90 }
paddy@2 91 }
paddy@10 92 err = factory.TeardownStorer(storer, ctx)
paddy@2 93 if err != nil {
paddy@2 94 t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
paddy@2 95 }
paddy@2 96 }
paddy@2 97 }
paddy@5 98
paddy@5 99 func TestGetDevicesNoErrorForMissing(t *testing.T) {
paddy@9 100 for _, factory := range storerFactories {
paddy@10 101 ctx := context.Background()
paddy@10 102 storer, err := factory.NewStorer(ctx)
paddy@5 103 if err != nil {
paddy@9 104 t.Fatalf("Fatal error creatng Storer from %T: %+v\n", factory, err)
paddy@5 105 }
paddy@5 106
paddy@10 107 results, err := storer.GetDevices([]uuid.ID{uuid.NewID()}, ctx)
paddy@5 108 if err != nil {
paddy@5 109 t.Errorf("Unexpected error retrieving devices from %T: %+v\n", storer, err)
paddy@5 110 }
paddy@5 111 if len(results) != 0 {
paddy@5 112 t.Errorf("Expected results to be empty, got %+v from %T instead\n", results, storer)
paddy@5 113 }
paddy@10 114 err = factory.TeardownStorer(storer, ctx)
paddy@5 115 if err != nil {
paddy@5 116 t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
paddy@5 117 }
paddy@5 118 }
paddy@5 119 }
paddy@5 120
paddy@5 121 func TestCreateDevicesDuplicates(t *testing.T) {
paddy@9 122 for _, factory := range storerFactories {
paddy@10 123 ctx := context.Background()
paddy@10 124 storer, err := factory.NewStorer(ctx)
paddy@5 125 if err != nil {
paddy@9 126 t.Fatalf("Fatal error creating Storer from %T: %+v\n", factory, err)
paddy@5 127 }
paddy@5 128
paddy@5 129 devices := []Device{
paddy@5 130 {ID: uuid.NewID(), Name: "Test 1", Owner: uuid.NewID(), Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@5 131 {ID: uuid.NewID(), Name: "Test 2", Owner: uuid.NewID(), Type: TypeAndroidTablet, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@5 132 {ID: uuid.NewID(), Name: "Test 3", Owner: uuid.NewID(), Type: TypeChromeExtension, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@5 133 }
paddy@5 134
paddy@10 135 err = storer.CreateDevices(devices, ctx)
paddy@5 136 if err != nil {
paddy@5 137 t.Errorf("Unexpected error creating devices in %T: %+v\n", storer, err)
paddy@5 138 }
paddy@5 139
paddy@5 140 newDevices := []Device{
paddy@5 141 {ID: uuid.NewID(), Name: "Test 4", Owner: uuid.NewID(), Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@5 142 {ID: uuid.NewID(), Name: "Test 5", Owner: uuid.NewID(), Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@5 143 }
paddy@5 144
paddy@10 145 err = storer.CreateDevices([]Device{newDevices[0], devices[1], newDevices[1]}, ctx)
paddy@5 146 daeErr, ok := err.(ErrDeviceAlreadyExists)
paddy@5 147 if !ok {
paddy@5 148 t.Errorf("Expected ErrDeviceAlreadyExists creating duplicate device in %T, got %+v\n", storer, err)
paddy@5 149 }
paddy@5 150 if !uuid.ID(daeErr).Equal(devices[1].ID) {
paddy@5 151 t.Errorf("Expected ErrDeviceAlreadyExists to be %+v, got %+v from %T\n", devices[1].ID, daeErr, storer)
paddy@5 152 }
paddy@5 153
paddy@5 154 // inserts should be a transaction; they either all make it, or none do
paddy@10 155 results, err := storer.GetDevices([]uuid.ID{newDevices[0].ID, newDevices[1].ID}, ctx)
paddy@5 156 if err != nil {
paddy@5 157 t.Errorf("Error retrieving devices from %T: %+v\n", storer, err)
paddy@5 158 }
paddy@5 159 if len(results) != 0 {
paddy@5 160 t.Errorf("Expected new inserts to not be in results, got %+v from %T\n", results, storer)
paddy@5 161 }
paddy@5 162
paddy@10 163 err = factory.TeardownStorer(storer, ctx)
paddy@5 164 if err != nil {
paddy@5 165 t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
paddy@5 166 }
paddy@5 167 }
paddy@5 168 }
paddy@8 169
paddy@8 170 func TestCreateAndListDevicesByOwner(t *testing.T) {
paddy@9 171 for _, factory := range storerFactories {
paddy@10 172 ctx := context.Background()
paddy@10 173 storer, err := factory.NewStorer(ctx)
paddy@8 174 if err != nil {
paddy@9 175 t.Fatalf("Fatal error creating Storer from %T: %+v\n", factory, err)
paddy@8 176 }
paddy@8 177
paddy@8 178 owner1, owner2 := uuid.NewID(), uuid.NewID()
paddy@8 179 devices := []Device{
paddy@8 180 {ID: uuid.NewID(), Name: "Test 1", Owner: owner1, Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@8 181 {ID: uuid.NewID(), Name: "Test 2", Owner: owner2, Type: TypeAndroidTablet, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@8 182 {ID: uuid.NewID(), Name: "Test 3", Owner: owner1, Type: TypeChromeExtension, Created: time.Now().Add(time.Minute), LastSeen: time.Now(), PushToken: "test token"},
paddy@8 183 }
paddy@8 184
paddy@10 185 err = storer.CreateDevices(devices, ctx)
paddy@8 186 if err != nil {
paddy@8 187 t.Errorf("Error creating devices in %T: %+v\n", storer, err)
paddy@8 188 }
paddy@8 189
paddy@10 190 results, err := storer.ListDevicesByOwner(owner1, ctx)
paddy@8 191 if err != nil {
paddy@8 192 t.Errorf("Error listing devices for owner1 from %T: %+v\n", storer, err)
paddy@8 193 }
paddy@8 194 if len(results) != 2 {
paddy@8 195 t.Errorf("Expected %d results for owner1, got %d from %T\n", 2, len(results), storer)
paddy@8 196 }
paddy@8 197 resultMap := ToMap(results)
paddy@8 198 d, ok := resultMap[devices[0].ID.String()]
paddy@8 199 if !ok {
paddy@8 200 t.Errorf("Expected to get %s in results, got %+v from %T\n", devices[0].Name, results, storer)
paddy@8 201 }
paddy@8 202 ok, field, expected, result := compareDevices(devices[0], d)
paddy@8 203 if !ok {
paddy@8 204 t.Errorf("Expected %s of %s to be %v, got %v from %T\n", field, devices[0].Name, expected, result, storer)
paddy@8 205 }
paddy@8 206 d, ok = resultMap[devices[2].ID.String()]
paddy@8 207 if !ok {
paddy@8 208 t.Errorf("Expected to get %s in results, got %+v from %T\n", devices[2].Name, results, storer)
paddy@8 209 }
paddy@8 210 ok, field, expected, result = compareDevices(devices[2], d)
paddy@8 211 if !ok {
paddy@8 212 t.Errorf("Expected %s of %s to be %v, got %v from %T\n", field, devices[2].Name, expected, result, storer)
paddy@8 213 }
paddy@8 214
paddy@10 215 results, err = storer.ListDevicesByOwner(owner2, ctx)
paddy@8 216 if err != nil {
paddy@8 217 t.Errorf("Error listing devices for owner2 from %T: %+v\n", storer, err)
paddy@8 218 }
paddy@8 219 if len(results) != 1 {
paddy@8 220 t.Errorf("Expected %d results for owner2, got %d from %T\n", 1, len(results), storer)
paddy@8 221 }
paddy@8 222 ok, field, expected, result = compareDevices(devices[1], results[0])
paddy@8 223 if !ok {
paddy@8 224 t.Errorf("Expected %s of %s to be %v, got %v from %T\n", field, devices[1].Name, expected, result, storer)
paddy@8 225 }
paddy@8 226
paddy@10 227 err = factory.TeardownStorer(storer, ctx)
paddy@8 228 if err != nil {
paddy@8 229 t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
paddy@8 230 }
paddy@8 231 }
paddy@8 232 }
paddy@10 233
paddy@10 234 func TestUpdateDevicesHappyPath(t *testing.T) {
paddy@10 235 device := Device{
paddy@10 236 ID: uuid.NewID(),
paddy@10 237 Name: "Test 1",
paddy@10 238 Owner: uuid.NewID(),
paddy@10 239 Type: TypeAndroidPhone,
paddy@10 240 Created: time.Now(),
paddy@10 241 LastSeen: time.Now(),
paddy@10 242 PushToken: "test token",
paddy@10 243 }
paddy@10 244 for _, factory := range storerFactories {
paddy@10 245 ctx := context.Background()
paddy@10 246 storer, err := factory.NewStorer(ctx)
paddy@10 247 if err != nil {
paddy@10 248 t.Fatalf("Fatal error creating Storer from %T: %+v\n", factory, err)
paddy@10 249 }
paddy@10 250 for i := 1; i < changeVariations; i++ {
paddy@10 251 var change DeviceChange
paddy@10 252 var owner uuid.ID
paddy@10 253 var name, pushToken string
paddy@10 254 var created, lastSeen time.Time
paddy@10 255 var deviceType DeviceType
paddy@10 256
paddy@10 257 device.ID = uuid.NewID()
paddy@10 258
paddy@10 259 expectation := device
paddy@10 260 result := device
paddy@10 261
paddy@10 262 change.DeviceID = device.ID
paddy@10 263
paddy@10 264 if i&changeName != 0 {
paddy@10 265 name = fmt.Sprintf("name-%d", i)
paddy@10 266 change.Name = &name
paddy@10 267 expectation.Name = name
paddy@10 268 }
paddy@10 269 if i&changeOwner != 0 {
paddy@10 270 owner = uuid.NewID()
paddy@10 271 change.Owner = &owner
paddy@10 272 expectation.Owner = owner
paddy@10 273 }
paddy@10 274 if i&changeType != 0 {
paddy@10 275 deviceType = DeviceType(fmt.Sprintf("type-%d", i))
paddy@10 276 change.Type = &deviceType
paddy@10 277 expectation.Type = deviceType
paddy@10 278 }
paddy@10 279 if i&changeCreated != 0 {
paddy@10 280 created = time.Now().Add(time.Hour * time.Duration(i))
paddy@10 281 change.Created = &created
paddy@10 282 expectation.Created = created
paddy@10 283 }
paddy@10 284 if i&changeLastSeen != 0 {
paddy@10 285 lastSeen = time.Now().Add(time.Minute * time.Duration(i*-1))
paddy@10 286 change.LastSeen = &lastSeen
paddy@10 287 expectation.LastSeen = lastSeen
paddy@10 288 }
paddy@10 289 if i&changePushToken != 0 {
paddy@10 290 pushToken = fmt.Sprintf("push-token-%d", i)
paddy@10 291 change.PushToken = &pushToken
paddy@10 292 expectation.PushToken = pushToken
paddy@10 293 }
paddy@10 294 result = ApplyChange(result, change)
paddy@10 295 ok, field, expectedVal, resultVal := compareDevices(expectation, result)
paddy@10 296 if !ok {
paddy@10 297 t.Errorf("Expected %s of %s to be %v, got %v after applying DeviceChange %+v\n", field, device.Name, expectedVal, resultVal, change)
paddy@10 298 }
paddy@10 299
paddy@10 300 err = storer.CreateDevices([]Device{device}, ctx)
paddy@10 301 if err != nil {
paddy@10 302 t.Errorf("Unexpected error creating devices in %T: %+v\n", storer, err)
paddy@10 303 }
paddy@10 304
paddy@10 305 err = storer.UpdateDevice(change, ctx)
paddy@10 306 if err != nil {
paddy@10 307 t.Errorf("Unexpected error updating device in %T: %+v\n", storer, err)
paddy@10 308 }
paddy@10 309
paddy@10 310 retrieved, err := storer.GetDevices([]uuid.ID{device.ID}, ctx)
paddy@10 311 if err != nil {
paddy@10 312 t.Errorf("Unexpected error retrieving devices from %T: %+v\n", storer, err)
paddy@10 313 }
paddy@10 314 retrievedDevice, ok := retrieved[device.ID.String()]
paddy@10 315 if !ok {
paddy@10 316 t.Errorf("Expected retrieved devices to contain %s, got %+v from %T\n", device.Name, retrieved, storer)
paddy@10 317 }
paddy@10 318 ok, field, expectedVal, resultVal = compareDevices(expectation, retrievedDevice)
paddy@10 319 if !ok {
paddy@10 320 t.Errorf("Expected %s of %s to be %v, got %v from %T\n", field, device.Name, expectedVal, resultVal, storer)
paddy@10 321 }
paddy@10 322 }
paddy@10 323
paddy@10 324 err = factory.TeardownStorer(storer, ctx)
paddy@10 325 if err != nil {
paddy@10 326 t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
paddy@10 327 }
paddy@10 328 }
paddy@10 329 }
paddy@11 330
paddy@11 331 func TestUpdateDeviceNotFound(t *testing.T) {
paddy@11 332 for _, factory := range storerFactories {
paddy@11 333 ctx := context.Background()
paddy@11 334 storer, err := factory.NewStorer(ctx)
paddy@11 335 if err != nil {
paddy@11 336 t.Fatalf("Fatal error creating Storer from %T: %+v\n", factory, err)
paddy@11 337 }
paddy@11 338
paddy@11 339 deviceID := uuid.NewID()
paddy@11 340 name := "my new name"
paddy@11 341 change := DeviceChange{DeviceID: deviceID, Name: &name}
paddy@11 342
paddy@11 343 err = storer.UpdateDevice(change, ctx)
paddy@11 344 if err != ErrDeviceNotFound {
paddy@11 345 t.Errorf("Expected error to be ErrDeviceNotFound, %T returned %+v\n", storer, err)
paddy@11 346 }
paddy@11 347
paddy@11 348 results, err := storer.GetDevices([]uuid.ID{deviceID}, ctx)
paddy@11 349 if err != nil {
paddy@11 350 t.Errorf("Error retrieving devices from %T: %+v\n", storer, err)
paddy@11 351 }
paddy@11 352 if len(results) != 0 {
paddy@11 353 t.Errorf("Expected no devices in %T, got %+v\n", storer, results)
paddy@11 354 }
paddy@11 355
paddy@11 356 err = factory.TeardownStorer(storer, ctx)
paddy@11 357 if err != nil {
paddy@11 358 t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
paddy@11 359 }
paddy@11 360 }
paddy@11 361 }
paddy@14 362
paddy@14 363 func TestDeleteDevicesHappyPath(t *testing.T) {
paddy@14 364 for _, factory := range storerFactories {
paddy@14 365 ctx := context.Background()
paddy@14 366 storer, err := factory.NewStorer(ctx)
paddy@14 367 if err != nil {
paddy@14 368 t.Fatalf("Fatal error creating Storer from %T: %+v\n", factory, err)
paddy@14 369 }
paddy@14 370
paddy@14 371 owner1, owner2 := uuid.NewID(), uuid.NewID()
paddy@14 372
paddy@14 373 devices := []Device{
paddy@14 374 {ID: uuid.NewID(), Name: "Test 1", Owner: owner1, Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@14 375 {ID: uuid.NewID(), Name: "Test 2", Owner: owner2, Type: TypeAndroidTablet, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@14 376 {ID: uuid.NewID(), Name: "Test 3", Owner: owner1, Type: TypeChromeExtension, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
paddy@14 377 }
paddy@14 378
paddy@14 379 err = storer.CreateDevices(devices, ctx)
paddy@14 380 if err != nil {
paddy@14 381 t.Errorf("Error creating devices in %T: %+v\n", storer, err)
paddy@14 382 }
paddy@14 383
paddy@14 384 err = storer.DeleteDevices([]uuid.ID{devices[0].ID, devices[1].ID}, ctx)
paddy@14 385 if err != nil {
paddy@14 386 t.Errorf("Error deleting devices from %T: %+v\n", storer, err)
paddy@14 387 }
paddy@14 388
paddy@14 389 results, err := storer.GetDevices([]uuid.ID{devices[0].ID, devices[1].ID, devices[2].ID}, ctx)
paddy@14 390 if err != nil {
paddy@14 391 t.Errorf("Unexpected error retrieving devices from %T: %+v\n", storer, err)
paddy@14 392 }
paddy@14 393
paddy@14 394 if len(results) != 1 {
paddy@14 395 t.Errorf("Expected %d results, got %d from %T\n", 1, len(results), storer)
paddy@14 396 }
paddy@14 397
paddy@14 398 device, ok := results[devices[0].ID.String()]
paddy@14 399 if ok {
paddy@14 400 t.Errorf("Retrieved first device (which was deleted!) from %T: %+v\n", storer, device)
paddy@14 401 }
paddy@14 402
paddy@14 403 device, ok = results[devices[1].ID.String()]
paddy@14 404 if ok {
paddy@14 405 t.Errorf("Retrieved second device (which was deleted!) from %T: %+v\n", storer, device)
paddy@14 406 }
paddy@14 407
paddy@14 408 device, ok = results[devices[2].ID.String()]
paddy@14 409 if !ok {
paddy@14 410 t.Errorf("Didn't retrieve third device (which wasn't deleted!) from %T. Got %+v\n", storer, results)
paddy@14 411 }
paddy@14 412
paddy@14 413 err = factory.TeardownStorer(storer, ctx)
paddy@14 414 if err != nil {
paddy@14 415 t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
paddy@14 416 }
paddy@14 417 }
paddy@14 418 }