diff --git a/api/initialise_test.go b/api/initialise_test.go index 11ea37d71cc0c0c4464ac9bbf54c403b43c51e26..39fd31483246ca8a7b54f58f2f5237ed99061290 100644 --- a/api/initialise_test.go +++ b/api/initialise_test.go @@ -5,6 +5,7 @@ import ( "net" "os" "testing" + "time" cpb "code.fbi.h-da.de/cocsn/api/go/gosdn/core" ppb "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd" @@ -71,13 +72,17 @@ func bootstrapUnitTest() { log.Fatal(err) } + mockChange := &mocks.Change{} + mockChange.On("Age").Return(time.Hour) + mockChange.On("State").Return(ppb.Change_INCONSISTENT) + mockPnd := mocks.NetworkDomain{} mockPnd.On("ID").Return(pndUUID) mockPnd.On("GetName").Return("test") mockPnd.On("GetDescription").Return("test") mockPnd.On("PendingChanges").Return([]uuid.UUID{changeUUID}) mockPnd.On("CommittedChanges").Return([]uuid.UUID{changeUUID}) - mockPnd.On("GetChange", mock.Anything).Return(&nucleus.Change{}, nil) + mockPnd.On("GetChange", mock.Anything).Return(mockChange, nil) mockPnd.On("AddDevice", mock.Anything, mock.Anything, mock.Anything).Return(nil) mockPnd.On("GetDevice", mock.Anything).Return(&nucleus.CommonDevice{ UUID: deviceUUID, diff --git a/go.mod b/go.mod index 3352d794160883bce4428e0e5ae4220c2ed2e87b..a08af136b5f58a1b4abcc8c26f6465b851558df0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module code.fbi.h-da.de/cocsn/gosdn go 1.16 require ( - code.fbi.h-da.de/cocsn/api v0.2.2 + code.fbi.h-da.de/cocsn/api v0.2.3 code.fbi.h-da.de/cocsn/yang-models v0.0.7 github.com/aristanetworks/goarista v0.0.0-20201120222254-94a892eb0c6a github.com/docker/docker v20.10.6+incompatible diff --git a/go.sum b/go.sum index 7e38b738e82ae94a458608b99b5399eb21b924f3..5ef6055e5ebd8c702b23cce100414d576e0b1830 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -code.fbi.h-da.de/cocsn/api v0.2.2 h1:pJ1P3+l8Fl+JWEkoLTSBOvB6LrxUYYqRbfdt+eSWQSk= -code.fbi.h-da.de/cocsn/api v0.2.2/go.mod h1:s+P4Lrxl5rHyo/Q0UTABZrDfH4zuAoRKdzktlL0UsRI= +code.fbi.h-da.de/cocsn/api v0.2.3 h1:zyXVU2yuRuS5a+UMGUj8eT86E+sxw15NHtFN9tjXfCk= +code.fbi.h-da.de/cocsn/api v0.2.3/go.mod h1:s+P4Lrxl5rHyo/Q0UTABZrDfH4zuAoRKdzktlL0UsRI= code.fbi.h-da.de/cocsn/yang-models v0.0.7 h1:3TOo8J+EdAJKeq4o3aaNWZRhjSwguIS8wciW1U9PkSk= code.fbi.h-da.de/cocsn/yang-models v0.0.7/go.mod h1:M+2HinfhTT8nA8qvn2cpWNlOtuiizTNDWA3yfy72K/g= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= diff --git a/interfaces/change/change.go b/interfaces/change/change.go index 493c2183fb3cb3b416badaf39d1c9e449f7e1db4..28b15cbe8be4bbb43959eb1a134e3670c9406f35 100644 --- a/interfaces/change/change.go +++ b/interfaces/change/change.go @@ -1,6 +1,8 @@ package change import ( + "time" + ppb "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd" "github.com/google/uuid" "github.com/openconfig/ygot/ygot" @@ -15,6 +17,7 @@ type Change interface { Commit() error Confirm() error State() ppb.Change_State + Age() time.Duration } // Payload contains two ygot.GoStructs, the first represents the original state diff --git a/mocks/Change.go b/mocks/Change.go index c211183e76791592c3dcb4274f3fd250df54969f..945413247293aa4e2d6aba02b6cca46b9a0024f3 100644 --- a/mocks/Change.go +++ b/mocks/Change.go @@ -6,6 +6,8 @@ import ( pnd "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd" mock "github.com/stretchr/testify/mock" + time "time" + uuid "github.com/google/uuid" ) @@ -14,6 +16,20 @@ type Change struct { mock.Mock } +// Age provides a mock function with given fields: +func (_m *Change) Age() time.Duration { + ret := _m.Called() + + var r0 time.Duration + if rf, ok := ret.Get(0).(func() time.Duration); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(time.Duration) + } + + return r0 +} + // Commit provides a mock function with given fields: func (_m *Change) Commit() error { ret := _m.Called() diff --git a/northbound/server/pnd.go b/northbound/server/pnd.go index 42168323f949af46682f7246ca54cd7882a0aaaa..887ded7dccc5ef9adfb069b403cf109c4e34f092 100644 --- a/northbound/server/pnd.go +++ b/northbound/server/pnd.go @@ -281,18 +281,11 @@ func fillChanges(pnd networkdomain.NetworkDomain, all bool, cuid ...string) ([]* log.Error(err) return nil, status.Errorf(codes.Aborted, "%v", err) } - change, ok := c.(*nucleus.Change) - if !ok { - return nil, &errors.ErrInvalidTypeAssertion{ - Value: change, - Type: reflect.TypeOf(&nucleus.Change{}), - } - } changes[i] = &ppb.Change{ Id: ch.String(), - Age: change.Age().Microseconds(), - State: change.State(), + Age: c.Age().Microseconds(), + State: c.State(), } } return changes, nil diff --git a/northbound/server/pnd_test.go b/northbound/server/pnd_test.go index 0137cde1a7d54bd6aab8bd48a563a3a7f55111c5..83ca057c7d0127e0e2cb434dc7866c0e2dc3683b 100644 --- a/northbound/server/pnd_test.go +++ b/northbound/server/pnd_test.go @@ -5,6 +5,7 @@ import ( "os" "reflect" "testing" + "time" ppb "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd" spb "code.fbi.h-da.de/cocsn/api/go/gosdn/southbound" @@ -75,6 +76,10 @@ func TestMain(m *testing.M) { log.Fatal(err) } + mockChange := &mocks.Change{} + mockChange.On("Age").Return(time.Hour) + mockChange.On("State").Return(ppb.Change_INCONSISTENT) + mockPnd = &mocks.NetworkDomain{} mockPnd.On("ID").Return(pndUUID) mockPnd.On("GetName").Return("test") @@ -83,7 +88,7 @@ func TestMain(m *testing.M) { mockPnd.On("Devices").Return([]uuid.UUID{deviceUUID}) mockPnd.On("PendingChanges").Return([]uuid.UUID{pendingChangeUUID}) mockPnd.On("CommittedChanges").Return([]uuid.UUID{committedChangeUUID}) - mockPnd.On("GetChange", mock.Anything).Return(&nucleus.Change{}, nil) + mockPnd.On("GetChange", mock.Anything).Return(mockChange, nil) mockPnd.On("AddDevice", mock.Anything, mock.Anything, mock.Anything).Return(nil) mockPnd.On("GetDevice", mock.Anything).Return(mockDevice, nil) mockPnd.On("Commit", mock.Anything).Return(nil) diff --git a/nucleus/change.go b/nucleus/change.go index 391a90bfe4da99142f820e840e6b0f262151ac32..8bccf6deec1d88952bef7cdfc3aa7be0965b6e51 100644 --- a/nucleus/change.go +++ b/nucleus/change.go @@ -28,26 +28,25 @@ func init() { } } -// NewChange takes a Device UUID, a pair GoStructs (current and intended state) -// a callback function and a channel for errors and returns a *Change +// NewChange takes a Device UUID, a pair GoStructs (current and intended state), +// a callback function, and returns a *Change. // The callback function is used by the Commit() and Confirm() functions. It // must define how the change is carried out. -func NewChange(device uuid.UUID, currentState ygot.GoStruct, change ygot.GoStruct, callback func(ygot.GoStruct, ygot.GoStruct) error, errChan chan error) *Change { - commit, confirm, out := stateManager(changeTimeout) - return &Change{ +func NewChange(device uuid.UUID, currentState ygot.GoStruct, change ygot.GoStruct, callback func(ygot.GoStruct, ygot.GoStruct) error) *Change { + c := &Change{ cuid: uuid.New(), duid: device, timestamp: time.Now(), previousState: currentState, intendedState: change, - committed: false, - confirmed: false, callback: callback, - errChan: errChan, - out: out, - commit: commit, - confirm: confirm, } + stateIn, stateOut, requestState, errChan := stateManager(c, changeTimeout) + c.stateIn = stateIn + c.stateOut = stateOut + c.requestState = requestState + c.errChan = errChan + return c } // Change is an intended change to an OND. It is unique and immutable. @@ -60,14 +59,11 @@ type Change struct { timestamp time.Time previousState ygot.GoStruct intendedState ygot.GoStruct - committed bool - confirmed bool - inconsistent bool callback func(ygot.GoStruct, ygot.GoStruct) error - errChan chan error - out <-chan bool - commit chan<- *Change - confirm chan<- *Change + errChan <-chan error + requestState chan<- bool + stateIn chan<- ppb.Change_State + stateOut <-chan ppb.Change_State } // ID returns the Change's UUID @@ -79,36 +75,30 @@ func (c *Change) ID() uuid.UUID { // and starts the timeout-timer for the Change. If the timer expires // the change is rolled back. func (c *Change) Commit() error { - if c.committed { + if c.State() == ppb.Change_COMMITTED { return fmt.Errorf("change %v already committed", c.cuid) } - c.commit <- c + c.stateIn <- ppb.Change_COMMITTED select { case err := <-c.errChan: - if err != nil { - return err - } - case <-c.out: + return err + case <-c.stateOut: return nil } - return nil } // Confirm confirms a committed Change and stops the rollback timer. func (c *Change) Confirm() error { - if !c.committed { + if c.State() != ppb.Change_COMMITTED { return fmt.Errorf("cannot confirm uncommitted change %v", c.cuid) } - c.confirm <- c + c.stateIn <- ppb.Change_CONFIRMED select { case err := <-c.errChan: - if err != nil { - return err - } - case <-c.out: + return err + case <-c.stateOut: return nil } - return nil } // Age returns the passed time since the Change was created @@ -118,44 +108,51 @@ func (c *Change) Age() time.Duration { // State returns the changes's state. func (c *Change) State() ppb.Change_State { - if !c.committed { - return ppb.Change_PENDING - } else if !c.confirmed { - return ppb.Change_COMMITTED - } else { - return ppb.Change_CONFIRMED - } + c.requestState <- true + return <-c.stateOut } -func stateManager(timeout time.Duration) (chan<- *Change, chan<- *Change, <-chan bool) { - commit := make(chan *Change) - confirm := make(chan *Change) - out := make(chan bool) +func stateManager(ch *Change, timeout time.Duration) (chan<- ppb.Change_State, <-chan ppb.Change_State, chan<- bool, <-chan error) { + stateIn := make(chan ppb.Change_State) + stateOut := make(chan ppb.Change_State) + stateRequest := make(chan bool) + errChan := make(chan error) ticker := time.NewTicker(timeout) go func() { - ch := <-commit - err := ch.callback(ch.previousState, ch.intendedState) - if err != nil { - ch.errChan <- err - } - ch.committed = true - out <- true + state := ppb.Change_PENDING for { select { case <-ticker.C: - err := ch.callback(ch.intendedState, ch.previousState) - if err != nil { - ch.errChan <- err + // only roll back committed changes + if state == ppb.Change_COMMITTED { + err := ch.callback(ch.intendedState, ch.previousState) + if err != nil { + state = ppb.Change_INCONSISTENT + errChan <- err + } + errChan <- fmt.Errorf("change %v timed out", ch.cuid) + break + } + case s := <-stateIn: + switch s { + case ppb.Change_COMMITTED: + err := ch.callback(ch.previousState, ch.intendedState) + if err != nil { + state = ppb.Change_INCONSISTENT + errChan <- err + continue + } + state = ppb.Change_COMMITTED + stateOut <- state + case ppb.Change_CONFIRMED: + state = ppb.Change_CONFIRMED + stateOut <- state } - ch.errChan <- fmt.Errorf("change %v timed out", ch.cuid) - break - case <-confirm: - ch.confirmed = true - out <- true - break + case <-stateRequest: + stateOut <- state } } }() - return commit, confirm, out + return stateIn, stateOut, stateRequest, errChan } diff --git a/nucleus/change_test.go b/nucleus/change_test.go index 422b172619329a65189cf6acb130fc554ca410ed..3f16dd04a61b75b60c677d613dad4ec7e4fa7d31 100644 --- a/nucleus/change_test.go +++ b/nucleus/change_test.go @@ -3,6 +3,7 @@ package nucleus import ( "errors" "reflect" + "sync" "testing" "time" @@ -28,16 +29,11 @@ var rollbackDevice = &exampleoc.Device{ } func TestChange_CommitRollback(t *testing.T) { + wg := sync.WaitGroup{} wantErr := false want := rollbackHostname callback := make(chan string) - errChan := make(chan error, 10) - commit, confirm, out := stateManager(time.Millisecond * 100) c := &Change{ - commit: commit, - confirm: confirm, - errChan: errChan, - out: out, cuid: cuid, duid: did, timestamp: time.Now(), @@ -45,7 +41,7 @@ func TestChange_CommitRollback(t *testing.T) { intendedState: commitDevice, callback: func(first ygot.GoStruct, second ygot.GoStruct) error { hostname := *first.(*exampleoc.Device).System.Hostname - t.Logf("hostname: %v", hostname) + t.Logf("callback in test %v", t.Name()) switch hostname { case rollbackHostname: callback <- rollbackHostname @@ -53,27 +49,33 @@ func TestChange_CommitRollback(t *testing.T) { return nil }, } + stateIn, stateOut, requestState, errChan := stateManager(c, time.Millisecond*100) + c.stateIn = stateIn + c.stateOut = stateOut + c.requestState = requestState + c.errChan = errChan + wg.Add(1) go func() { + defer wg.Done() time.Sleep(time.Millisecond * 10) if err := c.Commit(); (err != nil) != wantErr { t.Errorf("Commit() error = %v, wantErr %v", err, wantErr) } - time.Sleep(time.Millisecond * 100) + time.Sleep(time.Millisecond * 200) }() got := <-callback if !reflect.DeepEqual(got, want) { t.Errorf("Commit() = %v, want %v", got, want) } + wg.Wait() } func TestChange_CommitRollbackError(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(1) wantErr := false want := errors.New("this is an expected error") - commit, confirm, out := stateManager(time.Millisecond * 100) c := &Change{ - commit: commit, - confirm: confirm, - out: out, cuid: cuid, duid: did, timestamp: time.Now(), @@ -81,35 +83,38 @@ func TestChange_CommitRollbackError(t *testing.T) { intendedState: commitDevice, callback: func(first ygot.GoStruct, second ygot.GoStruct) error { hostname := *second.(*exampleoc.Device).System.Hostname - t.Logf("hostname: %v", hostname) + t.Logf("callback in test %v", t.Name()) switch hostname { case rollbackHostname: return errors.New("this is an expected error") } return nil }, - errChan: make(chan error), } + stateIn, stateOut, requestState, errChan := stateManager(c, time.Millisecond*100) + c.stateIn = stateIn + c.stateOut = stateOut + c.requestState = requestState + c.errChan = errChan + go func() { + defer wg.Done() time.Sleep(time.Millisecond * 10) if err := c.Commit(); (err != nil) != wantErr { t.Errorf("Commit() error = %v, wantErr %v", err, wantErr) } - time.Sleep(time.Millisecond * 100) + time.Sleep(time.Millisecond * 200) }() got := <-c.errChan if !reflect.DeepEqual(got, want) { t.Errorf("Commit() = %v, want %v", got, want) } + wg.Wait() } func TestChange_CommitError(t *testing.T) { - wantErr := true - commit, confirm, out := stateManager(time.Millisecond * 100) + want := ppb.Change_INCONSISTENT c := &Change{ - commit: commit, - confirm: confirm, - out: out, cuid: cuid, duid: did, timestamp: time.Now(), @@ -119,38 +124,41 @@ func TestChange_CommitError(t *testing.T) { return errors.New("this is an expected error") }, } - go func() { - time.Sleep(time.Millisecond * 10) - if err := c.Commit(); (err != nil) != wantErr { - t.Errorf("Commit() error = %v, wantErr %v", err, wantErr) - } - }() - got := c.committed - if !reflect.DeepEqual(got, false) { - t.Errorf("Commit() = %v, want %v", got, false) + stateIn, stateOut, requestState, errChan := stateManager(c, time.Millisecond*100) + c.stateIn = stateIn + c.stateOut = stateOut + c.requestState = requestState + c.errChan = errChan + + time.Sleep(time.Millisecond * 10) + if err := c.Commit(); err == nil { + t.Errorf("Commit() expected error, error = %v", err) + } + got := c.State() + if !reflect.DeepEqual(got, want) { + t.Errorf("Commit() = %v, want %v", got, want) } } func TestChange_Commit(t *testing.T) { want := ppb.Change_COMMITTED - - commit, confirm, out := stateManager(time.Millisecond * 100) c := &Change{ - commit: commit, - confirm: confirm, - out: out, cuid: cuid, duid: did, timestamp: time.Now(), previousState: rollbackDevice, intendedState: commitDevice, callback: func(first ygot.GoStruct, second ygot.GoStruct) error { - hostname := *first.(*exampleoc.Device).System.Hostname - t.Logf("hostname: %v", hostname) + t.Logf("callback in test %v", t.Name()) return nil }, - errChan: make(chan error, 10), } + stateIn, stateOut, requestState, errChan := stateManager(c, time.Millisecond*100) + c.stateIn = stateIn + c.stateOut = stateOut + c.requestState = requestState + c.errChan = errChan + if err := c.Commit(); err != nil { t.Errorf("Commit() error = %v", err) } @@ -179,13 +187,7 @@ func TestChange_Confirm(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - errChan := make(chan error, 10) - commit, confirm, out := stateManager(time.Millisecond * 100) c := &Change{ - commit: commit, - confirm: confirm, - errChan: errChan, - out: out, previousState: &exampleoc.Device{ System: &exampleoc.System{ Hostname: &rollbackHostname, @@ -197,11 +199,16 @@ func TestChange_Confirm(t *testing.T) { }, }, callback: func(first ygot.GoStruct, second ygot.GoStruct) error { - hostname := *first.(*exampleoc.Device).System.Hostname - t.Logf("hostname: %v", hostname) + t.Logf("callback in test %v", t.Name()) return nil }, } + stateIn, stateOut, requestState, errChan := stateManager(c, time.Millisecond*100) + c.stateIn = stateIn + c.stateOut = stateOut + c.requestState = requestState + c.errChan = errChan + if tt.name == "committed" { if err := c.Commit(); err != nil { t.Errorf("Commit() error = %v, wantErr %v", err, tt.wantErr) @@ -262,12 +269,10 @@ func TestChange_State(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { callback := func(first ygot.GoStruct, second ygot.GoStruct) error { - hostname := *first.(*exampleoc.Device).System.Hostname - t.Logf("hostname: %v", hostname) + t.Logf("callback in test %v", t.Name()) return nil } - errChan := make(chan error) - c := NewChange(did, rollbackDevice, commitDevice, callback, errChan) + c := NewChange(did, rollbackDevice, commitDevice, callback) if tt.name != "pending" { if err := c.Commit(); err != nil { t.Errorf("Commit() error = %v", err) diff --git a/nucleus/initialise_test.go b/nucleus/initialise_test.go index c93c3615ff866b3adcfd69e6e82acd185fa44bda..ed715276991df0cb7602ffbd345d7189652b8972 100644 --- a/nucleus/initialise_test.go +++ b/nucleus/initialise_test.go @@ -155,6 +155,5 @@ func newPnd() pndImplementation { devices: NewDeviceStore(), changes: ChangeStore{genericStore{}}, id: defaultPndID, - errChans: make(map[uuid.UUID]chan error), } } diff --git a/nucleus/principalNetworkDomain.go b/nucleus/principalNetworkDomain.go index 4655a0b074dcfdbf9dcbfb1187ab3c3a36b04cd6..18b06083047476836375ee690fae350988fad3de 100644 --- a/nucleus/principalNetworkDomain.go +++ b/nucleus/principalNetworkDomain.go @@ -35,7 +35,6 @@ func NewPND(name, description string, id uuid.UUID, sbi southbound.SouthboundInt devices: NewDeviceStore(), changes: ChangeStore{genericStore{}}, id: id, - errChans: make(map[uuid.UUID]chan error), csbiClient: c, callback: callback, @@ -53,7 +52,6 @@ type pndImplementation struct { devices *DeviceStore changes ChangeStore id uuid.UUID - errChans map[uuid.UUID]chan error csbiClient cpb.CsbiClient callback func(uuid.UUID, chan DeviceDetails) @@ -312,11 +310,7 @@ func (pnd *pndImplementation) ChangeOND(duid uuid.UUID, operation ppb.ApiOperati payload := change.Payload{Original: original, Modified: modified} return d.Transport().Set(ctx, payload) } - - errChan := make(chan error) - ch := NewChange(duid, d.Model(), cpy, callback, errChan) - pnd.errChans[ch.ID()] = errChan - + ch := NewChange(duid, d.Model(), cpy, callback) if err := pnd.changes.Add(ch); err != nil { return uuid.Nil, err } diff --git a/nucleus/principalNetworkDomain_test.go b/nucleus/principalNetworkDomain_test.go index 536d4d71993971b2cedd071dd4438230a9f61cfb..b273821a04c0dce6c6faab303064f12616d246c9 100644 --- a/nucleus/principalNetworkDomain_test.go +++ b/nucleus/principalNetworkDomain_test.go @@ -16,6 +16,7 @@ import ( "github.com/google/uuid" gpb "github.com/openconfig/gnmi/proto/gnmi" "github.com/openconfig/ygot/ygot" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/mock" ) @@ -790,21 +791,31 @@ func Test_pndImplementation_Confirm(t *testing.T) { } func Test_pndImplementation_PendingChanges(t *testing.T) { + testName := t.Name() + callback := func(first ygot.GoStruct, second ygot.GoStruct) error { + log.Infof("callback in test %v", testName) + return nil + } + + store := NewChangeStore() + pending := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := store.Add(pending); err != nil { + t.Error(err) + return + } tests := []struct { name string want []uuid.UUID }{ { name: "default", - want: []uuid.UUID{cuid}, + want: []uuid.UUID{pending.cuid}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pnd := newPnd() - pnd.changes.genericStore[cuid] = &Change{ - cuid: cuid, - } + pnd.changes = *store if got := pnd.PendingChanges(); !reflect.DeepEqual(got, tt.want) { t.Errorf("pndImplementation.PendingChanges() = %v, want %v", got, tt.want) } @@ -813,22 +824,35 @@ func Test_pndImplementation_PendingChanges(t *testing.T) { } func Test_pndImplementation_CommittedChanges(t *testing.T) { + testName := t.Name() + callback := func(first ygot.GoStruct, second ygot.GoStruct) error { + log.Infof("callback in test %v", testName) + return nil + } + + store := NewChangeStore() + committed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := committed.Commit(); err != nil { + t.Error(err) + return + } + if err := store.Add(committed); err != nil { + t.Error(err) + return + } tests := []struct { name string want []uuid.UUID }{ { name: "default", - want: []uuid.UUID{cuid}, + want: []uuid.UUID{committed.cuid}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pnd := newPnd() - pnd.changes.genericStore[cuid] = &Change{ - cuid: cuid, - committed: true, - } + pnd.changes = *store if got := pnd.CommittedChanges(); !reflect.DeepEqual(got, tt.want) { t.Errorf("pndImplementation.CommittedChanges() = %v, want %v", got, tt.want) } @@ -837,23 +861,38 @@ func Test_pndImplementation_CommittedChanges(t *testing.T) { } func Test_pndImplementation_ConfirmedChanges(t *testing.T) { + testName := t.Name() + callback := func(first ygot.GoStruct, second ygot.GoStruct) error { + log.Infof("callback in test %v", testName) + return nil + } + store := NewChangeStore() + confirmed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := confirmed.Commit(); err != nil { + t.Error(err) + return + } + if err := confirmed.Confirm(); err != nil { + t.Error(err) + return + } + if err := store.Add(confirmed); err != nil { + t.Error(err) + return + } tests := []struct { name string want []uuid.UUID }{ { name: "default", - want: []uuid.UUID{cuid}, + want: []uuid.UUID{confirmed.cuid}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pnd := newPnd() - pnd.changes.genericStore[cuid] = &Change{ - cuid: cuid, - committed: true, - confirmed: true, - } + pnd.changes = *store if got := pnd.ConfirmedChanges(); !reflect.DeepEqual(got, tt.want) { t.Errorf("pndImplementation.ConfirmedChanges() = %v, want %v", got, tt.want) } diff --git a/nucleus/store_test.go b/nucleus/store_test.go index 42f6a95d6677e31c8227c016fba9cfdcac986277..2e19b2ff2f30d995a789c735a5706f46577f3381 100644 --- a/nucleus/store_test.go +++ b/nucleus/store_test.go @@ -6,6 +6,7 @@ import ( "testing" ppb "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd" + "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" "code.fbi.h-da.de/cocsn/gosdn/interfaces/device" "code.fbi.h-da.de/cocsn/gosdn/interfaces/networkdomain" @@ -14,6 +15,8 @@ import ( "code.fbi.h-da.de/cocsn/gosdn/mocks" "github.com/google/uuid" + "github.com/openconfig/ygot/ygot" + log "github.com/sirupsen/logrus" ) func Test_Store_add(t *testing.T) { @@ -423,29 +426,30 @@ func Test_deviceStore_get(t *testing.T) { } func TestChangeStore_Pending(t *testing.T) { - type fields struct { - genericStore genericStore + testName := t.Name() + callback := func(first ygot.GoStruct, second ygot.GoStruct) error { + log.Infof("callback in test %v", testName) + return nil + } + + store := NewChangeStore() + pending := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := store.Add(pending); err != nil { + t.Error(err) + return } tests := []struct { - name string - fields fields - want []uuid.UUID + name string + want []uuid.UUID }{ { name: "default", - fields: fields{ - genericStore: genericStore{ - cuid: &Change{cuid: cuid}, - }, - }, - want: []uuid.UUID{cuid}, + want: []uuid.UUID{pending.cuid}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := ChangeStore{ - genericStore: tt.fields.genericStore, - } + s := store if got := s.Pending(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Pending() = %v, want %v", got, tt.want) } @@ -454,32 +458,34 @@ func TestChangeStore_Pending(t *testing.T) { } func TestChangeStore_Committed(t *testing.T) { - type fields struct { - genericStore genericStore + testName := t.Name() + callback := func(first ygot.GoStruct, second ygot.GoStruct) error { + log.Infof("callback in test %v", testName) + return nil + } + + store := NewChangeStore() + committed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := committed.Commit(); err != nil { + t.Error(err) + return + } + if err := store.Add(committed); err != nil { + t.Error(err) + return } tests := []struct { - name string - fields fields - want []uuid.UUID + name string + want []uuid.UUID }{ { name: "default", - fields: fields{ - genericStore: genericStore{ - cuid: &Change{ - cuid: cuid, - committed: true, - }, - }, - }, - want: []uuid.UUID{cuid}, + want: []uuid.UUID{committed.cuid}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := ChangeStore{ - genericStore: tt.fields.genericStore, - } + s := store if got := s.Committed(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Committed() = %v, want %v", got, tt.want) } @@ -488,33 +494,39 @@ func TestChangeStore_Committed(t *testing.T) { } func TestChangeStore_Confirmed(t *testing.T) { - type fields struct { - genericStore genericStore + testName := t.Name() + callback := func(first ygot.GoStruct, second ygot.GoStruct) error { + log.Infof("callback in test %v", testName) + return nil + } + + store := NewChangeStore() + confirmed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := confirmed.Commit(); err != nil { + t.Error(err) + return } + if err := confirmed.Confirm(); err != nil { + t.Error(err) + return + } + if err := store.Add(confirmed); err != nil { + t.Error(err) + return + } + tests := []struct { - name string - fields fields - want []uuid.UUID + name string + want []uuid.UUID }{ { name: "default", - fields: fields{ - genericStore: genericStore{ - cuid: &Change{ - cuid: cuid, - committed: true, - confirmed: true, - }, - }, - }, - want: []uuid.UUID{cuid}, + want: []uuid.UUID{confirmed.cuid}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := ChangeStore{ - genericStore: tt.fields.genericStore, - } + s := store if got := s.Confirmed(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Confirmed() = %v, want %v", got, tt.want) } @@ -523,18 +535,27 @@ func TestChangeStore_Confirmed(t *testing.T) { } func Test_filterChanges(t *testing.T) { + testName := t.Name() + callback := func(first ygot.GoStruct, second ygot.GoStruct) error { + log.Infof("callback in test %v", testName) + return nil + } + store := NewChangeStore() - pending := &Change{ - cuid: uuid.New(), + pending := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + committed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := committed.Commit(); err != nil { + t.Error(err) + return } - committed := &Change{ - cuid: uuid.New(), - committed: true, + confirmed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback) + if err := confirmed.Commit(); err != nil { + t.Error(err) + return } - confirmed := &Change{ - cuid: uuid.New(), - committed: true, - confirmed: true, + if err := confirmed.Confirm(); err != nil { + t.Error(err) + return } if err := store.Add(pending); err != nil { t.Error(err)