ducky/devices

Paddy 2015-11-14 Parent:7bc6a84ac906 Child:e0bf06577ba5

5:408abf6e48d3 Browse Files

Add more interface tests. Add a test to ensure that, when retrieving Devices, no error is returned if a Device cannot be found. Add a test to ensure that, when adding Devices, adding a Device that shares an ID with a Device already in the Storer returns an ErrDeviceAlreadyExists error. This involved creating the ErrDeviceAlreadyExists error, and modifying the in-memory implementation to properly return it. Fix a go vet issue in our previous test, wherein we forgot to pass the storer to a log message, resulting in a mismatch between the number of variables expected and the number of variables provided. Rename our tests to be better reflective of what they actually test.

devices.go memstore.go storer_test.go

     1.1 --- a/devices.go	Thu Nov 12 23:26:26 2015 -0800
     1.2 +++ b/devices.go	Sat Nov 14 05:56:04 2015 -0800
     1.3 @@ -2,6 +2,7 @@
     1.4  
     1.5  import (
     1.6  	"errors"
     1.7 +	"fmt"
     1.8  	"log"
     1.9  	"time"
    1.10  
    1.11 @@ -81,6 +82,12 @@
    1.12  	Destroy(c context.Context) error
    1.13  }
    1.14  
    1.15 +type ErrDeviceAlreadyExists uuid.ID
    1.16 +
    1.17 +func (e ErrDeviceAlreadyExists) Error() string {
    1.18 +	return fmt.Sprintf("device with ID %s already exists in datastore", uuid.ID(e).String())
    1.19 +}
    1.20 +
    1.21  // GetMany returns as many of the Devices specified by the passed IDs as possible.
    1.22  // They are returned as a map, with the key being the string version of the ID.
    1.23  // No error will be returned if a Device can't be found.
     2.1 --- a/memstore.go	Thu Nov 12 23:26:26 2015 -0800
     2.2 +++ b/memstore.go	Sat Nov 14 05:56:04 2015 -0800
     2.3 @@ -47,6 +47,12 @@
     2.4  	defer m.lock.Unlock()
     2.5  
     2.6  	for _, device := range devices {
     2.7 +		if _, ok := m.devices[device.ID.String()]; ok {
     2.8 +			return ErrDeviceAlreadyExists(device.ID)
     2.9 +		}
    2.10 +	}
    2.11 +
    2.12 +	for _, device := range devices {
    2.13  		m.devices[device.ID.String()] = device
    2.14  	}
    2.15  	return nil
     3.1 --- a/storer_test.go	Thu Nov 12 23:26:26 2015 -0800
     3.2 +++ b/storer_test.go	Sat Nov 14 05:56:04 2015 -0800
     3.3 @@ -35,7 +35,7 @@
     3.4  	return true, "", nil, nil
     3.5  }
     3.6  
     3.7 -func TestGetDevicesHappyPath(t *testing.T) {
     3.8 +func TestCreateAndGetDevices(t *testing.T) {
     3.9  	for _, storer := range storers {
    3.10  		storer, err := storer.Factory(context.TODO())
    3.11  		if err != nil {
    3.12 @@ -50,7 +50,7 @@
    3.13  
    3.14  		err = storer.CreateDevices(devices, context.TODO())
    3.15  		if err != nil {
    3.16 -			t.Errorf("Error creating devices in %T: %+v\n", err)
    3.17 +			t.Errorf("Error creating devices in %T: %+v\n", storer, err)
    3.18  		}
    3.19  
    3.20  		ids := make([]uuid.ID, 0, len(devices))
    3.21 @@ -78,3 +78,72 @@
    3.22  		}
    3.23  	}
    3.24  }
    3.25 +
    3.26 +func TestGetDevicesNoErrorForMissing(t *testing.T) {
    3.27 +	for _, storer := range storers {
    3.28 +		storer, err := storer.Factory(context.TODO())
    3.29 +		if err != nil {
    3.30 +			t.Fatalf("Fatal error creatng %T: %+v\n", storer, err)
    3.31 +		}
    3.32 +
    3.33 +		results, err := storer.GetDevices([]uuid.ID{uuid.NewID()}, context.TODO())
    3.34 +		if err != nil {
    3.35 +			t.Errorf("Unexpected error retrieving devices from %T: %+v\n", storer, err)
    3.36 +		}
    3.37 +		if len(results) != 0 {
    3.38 +			t.Errorf("Expected results to be empty, got %+v from %T instead\n", results, storer)
    3.39 +		}
    3.40 +		err = storer.Destroy(context.TODO())
    3.41 +		if err != nil {
    3.42 +			t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
    3.43 +		}
    3.44 +	}
    3.45 +}
    3.46 +
    3.47 +func TestCreateDevicesDuplicates(t *testing.T) {
    3.48 +	for _, storer := range storers {
    3.49 +		storer, err := storer.Factory(context.TODO())
    3.50 +		if err != nil {
    3.51 +			t.Fatalf("Fatal error creating %T: %+v\n", storer, err)
    3.52 +		}
    3.53 +
    3.54 +		devices := []Device{
    3.55 +			{ID: uuid.NewID(), Name: "Test 1", Owner: uuid.NewID(), Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
    3.56 +			{ID: uuid.NewID(), Name: "Test 2", Owner: uuid.NewID(), Type: TypeAndroidTablet, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
    3.57 +			{ID: uuid.NewID(), Name: "Test 3", Owner: uuid.NewID(), Type: TypeChromeExtension, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
    3.58 +		}
    3.59 +
    3.60 +		err = storer.CreateDevices(devices, context.TODO())
    3.61 +		if err != nil {
    3.62 +			t.Errorf("Unexpected error creating devices in %T: %+v\n", storer, err)
    3.63 +		}
    3.64 +
    3.65 +		newDevices := []Device{
    3.66 +			{ID: uuid.NewID(), Name: "Test 4", Owner: uuid.NewID(), Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
    3.67 +			{ID: uuid.NewID(), Name: "Test 5", Owner: uuid.NewID(), Type: TypeAndroidPhone, Created: time.Now(), LastSeen: time.Now(), PushToken: "test token"},
    3.68 +		}
    3.69 +
    3.70 +		err = storer.CreateDevices([]Device{newDevices[0], devices[1], newDevices[1]}, context.TODO())
    3.71 +		daeErr, ok := err.(ErrDeviceAlreadyExists)
    3.72 +		if !ok {
    3.73 +			t.Errorf("Expected ErrDeviceAlreadyExists creating duplicate device in %T, got %+v\n", storer, err)
    3.74 +		}
    3.75 +		if !uuid.ID(daeErr).Equal(devices[1].ID) {
    3.76 +			t.Errorf("Expected ErrDeviceAlreadyExists to be %+v, got %+v from %T\n", devices[1].ID, daeErr, storer)
    3.77 +		}
    3.78 +
    3.79 +		// inserts should be a transaction; they either all make it, or none do
    3.80 +		results, err := storer.GetDevices([]uuid.ID{newDevices[0].ID, newDevices[1].ID}, context.TODO())
    3.81 +		if err != nil {
    3.82 +			t.Errorf("Error retrieving devices from %T: %+v\n", storer, err)
    3.83 +		}
    3.84 +		if len(results) != 0 {
    3.85 +			t.Errorf("Expected new inserts to not be in results, got %+v from %T\n", results, storer)
    3.86 +		}
    3.87 +
    3.88 +		err = storer.Destroy(context.TODO())
    3.89 +		if err != nil {
    3.90 +			t.Errorf("Error cleaning up after %T: %+v\n", storer, err)
    3.91 +		}
    3.92 +	}
    3.93 +}