From 82e5c11a9deaa105b90fbb99fb92bb54ff1f17d5 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Fri, 21 Jun 2019 16:10:30 +1000 Subject: [PATCH 01/14] Initial implementation of mapstore --- 06_puppy/alfredxiao/main.go | 24 +++++++++++++++ 06_puppy/alfredxiao/main_test.go | 1 + 06_puppy/alfredxiao/mapstore.go | 52 ++++++++++++++++++++++++++++++++ 06_puppy/alfredxiao/types.go | 15 +++++++++ 4 files changed, 92 insertions(+) create mode 100644 06_puppy/alfredxiao/main.go create mode 100644 06_puppy/alfredxiao/main_test.go create mode 100644 06_puppy/alfredxiao/mapstore.go create mode 100644 06_puppy/alfredxiao/types.go diff --git a/06_puppy/alfredxiao/main.go b/06_puppy/alfredxiao/main.go new file mode 100644 index 000000000..b915187ba --- /dev/null +++ b/06_puppy/alfredxiao/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "io" + "os" +) +var out io.Writer = os.Stdout + +func main() { + store1 := NewMapStore() + store1.CreatePuppy(Puppy{ + ID: "1", + Colour: "Red", + }) + + puppy, _ := store1.ReadPuppy("1") + fmt.Fprintln(out, puppy) + + puppy.Colour = "Blue" + store1.UpdatePuppy(puppy) + puppy, _ = store1.ReadPuppy("1") + fmt.Fprintln(out, puppy) +} diff --git a/06_puppy/alfredxiao/main_test.go b/06_puppy/alfredxiao/main_test.go new file mode 100644 index 000000000..06ab7d0f9 --- /dev/null +++ b/06_puppy/alfredxiao/main_test.go @@ -0,0 +1 @@ +package main diff --git a/06_puppy/alfredxiao/mapstore.go b/06_puppy/alfredxiao/mapstore.go new file mode 100644 index 000000000..35c5d8cc8 --- /dev/null +++ b/06_puppy/alfredxiao/mapstore.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" +) + +type MapStore struct { + data map[string]Puppy +} + +func (s *MapStore) CreatePuppy(p Puppy) error { + _, ok := s.data[p.ID] + if ok { + return fmt.Errorf("Puppy with ID[%s] already exists", p.ID) + } + + s.data[p.ID] = p + return nil +} + +func (s *MapStore) ReadPuppy(ID string) (Puppy, error) { + p, ok := s.data[ID] + if !ok { + return Puppy{}, fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) + } + + return p, nil +} + +func (s *MapStore) UpdatePuppy(p Puppy) error { + _, ok := s.data[p.ID] + if !ok { + return fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) + } + s.data[p.ID] = p + return nil +} + +func (s *MapStore) DeletePet(ID string) (bool, error) { + p, ok := s.data[ID] + if !ok { + return false, fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) + } + delete(s.data, ID) + return true, nil +} + +func NewMapStore() *MapStore { + return &MapStore{ + data: make(map[string]Puppy), + } +} diff --git a/06_puppy/alfredxiao/types.go b/06_puppy/alfredxiao/types.go new file mode 100644 index 000000000..7874fc81a --- /dev/null +++ b/06_puppy/alfredxiao/types.go @@ -0,0 +1,15 @@ +package main + +type Puppy struct { + ID string + Breed string + Colour string + Value string +} + +type Storer interface { + CreatePuppy(p Puppy) error + ReadPuppy(ID string) (Puppy, error) + UpdatePuppy(p Puppy) error + DeletePet(ID string) (bool, error) +} From fa5489244c5308cf298016cad5e5072ae56edd42 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Mon, 24 Jun 2019 09:24:26 +1000 Subject: [PATCH 02/14] Add SyncStore implementation --- 06_puppy/alfredxiao/main.go | 2 +- 06_puppy/alfredxiao/syncstore.go | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 06_puppy/alfredxiao/syncstore.go diff --git a/06_puppy/alfredxiao/main.go b/06_puppy/alfredxiao/main.go index b915187ba..811ec9e54 100644 --- a/06_puppy/alfredxiao/main.go +++ b/06_puppy/alfredxiao/main.go @@ -8,7 +8,7 @@ import ( var out io.Writer = os.Stdout func main() { - store1 := NewMapStore() + store1 := NewSyncStore() store1.CreatePuppy(Puppy{ ID: "1", Colour: "Red", diff --git a/06_puppy/alfredxiao/syncstore.go b/06_puppy/alfredxiao/syncstore.go new file mode 100644 index 000000000..168244d1d --- /dev/null +++ b/06_puppy/alfredxiao/syncstore.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "sync" +) + +type SyncStore struct { + data sync.Map +} + +func (s *SyncStore) CreatePuppy(p Puppy) error { + _, ok := s.data.Load(p.ID) + if ok { + return fmt.Errorf("Puppy with ID[%s] already exists", p.ID) + } + + s.data.Store(p.ID, p) + return nil +} + +func (s *SyncStore) ReadPuppy(ID string) (Puppy, error) { + p, ok := s.data.Load(ID) + if !ok { + return Puppy{}, fmt.Errorf("Puppy with ID[%s] does not exists", p.(Puppy).ID) + } + + return p.(Puppy), nil +} + +func (s *SyncStore) UpdatePuppy(p Puppy) error { + _, ok := s.data.Load(p.ID) + if !ok { + return fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) + } + s.data.Store(p.ID, p) + return nil +} + +func (s *SyncStore) DeletePet(ID string) (bool, error) { + p, ok := s.data.Load(ID) + if !ok { + return false, fmt.Errorf("Puppy with ID[%s] does not exists", p.(Puppy).ID) + } + s.data.Delete(ID) + return true, nil +} + +func NewSyncStore() *SyncStore { + return &SyncStore{} +} From 42e6cb5cf25d2236e3fdf310bb43cd3ec9e3fff5 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Mon, 24 Jun 2019 10:25:36 +1000 Subject: [PATCH 03/14] Add test suite to test both mapstore and syncstore, add main_test as well --- 06_puppy/alfredxiao/main.go | 7 +-- 06_puppy/alfredxiao/main_test.go | 15 ++++++ 06_puppy/alfredxiao/mapstore.go | 2 +- 06_puppy/alfredxiao/store_test.go | 81 +++++++++++++++++++++++++++++++ 06_puppy/alfredxiao/syncstore.go | 8 +-- 06_puppy/alfredxiao/types.go | 2 +- 6 files changed, 103 insertions(+), 12 deletions(-) create mode 100644 06_puppy/alfredxiao/store_test.go diff --git a/06_puppy/alfredxiao/main.go b/06_puppy/alfredxiao/main.go index 811ec9e54..8c553cf55 100644 --- a/06_puppy/alfredxiao/main.go +++ b/06_puppy/alfredxiao/main.go @@ -15,10 +15,5 @@ func main() { }) puppy, _ := store1.ReadPuppy("1") - fmt.Fprintln(out, puppy) - - puppy.Colour = "Blue" - store1.UpdatePuppy(puppy) - puppy, _ = store1.ReadPuppy("1") - fmt.Fprintln(out, puppy) + fmt.Fprint(out, puppy.Colour) } diff --git a/06_puppy/alfredxiao/main_test.go b/06_puppy/alfredxiao/main_test.go index 06ab7d0f9..d75105e2d 100644 --- a/06_puppy/alfredxiao/main_test.go +++ b/06_puppy/alfredxiao/main_test.go @@ -1 +1,16 @@ package main + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMainOutput(t *testing.T) { + var buf bytes.Buffer + out = &buf + main() + + assert.Equal(t, "Red", buf.String()) +} diff --git a/06_puppy/alfredxiao/mapstore.go b/06_puppy/alfredxiao/mapstore.go index 35c5d8cc8..b76926710 100644 --- a/06_puppy/alfredxiao/mapstore.go +++ b/06_puppy/alfredxiao/mapstore.go @@ -36,7 +36,7 @@ func (s *MapStore) UpdatePuppy(p Puppy) error { return nil } -func (s *MapStore) DeletePet(ID string) (bool, error) { +func (s *MapStore) DeletePuppy(ID string) (bool, error) { p, ok := s.data[ID] if !ok { return false, fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go new file mode 100644 index 000000000..58c6617b4 --- /dev/null +++ b/06_puppy/alfredxiao/store_test.go @@ -0,0 +1,81 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type storerSuite struct { + suite.Suite + store Storer +} + +func (s *storerSuite) TestCreatePuppyHappyCase() { + t := s.T() + err := s.store.CreatePuppy(Puppy{ID:"1", Colour: "Black"}) + assert.NoError(s.T(), err, "Happy case puppy creation") + + p, _ := s.store.ReadPuppy("1") + assert.Equal(t, "Black", p.Colour) +} + +func (s *storerSuite) TestCreatePuppyAlreadyExists() { + s.store.CreatePuppy(Puppy{ID:"2"}) + err := s.store.CreatePuppy(Puppy{ID:"2", Colour:"Red"}) + assert.Error(s.T(), err, "Puppy creation fails if ID already exists") +} + +func (s *storerSuite) TestReadPuppyHappyCase() { + t := s.T() + s.store.CreatePuppy(Puppy{ID:"3", Colour:"Blue"}) + p, err := s.store.ReadPuppy("3") + require.NoError(t, err) + assert.Equal(t, "Blue", p.Colour) +} + +func (s *storerSuite) TestReadPuppyNonExisting() { + t := s.T() + _, err := s.store.ReadPuppy("4") + assert.Error(t, err) +} + +func (s *storerSuite) TestUpdatePuppyHappyCase() { + t := s.T() + s.store.CreatePuppy(Puppy{ID:"5", Colour:"Brown"}) + err := s.store.UpdatePuppy(Puppy{ID:"5", Colour:"Green"}) + require.NoError(t, err) + p, _ := s.store.ReadPuppy("5") + require.Equal(t, "Green", p.Colour) +} + +func (s *storerSuite) TestUpdatePuppyNonExisting() { + t := s.T() + err := s.store.UpdatePuppy(Puppy{ID:"6"}) + assert.Error(t, err) +} + +func (s *storerSuite) TestDeletePuppyHappyCase() { + t := s.T() + s.store.CreatePuppy(Puppy{ID:"7", Colour:"Brown"}) + deleted, err := s.store.DeletePuppy("7") + require.NoError(t, err) + require.Equal(t, true, deleted) + + _, err = s.store.ReadPuppy("7") + assert.Error(t, err, "Puppy gone after deletion") +} + +func (s *storerSuite) TestDeletePuppyNonExisting() { + t := s.T() + deleted, err := s.store.DeletePuppy("8") + require.Error(t, err) + assert.Equal(t, false, deleted) +} + +func TestRest(t *testing.T) { + suite.Run(t, &storerSuite{store: NewMapStore()}) + suite.Run(t, &storerSuite{store: NewSyncStore()}) +} diff --git a/06_puppy/alfredxiao/syncstore.go b/06_puppy/alfredxiao/syncstore.go index 168244d1d..5fd2f3304 100644 --- a/06_puppy/alfredxiao/syncstore.go +++ b/06_puppy/alfredxiao/syncstore.go @@ -22,7 +22,7 @@ func (s *SyncStore) CreatePuppy(p Puppy) error { func (s *SyncStore) ReadPuppy(ID string) (Puppy, error) { p, ok := s.data.Load(ID) if !ok { - return Puppy{}, fmt.Errorf("Puppy with ID[%s] does not exists", p.(Puppy).ID) + return Puppy{}, fmt.Errorf("Puppy with ID[%s] does not exists", ID) } return p.(Puppy), nil @@ -37,10 +37,10 @@ func (s *SyncStore) UpdatePuppy(p Puppy) error { return nil } -func (s *SyncStore) DeletePet(ID string) (bool, error) { - p, ok := s.data.Load(ID) +func (s *SyncStore) DeletePuppy(ID string) (bool, error) { + _, ok := s.data.Load(ID) if !ok { - return false, fmt.Errorf("Puppy with ID[%s] does not exists", p.(Puppy).ID) + return false, fmt.Errorf("Puppy with ID[%s] does not exists", ID) } s.data.Delete(ID) return true, nil diff --git a/06_puppy/alfredxiao/types.go b/06_puppy/alfredxiao/types.go index 7874fc81a..3816e5263 100644 --- a/06_puppy/alfredxiao/types.go +++ b/06_puppy/alfredxiao/types.go @@ -11,5 +11,5 @@ type Storer interface { CreatePuppy(p Puppy) error ReadPuppy(ID string) (Puppy, error) UpdatePuppy(p Puppy) error - DeletePet(ID string) (bool, error) + DeletePuppy(ID string) (bool, error) } From 9ef3a5a0afed9fd074d74d12f68071b96bc468ac Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Mon, 24 Jun 2019 10:31:00 +1000 Subject: [PATCH 04/14] fix linting issues --- 06_puppy/alfredxiao/main.go | 15 ++++---- 06_puppy/alfredxiao/main_test.go | 8 ++--- 06_puppy/alfredxiao/mapstore.go | 60 +++++++++++++++---------------- 06_puppy/alfredxiao/store_test.go | 20 +++++------ 06_puppy/alfredxiao/syncstore.go | 58 +++++++++++++++--------------- 06_puppy/alfredxiao/types.go | 10 +++--- 6 files changed, 86 insertions(+), 85 deletions(-) diff --git a/06_puppy/alfredxiao/main.go b/06_puppy/alfredxiao/main.go index 8c553cf55..0adee77c3 100644 --- a/06_puppy/alfredxiao/main.go +++ b/06_puppy/alfredxiao/main.go @@ -5,15 +5,16 @@ import ( "io" "os" ) + var out io.Writer = os.Stdout func main() { - store1 := NewSyncStore() - store1.CreatePuppy(Puppy{ - ID: "1", - Colour: "Red", - }) + store1 := NewSyncStore() + _ = store1.CreatePuppy(Puppy{ + ID: "1", + Colour: "Red", + }) - puppy, _ := store1.ReadPuppy("1") - fmt.Fprint(out, puppy.Colour) + puppy, _ := store1.ReadPuppy("1") + fmt.Fprint(out, puppy.Colour) } diff --git a/06_puppy/alfredxiao/main_test.go b/06_puppy/alfredxiao/main_test.go index d75105e2d..aad093632 100644 --- a/06_puppy/alfredxiao/main_test.go +++ b/06_puppy/alfredxiao/main_test.go @@ -1,10 +1,10 @@ package main import ( - "bytes" - "testing" + "bytes" + "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/assert" ) func TestMainOutput(t *testing.T) { @@ -12,5 +12,5 @@ func TestMainOutput(t *testing.T) { out = &buf main() - assert.Equal(t, "Red", buf.String()) + assert.Equal(t, "Red", buf.String()) } diff --git a/06_puppy/alfredxiao/mapstore.go b/06_puppy/alfredxiao/mapstore.go index b76926710..594620eb6 100644 --- a/06_puppy/alfredxiao/mapstore.go +++ b/06_puppy/alfredxiao/mapstore.go @@ -1,52 +1,52 @@ package main import ( - "fmt" + "fmt" ) type MapStore struct { - data map[string]Puppy + data map[string]Puppy } func (s *MapStore) CreatePuppy(p Puppy) error { - _, ok := s.data[p.ID] - if ok { - return fmt.Errorf("Puppy with ID[%s] already exists", p.ID) - } + _, ok := s.data[p.ID] + if ok { + return fmt.Errorf("puppy with ID[%s] already exists", p.ID) + } - s.data[p.ID] = p - return nil + s.data[p.ID] = p + return nil } -func (s *MapStore) ReadPuppy(ID string) (Puppy, error) { - p, ok := s.data[ID] - if !ok { - return Puppy{}, fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) - } +func (s *MapStore) ReadPuppy(id string) (Puppy, error) { + p, ok := s.data[id] + if !ok { + return Puppy{}, fmt.Errorf("puppy with ID[%s] does not exists", p.ID) + } - return p, nil + return p, nil } func (s *MapStore) UpdatePuppy(p Puppy) error { - _, ok := s.data[p.ID] - if !ok { - return fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) - } - s.data[p.ID] = p - return nil + _, ok := s.data[p.ID] + if !ok { + return fmt.Errorf("puppy with ID[%s] does not exists", p.ID) + } + s.data[p.ID] = p + return nil } -func (s *MapStore) DeletePuppy(ID string) (bool, error) { - p, ok := s.data[ID] - if !ok { - return false, fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) - } - delete(s.data, ID) - return true, nil +func (s *MapStore) DeletePuppy(id string) (bool, error) { + p, ok := s.data[id] + if !ok { + return false, fmt.Errorf("puppy with ID[%s] does not exists", p.ID) + } + delete(s.data, id) + return true, nil } func NewMapStore() *MapStore { - return &MapStore{ - data: make(map[string]Puppy), - } + return &MapStore{ + data: make(map[string]Puppy), + } } diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index 58c6617b4..d9ebadf17 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -15,7 +15,7 @@ type storerSuite struct { func (s *storerSuite) TestCreatePuppyHappyCase() { t := s.T() - err := s.store.CreatePuppy(Puppy{ID:"1", Colour: "Black"}) + err := s.store.CreatePuppy(Puppy{ID: "1", Colour: "Black"}) assert.NoError(s.T(), err, "Happy case puppy creation") p, _ := s.store.ReadPuppy("1") @@ -23,14 +23,14 @@ func (s *storerSuite) TestCreatePuppyHappyCase() { } func (s *storerSuite) TestCreatePuppyAlreadyExists() { - s.store.CreatePuppy(Puppy{ID:"2"}) - err := s.store.CreatePuppy(Puppy{ID:"2", Colour:"Red"}) + _ = s.store.CreatePuppy(Puppy{ID: "2"}) + err := s.store.CreatePuppy(Puppy{ID: "2", Colour: "Red"}) assert.Error(s.T(), err, "Puppy creation fails if ID already exists") } func (s *storerSuite) TestReadPuppyHappyCase() { t := s.T() - s.store.CreatePuppy(Puppy{ID:"3", Colour:"Blue"}) + _ = s.store.CreatePuppy(Puppy{ID: "3", Colour: "Blue"}) p, err := s.store.ReadPuppy("3") require.NoError(t, err) assert.Equal(t, "Blue", p.Colour) @@ -44,8 +44,8 @@ func (s *storerSuite) TestReadPuppyNonExisting() { func (s *storerSuite) TestUpdatePuppyHappyCase() { t := s.T() - s.store.CreatePuppy(Puppy{ID:"5", Colour:"Brown"}) - err := s.store.UpdatePuppy(Puppy{ID:"5", Colour:"Green"}) + _ = s.store.CreatePuppy(Puppy{ID: "5", Colour: "Brown"}) + err := s.store.UpdatePuppy(Puppy{ID: "5", Colour: "Green"}) require.NoError(t, err) p, _ := s.store.ReadPuppy("5") require.Equal(t, "Green", p.Colour) @@ -53,13 +53,13 @@ func (s *storerSuite) TestUpdatePuppyHappyCase() { func (s *storerSuite) TestUpdatePuppyNonExisting() { t := s.T() - err := s.store.UpdatePuppy(Puppy{ID:"6"}) + err := s.store.UpdatePuppy(Puppy{ID: "6"}) assert.Error(t, err) } func (s *storerSuite) TestDeletePuppyHappyCase() { t := s.T() - s.store.CreatePuppy(Puppy{ID:"7", Colour:"Brown"}) + _ = s.store.CreatePuppy(Puppy{ID: "7", Colour: "Brown"}) deleted, err := s.store.DeletePuppy("7") require.NoError(t, err) require.Equal(t, true, deleted) @@ -76,6 +76,6 @@ func (s *storerSuite) TestDeletePuppyNonExisting() { } func TestRest(t *testing.T) { - suite.Run(t, &storerSuite{store: NewMapStore()}) - suite.Run(t, &storerSuite{store: NewSyncStore()}) + suite.Run(t, &storerSuite{store: NewMapStore()}) + suite.Run(t, &storerSuite{store: NewSyncStore()}) } diff --git a/06_puppy/alfredxiao/syncstore.go b/06_puppy/alfredxiao/syncstore.go index 5fd2f3304..8ed52b936 100644 --- a/06_puppy/alfredxiao/syncstore.go +++ b/06_puppy/alfredxiao/syncstore.go @@ -1,51 +1,51 @@ package main import ( - "fmt" - "sync" + "fmt" + "sync" ) type SyncStore struct { - data sync.Map + data sync.Map } func (s *SyncStore) CreatePuppy(p Puppy) error { - _, ok := s.data.Load(p.ID) - if ok { - return fmt.Errorf("Puppy with ID[%s] already exists", p.ID) - } + _, ok := s.data.Load(p.ID) + if ok { + return fmt.Errorf("puppy with ID[%s] already exists", p.ID) + } - s.data.Store(p.ID, p) - return nil + s.data.Store(p.ID, p) + return nil } -func (s *SyncStore) ReadPuppy(ID string) (Puppy, error) { - p, ok := s.data.Load(ID) - if !ok { - return Puppy{}, fmt.Errorf("Puppy with ID[%s] does not exists", ID) - } +func (s *SyncStore) ReadPuppy(id string) (Puppy, error) { + p, ok := s.data.Load(id) + if !ok { + return Puppy{}, fmt.Errorf("puppy with ID[%s] does not exists", id) + } - return p.(Puppy), nil + return p.(Puppy), nil } func (s *SyncStore) UpdatePuppy(p Puppy) error { - _, ok := s.data.Load(p.ID) - if !ok { - return fmt.Errorf("Puppy with ID[%s] does not exists", p.ID) - } - s.data.Store(p.ID, p) - return nil + _, ok := s.data.Load(p.ID) + if !ok { + return fmt.Errorf("puppy with ID[%s] does not exists", p.ID) + } + s.data.Store(p.ID, p) + return nil } -func (s *SyncStore) DeletePuppy(ID string) (bool, error) { - _, ok := s.data.Load(ID) - if !ok { - return false, fmt.Errorf("Puppy with ID[%s] does not exists", ID) - } - s.data.Delete(ID) - return true, nil +func (s *SyncStore) DeletePuppy(id string) (bool, error) { + _, ok := s.data.Load(id) + if !ok { + return false, fmt.Errorf("puppy with ID[%s] does not exists", id) + } + s.data.Delete(id) + return true, nil } func NewSyncStore() *SyncStore { - return &SyncStore{} + return &SyncStore{} } diff --git a/06_puppy/alfredxiao/types.go b/06_puppy/alfredxiao/types.go index 3816e5263..2b5736bb3 100644 --- a/06_puppy/alfredxiao/types.go +++ b/06_puppy/alfredxiao/types.go @@ -1,14 +1,14 @@ package main type Puppy struct { - ID string - Breed string - Colour string - Value string + ID string + Breed string + Colour string + Value string } type Storer interface { - CreatePuppy(p Puppy) error + CreatePuppy(p Puppy) error ReadPuppy(ID string) (Puppy, error) UpdatePuppy(p Puppy) error DeletePuppy(ID string) (bool, error) From 1829fe3821fa8039d335285a8130135d9a4eb1cc Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Mon, 24 Jun 2019 22:55:59 +1000 Subject: [PATCH 05/14] Refactor type names to improve encapsulation --- 06_puppy/alfredxiao/mapstore.go | 14 +++++++------- 06_puppy/alfredxiao/syncstore.go | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/06_puppy/alfredxiao/mapstore.go b/06_puppy/alfredxiao/mapstore.go index 594620eb6..e7b63f03b 100644 --- a/06_puppy/alfredxiao/mapstore.go +++ b/06_puppy/alfredxiao/mapstore.go @@ -4,11 +4,11 @@ import ( "fmt" ) -type MapStore struct { +type mapStore struct { data map[string]Puppy } -func (s *MapStore) CreatePuppy(p Puppy) error { +func (s *mapStore) CreatePuppy(p Puppy) error { _, ok := s.data[p.ID] if ok { return fmt.Errorf("puppy with ID[%s] already exists", p.ID) @@ -18,7 +18,7 @@ func (s *MapStore) CreatePuppy(p Puppy) error { return nil } -func (s *MapStore) ReadPuppy(id string) (Puppy, error) { +func (s *mapStore) ReadPuppy(id string) (Puppy, error) { p, ok := s.data[id] if !ok { return Puppy{}, fmt.Errorf("puppy with ID[%s] does not exists", p.ID) @@ -27,7 +27,7 @@ func (s *MapStore) ReadPuppy(id string) (Puppy, error) { return p, nil } -func (s *MapStore) UpdatePuppy(p Puppy) error { +func (s *mapStore) UpdatePuppy(p Puppy) error { _, ok := s.data[p.ID] if !ok { return fmt.Errorf("puppy with ID[%s] does not exists", p.ID) @@ -36,7 +36,7 @@ func (s *MapStore) UpdatePuppy(p Puppy) error { return nil } -func (s *MapStore) DeletePuppy(id string) (bool, error) { +func (s *mapStore) DeletePuppy(id string) (bool, error) { p, ok := s.data[id] if !ok { return false, fmt.Errorf("puppy with ID[%s] does not exists", p.ID) @@ -45,8 +45,8 @@ func (s *MapStore) DeletePuppy(id string) (bool, error) { return true, nil } -func NewMapStore() *MapStore { - return &MapStore{ +func NewMapStore() Storer { + return &mapStore{ data: make(map[string]Puppy), } } diff --git a/06_puppy/alfredxiao/syncstore.go b/06_puppy/alfredxiao/syncstore.go index 8ed52b936..9ff70cc51 100644 --- a/06_puppy/alfredxiao/syncstore.go +++ b/06_puppy/alfredxiao/syncstore.go @@ -5,11 +5,11 @@ import ( "sync" ) -type SyncStore struct { +type syncStore struct { data sync.Map } -func (s *SyncStore) CreatePuppy(p Puppy) error { +func (s *syncStore) CreatePuppy(p Puppy) error { _, ok := s.data.Load(p.ID) if ok { return fmt.Errorf("puppy with ID[%s] already exists", p.ID) @@ -19,7 +19,7 @@ func (s *SyncStore) CreatePuppy(p Puppy) error { return nil } -func (s *SyncStore) ReadPuppy(id string) (Puppy, error) { +func (s *syncStore) ReadPuppy(id string) (Puppy, error) { p, ok := s.data.Load(id) if !ok { return Puppy{}, fmt.Errorf("puppy with ID[%s] does not exists", id) @@ -28,7 +28,7 @@ func (s *SyncStore) ReadPuppy(id string) (Puppy, error) { return p.(Puppy), nil } -func (s *SyncStore) UpdatePuppy(p Puppy) error { +func (s *syncStore) UpdatePuppy(p Puppy) error { _, ok := s.data.Load(p.ID) if !ok { return fmt.Errorf("puppy with ID[%s] does not exists", p.ID) @@ -37,7 +37,7 @@ func (s *SyncStore) UpdatePuppy(p Puppy) error { return nil } -func (s *SyncStore) DeletePuppy(id string) (bool, error) { +func (s *syncStore) DeletePuppy(id string) (bool, error) { _, ok := s.data.Load(id) if !ok { return false, fmt.Errorf("puppy with ID[%s] does not exists", id) @@ -46,6 +46,6 @@ func (s *SyncStore) DeletePuppy(id string) (bool, error) { return true, nil } -func NewSyncStore() *SyncStore { - return &SyncStore{} +func NewSyncStore() Storer { + return &syncStore{} } From c1eb57daa20fa9b4466c73b9275dd9ef25665102 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Tue, 25 Jun 2019 12:21:21 +1000 Subject: [PATCH 06/14] Fix copied typo in test function name --- 06_puppy/alfredxiao/store_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index d9ebadf17..eb86d23d7 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -75,7 +75,7 @@ func (s *storerSuite) TestDeletePuppyNonExisting() { assert.Equal(t, false, deleted) } -func TestRest(t *testing.T) { +func TestStorers(t *testing.T) { suite.Run(t, &storerSuite{store: NewMapStore()}) suite.Run(t, &storerSuite{store: NewSyncStore()}) } From bfcdac1f0f3f3fd626243c4b2194a82ed852f42e Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Tue, 25 Jun 2019 13:42:53 +1000 Subject: [PATCH 07/14] Remove the need to use assert package as suite can make assertions --- 06_puppy/alfredxiao/store_test.go | 36 ++++++++++++------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index eb86d23d7..c1ca0b810 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -3,7 +3,6 @@ package main import ( "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -14,65 +13,58 @@ type storerSuite struct { } func (s *storerSuite) TestCreatePuppyHappyCase() { - t := s.T() err := s.store.CreatePuppy(Puppy{ID: "1", Colour: "Black"}) - assert.NoError(s.T(), err, "Happy case puppy creation") + s.NoError(err, "Happy case puppy creation") p, _ := s.store.ReadPuppy("1") - assert.Equal(t, "Black", p.Colour) + s.Equal("Black", p.Colour) } func (s *storerSuite) TestCreatePuppyAlreadyExists() { _ = s.store.CreatePuppy(Puppy{ID: "2"}) err := s.store.CreatePuppy(Puppy{ID: "2", Colour: "Red"}) - assert.Error(s.T(), err, "Puppy creation fails if ID already exists") + s.Error(err, "Puppy creation fails if ID already exists") } func (s *storerSuite) TestReadPuppyHappyCase() { - t := s.T() _ = s.store.CreatePuppy(Puppy{ID: "3", Colour: "Blue"}) p, err := s.store.ReadPuppy("3") - require.NoError(t, err) - assert.Equal(t, "Blue", p.Colour) + require.NoError(s.T(), err) + s.Equal("Blue", p.Colour) } func (s *storerSuite) TestReadPuppyNonExisting() { - t := s.T() _, err := s.store.ReadPuppy("4") - assert.Error(t, err) + s.Error(err) } func (s *storerSuite) TestUpdatePuppyHappyCase() { - t := s.T() _ = s.store.CreatePuppy(Puppy{ID: "5", Colour: "Brown"}) err := s.store.UpdatePuppy(Puppy{ID: "5", Colour: "Green"}) - require.NoError(t, err) + require.NoError(s.T(), err) p, _ := s.store.ReadPuppy("5") - require.Equal(t, "Green", p.Colour) + s.Equal("Green", p.Colour) } func (s *storerSuite) TestUpdatePuppyNonExisting() { - t := s.T() err := s.store.UpdatePuppy(Puppy{ID: "6"}) - assert.Error(t, err) + s.Error(err) } func (s *storerSuite) TestDeletePuppyHappyCase() { - t := s.T() _ = s.store.CreatePuppy(Puppy{ID: "7", Colour: "Brown"}) deleted, err := s.store.DeletePuppy("7") - require.NoError(t, err) - require.Equal(t, true, deleted) + require.NoError(s.T(), err) + require.Equal(s.T(), true, deleted) _, err = s.store.ReadPuppy("7") - assert.Error(t, err, "Puppy gone after deletion") + s.Error(err, "Puppy gone after deletion") } func (s *storerSuite) TestDeletePuppyNonExisting() { - t := s.T() deleted, err := s.store.DeletePuppy("8") - require.Error(t, err) - assert.Equal(t, false, deleted) + require.Error(s.T(), err) + s.Equal(false, deleted) } func TestStorers(t *testing.T) { From 76cd4361f660b7114186637641e45e7283ca0cf6 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Tue, 25 Jun 2019 14:14:02 +1000 Subject: [PATCH 08/14] Refactor such that each test uses a new instance of storer --- 06_puppy/alfredxiao/store_test.go | 48 +++++++++++++++++++------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index c1ca0b810..cc377b241 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -9,65 +9,77 @@ import ( type storerSuite struct { suite.Suite - store Storer + storeFactory func() Storer } func (s *storerSuite) TestCreatePuppyHappyCase() { - err := s.store.CreatePuppy(Puppy{ID: "1", Colour: "Black"}) + store := s.storeFactory() + err := store.CreatePuppy(Puppy{ID: "1", Colour: "Black"}) s.NoError(err, "Happy case puppy creation") - p, _ := s.store.ReadPuppy("1") + p, _ := store.ReadPuppy("1") s.Equal("Black", p.Colour) } func (s *storerSuite) TestCreatePuppyAlreadyExists() { - _ = s.store.CreatePuppy(Puppy{ID: "2"}) - err := s.store.CreatePuppy(Puppy{ID: "2", Colour: "Red"}) + store := s.storeFactory() + _ = store.CreatePuppy(Puppy{ID: "2"}) + err := store.CreatePuppy(Puppy{ID: "2", Colour: "Red"}) s.Error(err, "Puppy creation fails if ID already exists") } func (s *storerSuite) TestReadPuppyHappyCase() { - _ = s.store.CreatePuppy(Puppy{ID: "3", Colour: "Blue"}) - p, err := s.store.ReadPuppy("3") + store := s.storeFactory() + _ = store.CreatePuppy(Puppy{ID: "3", Colour: "Blue"}) + p, err := store.ReadPuppy("3") require.NoError(s.T(), err) s.Equal("Blue", p.Colour) } func (s *storerSuite) TestReadPuppyNonExisting() { - _, err := s.store.ReadPuppy("4") + store := s.storeFactory() + _, err := store.ReadPuppy("4") s.Error(err) } func (s *storerSuite) TestUpdatePuppyHappyCase() { - _ = s.store.CreatePuppy(Puppy{ID: "5", Colour: "Brown"}) - err := s.store.UpdatePuppy(Puppy{ID: "5", Colour: "Green"}) + store := s.storeFactory() + _ = store.CreatePuppy(Puppy{ID: "5", Colour: "Brown"}) + err := store.UpdatePuppy(Puppy{ID: "5", Colour: "Green"}) require.NoError(s.T(), err) - p, _ := s.store.ReadPuppy("5") + p, _ := store.ReadPuppy("5") s.Equal("Green", p.Colour) } func (s *storerSuite) TestUpdatePuppyNonExisting() { - err := s.store.UpdatePuppy(Puppy{ID: "6"}) + store := s.storeFactory() + err := store.UpdatePuppy(Puppy{ID: "6"}) s.Error(err) } func (s *storerSuite) TestDeletePuppyHappyCase() { - _ = s.store.CreatePuppy(Puppy{ID: "7", Colour: "Brown"}) - deleted, err := s.store.DeletePuppy("7") + store := s.storeFactory() + _ = store.CreatePuppy(Puppy{ID: "7", Colour: "Brown"}) + deleted, err := store.DeletePuppy("7") require.NoError(s.T(), err) require.Equal(s.T(), true, deleted) - _, err = s.store.ReadPuppy("7") + _, err = store.ReadPuppy("7") s.Error(err, "Puppy gone after deletion") } func (s *storerSuite) TestDeletePuppyNonExisting() { - deleted, err := s.store.DeletePuppy("8") + store := s.storeFactory() + deleted, err := store.DeletePuppy("8") require.Error(s.T(), err) s.Equal(false, deleted) } func TestStorers(t *testing.T) { - suite.Run(t, &storerSuite{store: NewMapStore()}) - suite.Run(t, &storerSuite{store: NewSyncStore()}) + suite.Run(t, &storerSuite{ + storeFactory: NewMapStore, + }) + suite.Run(t, &storerSuite{ + storeFactory: NewSyncStore, + }) } From bb5ec4c52bab8349e37bffa7159e5797871e2858 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Tue, 25 Jun 2019 14:46:49 +1000 Subject: [PATCH 09/14] Use SetupTest to setup storer per tests --- 06_puppy/alfredxiao/store_test.go | 43 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index cc377b241..b68af646b 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -9,68 +9,65 @@ import ( type storerSuite struct { suite.Suite + store Storer storeFactory func() Storer } +func (s *storerSuite) SetupTest() { + s.store = s.storeFactory() +} + func (s *storerSuite) TestCreatePuppyHappyCase() { - store := s.storeFactory() - err := store.CreatePuppy(Puppy{ID: "1", Colour: "Black"}) + err := s.store.CreatePuppy(Puppy{ID: "1", Colour: "Black"}) s.NoError(err, "Happy case puppy creation") - p, _ := store.ReadPuppy("1") + p, _ := s.store.ReadPuppy("1") s.Equal("Black", p.Colour) } func (s *storerSuite) TestCreatePuppyAlreadyExists() { - store := s.storeFactory() - _ = store.CreatePuppy(Puppy{ID: "2"}) - err := store.CreatePuppy(Puppy{ID: "2", Colour: "Red"}) + _ = s.store.CreatePuppy(Puppy{ID: "2"}) + err := s.store.CreatePuppy(Puppy{ID: "2", Colour: "Red"}) s.Error(err, "Puppy creation fails if ID already exists") } func (s *storerSuite) TestReadPuppyHappyCase() { - store := s.storeFactory() - _ = store.CreatePuppy(Puppy{ID: "3", Colour: "Blue"}) - p, err := store.ReadPuppy("3") + _ = s.store.CreatePuppy(Puppy{ID: "3", Colour: "Blue"}) + p, err := s.store.ReadPuppy("3") require.NoError(s.T(), err) s.Equal("Blue", p.Colour) } func (s *storerSuite) TestReadPuppyNonExisting() { - store := s.storeFactory() - _, err := store.ReadPuppy("4") + _, err := s.store.ReadPuppy("4") s.Error(err) } func (s *storerSuite) TestUpdatePuppyHappyCase() { - store := s.storeFactory() - _ = store.CreatePuppy(Puppy{ID: "5", Colour: "Brown"}) - err := store.UpdatePuppy(Puppy{ID: "5", Colour: "Green"}) + _ = s.store.CreatePuppy(Puppy{ID: "5", Colour: "Brown"}) + err := s.store.UpdatePuppy(Puppy{ID: "5", Colour: "Green"}) require.NoError(s.T(), err) - p, _ := store.ReadPuppy("5") + p, _ := s.store.ReadPuppy("5") s.Equal("Green", p.Colour) } func (s *storerSuite) TestUpdatePuppyNonExisting() { - store := s.storeFactory() - err := store.UpdatePuppy(Puppy{ID: "6"}) + err := s.store.UpdatePuppy(Puppy{ID: "6"}) s.Error(err) } func (s *storerSuite) TestDeletePuppyHappyCase() { - store := s.storeFactory() - _ = store.CreatePuppy(Puppy{ID: "7", Colour: "Brown"}) - deleted, err := store.DeletePuppy("7") + _ = s.store.CreatePuppy(Puppy{ID: "7", Colour: "Brown"}) + deleted, err := s.store.DeletePuppy("7") require.NoError(s.T(), err) require.Equal(s.T(), true, deleted) - _, err = store.ReadPuppy("7") + _, err = s.store.ReadPuppy("7") s.Error(err, "Puppy gone after deletion") } func (s *storerSuite) TestDeletePuppyNonExisting() { - store := s.storeFactory() - deleted, err := store.DeletePuppy("8") + deleted, err := s.store.DeletePuppy("8") require.Error(s.T(), err) s.Equal(false, deleted) } From 6607e90613abc54fb83580898d8e42ede6d6c316 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Thu, 27 Jun 2019 10:31:44 +1000 Subject: [PATCH 10/14] Rename var to avoid confusion --- 06_puppy/alfredxiao/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/06_puppy/alfredxiao/main.go b/06_puppy/alfredxiao/main.go index 0adee77c3..cb3e2d31a 100644 --- a/06_puppy/alfredxiao/main.go +++ b/06_puppy/alfredxiao/main.go @@ -9,12 +9,12 @@ import ( var out io.Writer = os.Stdout func main() { - store1 := NewSyncStore() - _ = store1.CreatePuppy(Puppy{ + store := NewSyncStore() + _ = store.CreatePuppy(Puppy{ ID: "1", Colour: "Red", }) - puppy, _ := store1.ReadPuppy("1") + puppy, _ := store.ReadPuppy("1") fmt.Fprint(out, puppy.Colour) } From ad2b28fd4ceceea17e3b19dd6704f01cca297cd9 Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Thu, 27 Jun 2019 11:09:52 +1000 Subject: [PATCH 11/14] Refactor creation logic to provision id using UUID and return newly created id --- 06_puppy/alfredxiao/main.go | 7 ++--- 06_puppy/alfredxiao/mapstore.go | 14 ++++----- 06_puppy/alfredxiao/store_test.go | 51 ++++++++++++++----------------- 06_puppy/alfredxiao/syncstore.go | 14 ++++----- 06_puppy/alfredxiao/types.go | 2 +- 5 files changed, 41 insertions(+), 47 deletions(-) diff --git a/06_puppy/alfredxiao/main.go b/06_puppy/alfredxiao/main.go index cb3e2d31a..13cd90a00 100644 --- a/06_puppy/alfredxiao/main.go +++ b/06_puppy/alfredxiao/main.go @@ -9,12 +9,11 @@ import ( var out io.Writer = os.Stdout func main() { - store := NewSyncStore() - _ = store.CreatePuppy(Puppy{ - ID: "1", + store := NewMapStore() + id := store.CreatePuppy(Puppy{ Colour: "Red", }) - puppy, _ := store.ReadPuppy("1") + puppy, _ := store.ReadPuppy(id) fmt.Fprint(out, puppy.Colour) } diff --git a/06_puppy/alfredxiao/mapstore.go b/06_puppy/alfredxiao/mapstore.go index e7b63f03b..396a16efb 100644 --- a/06_puppy/alfredxiao/mapstore.go +++ b/06_puppy/alfredxiao/mapstore.go @@ -2,20 +2,20 @@ package main import ( "fmt" + + "github.com/google/uuid" ) type mapStore struct { data map[string]Puppy } -func (s *mapStore) CreatePuppy(p Puppy) error { - _, ok := s.data[p.ID] - if ok { - return fmt.Errorf("puppy with ID[%s] already exists", p.ID) - } +func (s *mapStore) CreatePuppy(p Puppy) string { + id := uuid.New().String() - s.data[p.ID] = p - return nil + p.ID = id + s.data[id] = p + return id } func (s *mapStore) ReadPuppy(id string) (Puppy, error) { diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index b68af646b..64a20495f 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -3,7 +3,6 @@ package main import ( "testing" - "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -18,57 +17,53 @@ func (s *storerSuite) SetupTest() { } func (s *storerSuite) TestCreatePuppyHappyCase() { - err := s.store.CreatePuppy(Puppy{ID: "1", Colour: "Black"}) - s.NoError(err, "Happy case puppy creation") + puppy := Puppy{Colour: "Black"} + id := s.store.CreatePuppy(puppy) + puppyRead, err := s.store.ReadPuppy(id) + s.Require().NoError(err) - p, _ := s.store.ReadPuppy("1") - s.Equal("Black", p.Colour) -} - -func (s *storerSuite) TestCreatePuppyAlreadyExists() { - _ = s.store.CreatePuppy(Puppy{ID: "2"}) - err := s.store.CreatePuppy(Puppy{ID: "2", Colour: "Red"}) - s.Error(err, "Puppy creation fails if ID already exists") + puppy.ID = id + s.Equal(puppy, puppyRead) } func (s *storerSuite) TestReadPuppyHappyCase() { - _ = s.store.CreatePuppy(Puppy{ID: "3", Colour: "Blue"}) - p, err := s.store.ReadPuppy("3") - require.NoError(s.T(), err) + id := s.store.CreatePuppy(Puppy{Colour: "Blue"}) + p, err := s.store.ReadPuppy(id) + s.Require().NoError(err) s.Equal("Blue", p.Colour) } func (s *storerSuite) TestReadPuppyNonExisting() { - _, err := s.store.ReadPuppy("4") + _, err := s.store.ReadPuppy("id_that_does_not_exist") s.Error(err) } func (s *storerSuite) TestUpdatePuppyHappyCase() { - _ = s.store.CreatePuppy(Puppy{ID: "5", Colour: "Brown"}) - err := s.store.UpdatePuppy(Puppy{ID: "5", Colour: "Green"}) - require.NoError(s.T(), err) - p, _ := s.store.ReadPuppy("5") + id := s.store.CreatePuppy(Puppy{Colour: "Brown"}) + err := s.store.UpdatePuppy(Puppy{ID: id, Colour: "Green"}) + s.Require().NoError(err) + p, _ := s.store.ReadPuppy(id) s.Equal("Green", p.Colour) } func (s *storerSuite) TestUpdatePuppyNonExisting() { - err := s.store.UpdatePuppy(Puppy{ID: "6"}) + err := s.store.UpdatePuppy(Puppy{ID: "id_that_does_not_exist_either"}) s.Error(err) } func (s *storerSuite) TestDeletePuppyHappyCase() { - _ = s.store.CreatePuppy(Puppy{ID: "7", Colour: "Brown"}) - deleted, err := s.store.DeletePuppy("7") - require.NoError(s.T(), err) - require.Equal(s.T(), true, deleted) + id := s.store.CreatePuppy(Puppy{Colour: "Brown"}) + deleted, err := s.store.DeletePuppy(id) + s.Require().NoError(err) + s.Require().Equal(true, deleted) - _, err = s.store.ReadPuppy("7") - s.Error(err, "Puppy gone after deletion") + _, err = s.store.ReadPuppy(id) + s.Error(err, "Puppy should be gone after deletion") } func (s *storerSuite) TestDeletePuppyNonExisting() { - deleted, err := s.store.DeletePuppy("8") - require.Error(s.T(), err) + deleted, err := s.store.DeletePuppy("id_that_does_not_exist_again") + s.Require().Error(err) s.Equal(false, deleted) } diff --git a/06_puppy/alfredxiao/syncstore.go b/06_puppy/alfredxiao/syncstore.go index 9ff70cc51..5f4bea113 100644 --- a/06_puppy/alfredxiao/syncstore.go +++ b/06_puppy/alfredxiao/syncstore.go @@ -3,20 +3,20 @@ package main import ( "fmt" "sync" + + "github.com/google/uuid" ) type syncStore struct { data sync.Map } -func (s *syncStore) CreatePuppy(p Puppy) error { - _, ok := s.data.Load(p.ID) - if ok { - return fmt.Errorf("puppy with ID[%s] already exists", p.ID) - } +func (s *syncStore) CreatePuppy(p Puppy) string { + id := uuid.New().String() - s.data.Store(p.ID, p) - return nil + p.ID = id + s.data.Store(id, p) + return id } func (s *syncStore) ReadPuppy(id string) (Puppy, error) { diff --git a/06_puppy/alfredxiao/types.go b/06_puppy/alfredxiao/types.go index 2b5736bb3..c75850bda 100644 --- a/06_puppy/alfredxiao/types.go +++ b/06_puppy/alfredxiao/types.go @@ -8,7 +8,7 @@ type Puppy struct { } type Storer interface { - CreatePuppy(p Puppy) error + CreatePuppy(p Puppy) string ReadPuppy(ID string) (Puppy, error) UpdatePuppy(p Puppy) error DeletePuppy(ID string) (bool, error) From 1e32c65ba58947a29fa8e966e607585e9ee16ecb Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Thu, 27 Jun 2019 11:12:21 +1000 Subject: [PATCH 12/14] Simplify deletion API to return only error to indicate success or faiulure --- 06_puppy/alfredxiao/mapstore.go | 6 +++--- 06_puppy/alfredxiao/store_test.go | 6 ++---- 06_puppy/alfredxiao/syncstore.go | 6 +++--- 06_puppy/alfredxiao/types.go | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/06_puppy/alfredxiao/mapstore.go b/06_puppy/alfredxiao/mapstore.go index 396a16efb..a96e0b18f 100644 --- a/06_puppy/alfredxiao/mapstore.go +++ b/06_puppy/alfredxiao/mapstore.go @@ -36,13 +36,13 @@ func (s *mapStore) UpdatePuppy(p Puppy) error { return nil } -func (s *mapStore) DeletePuppy(id string) (bool, error) { +func (s *mapStore) DeletePuppy(id string) error { p, ok := s.data[id] if !ok { - return false, fmt.Errorf("puppy with ID[%s] does not exists", p.ID) + return fmt.Errorf("puppy with ID[%s] does not exists", p.ID) } delete(s.data, id) - return true, nil + return nil } func NewMapStore() Storer { diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index 64a20495f..2b49e83d6 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -53,18 +53,16 @@ func (s *storerSuite) TestUpdatePuppyNonExisting() { func (s *storerSuite) TestDeletePuppyHappyCase() { id := s.store.CreatePuppy(Puppy{Colour: "Brown"}) - deleted, err := s.store.DeletePuppy(id) + err := s.store.DeletePuppy(id) s.Require().NoError(err) - s.Require().Equal(true, deleted) _, err = s.store.ReadPuppy(id) s.Error(err, "Puppy should be gone after deletion") } func (s *storerSuite) TestDeletePuppyNonExisting() { - deleted, err := s.store.DeletePuppy("id_that_does_not_exist_again") + err := s.store.DeletePuppy("id_that_does_not_exist_again") s.Require().Error(err) - s.Equal(false, deleted) } func TestStorers(t *testing.T) { diff --git a/06_puppy/alfredxiao/syncstore.go b/06_puppy/alfredxiao/syncstore.go index 5f4bea113..f6b81bad0 100644 --- a/06_puppy/alfredxiao/syncstore.go +++ b/06_puppy/alfredxiao/syncstore.go @@ -37,13 +37,13 @@ func (s *syncStore) UpdatePuppy(p Puppy) error { return nil } -func (s *syncStore) DeletePuppy(id string) (bool, error) { +func (s *syncStore) DeletePuppy(id string) error { _, ok := s.data.Load(id) if !ok { - return false, fmt.Errorf("puppy with ID[%s] does not exists", id) + return fmt.Errorf("puppy with ID[%s] does not exists", id) } s.data.Delete(id) - return true, nil + return nil } func NewSyncStore() Storer { diff --git a/06_puppy/alfredxiao/types.go b/06_puppy/alfredxiao/types.go index c75850bda..72308365f 100644 --- a/06_puppy/alfredxiao/types.go +++ b/06_puppy/alfredxiao/types.go @@ -11,5 +11,5 @@ type Storer interface { CreatePuppy(p Puppy) string ReadPuppy(ID string) (Puppy, error) UpdatePuppy(p Puppy) error - DeletePuppy(ID string) (bool, error) + DeletePuppy(ID string) error } From fd409e1e05e4a7de601564e9dcc77974639d874c Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Thu, 27 Jun 2019 11:14:23 +1000 Subject: [PATCH 13/14] Assert against all error vars rather than swallowing them --- 06_puppy/alfredxiao/store_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index 2b49e83d6..0bffb942f 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -42,7 +42,8 @@ func (s *storerSuite) TestUpdatePuppyHappyCase() { id := s.store.CreatePuppy(Puppy{Colour: "Brown"}) err := s.store.UpdatePuppy(Puppy{ID: id, Colour: "Green"}) s.Require().NoError(err) - p, _ := s.store.ReadPuppy(id) + p, err := s.store.ReadPuppy(id) + s.Require().NoError(err) s.Equal("Green", p.Colour) } From 3ebc43c1557cfd9efd331d15f7a48dc8e97f90cd Mon Sep 17 00:00:00 2001 From: Alfred Xiao Date: Thu, 27 Jun 2019 11:33:45 +1000 Subject: [PATCH 14/14] Refactor updation such that it accepts a separate ID arg --- 06_puppy/alfredxiao/mapstore.go | 12 +++++++++--- 06_puppy/alfredxiao/store_test.go | 10 ++++++++-- 06_puppy/alfredxiao/syncstore.go | 12 +++++++++--- 06_puppy/alfredxiao/types.go | 2 +- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/06_puppy/alfredxiao/mapstore.go b/06_puppy/alfredxiao/mapstore.go index a96e0b18f..555a7adea 100644 --- a/06_puppy/alfredxiao/mapstore.go +++ b/06_puppy/alfredxiao/mapstore.go @@ -27,12 +27,18 @@ func (s *mapStore) ReadPuppy(id string) (Puppy, error) { return p, nil } -func (s *mapStore) UpdatePuppy(p Puppy) error { - _, ok := s.data[p.ID] +func (s *mapStore) UpdatePuppy(id string, p Puppy) error { + if id != p.ID { + return fmt.Errorf("bad update request, two IDs (%s, %s) do not match", + id, p.ID) + } + + _, ok := s.data[id] if !ok { return fmt.Errorf("puppy with ID[%s] does not exists", p.ID) } - s.data[p.ID] = p + + s.data[id] = p return nil } diff --git a/06_puppy/alfredxiao/store_test.go b/06_puppy/alfredxiao/store_test.go index 0bffb942f..067621f52 100644 --- a/06_puppy/alfredxiao/store_test.go +++ b/06_puppy/alfredxiao/store_test.go @@ -40,15 +40,21 @@ func (s *storerSuite) TestReadPuppyNonExisting() { func (s *storerSuite) TestUpdatePuppyHappyCase() { id := s.store.CreatePuppy(Puppy{Colour: "Brown"}) - err := s.store.UpdatePuppy(Puppy{ID: id, Colour: "Green"}) + err := s.store.UpdatePuppy(id, Puppy{ID: id, Colour: "Green"}) s.Require().NoError(err) p, err := s.store.ReadPuppy(id) s.Require().NoError(err) s.Equal("Green", p.Colour) } +func (s *storerSuite) TestUpdatePuppyMismatchIDs() { + err := s.store.UpdatePuppy("id1", Puppy{ID: "id2"}) + s.Error(err) +} + func (s *storerSuite) TestUpdatePuppyNonExisting() { - err := s.store.UpdatePuppy(Puppy{ID: "id_that_does_not_exist_either"}) + id := "id_that_does_not_exist_either" + err := s.store.UpdatePuppy(id, Puppy{ID: id}) s.Error(err) } diff --git a/06_puppy/alfredxiao/syncstore.go b/06_puppy/alfredxiao/syncstore.go index f6b81bad0..0b5b222f3 100644 --- a/06_puppy/alfredxiao/syncstore.go +++ b/06_puppy/alfredxiao/syncstore.go @@ -28,12 +28,18 @@ func (s *syncStore) ReadPuppy(id string) (Puppy, error) { return p.(Puppy), nil } -func (s *syncStore) UpdatePuppy(p Puppy) error { - _, ok := s.data.Load(p.ID) +func (s *syncStore) UpdatePuppy(id string, p Puppy) error { + if id != p.ID { + return fmt.Errorf("bad update request, two IDs (%s, %s) do not match", + id, p.ID) + } + + _, ok := s.data.Load(id) if !ok { return fmt.Errorf("puppy with ID[%s] does not exists", p.ID) } - s.data.Store(p.ID, p) + + s.data.Store(id, p) return nil } diff --git a/06_puppy/alfredxiao/types.go b/06_puppy/alfredxiao/types.go index 72308365f..5d04abe8d 100644 --- a/06_puppy/alfredxiao/types.go +++ b/06_puppy/alfredxiao/types.go @@ -10,6 +10,6 @@ type Puppy struct { type Storer interface { CreatePuppy(p Puppy) string ReadPuppy(ID string) (Puppy, error) - UpdatePuppy(p Puppy) error + UpdatePuppy(ID string, p Puppy) error DeletePuppy(ID string) error }