ducky/devices

Paddy 2015-11-28 Parent:683050b4546b Child:1ae5bae472c1

12:03c49b4d3d9f Go to Latest

ducky/devices/storer_test.go

Add doc comments to all our exported types. It makes golint happy, and it's a good thing to do. It's kind of shameful that we went so long without them. Oops.

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 }