// RestoreGatewayApp restores the Gateway App func (m *Mapper) RestoreGatewayApp() error { // return err when current state of gateway app is not WaitingRestore if err := m.StateTable.CheckGatewayState(state.WaitingRestore); err != nil { return state.ErrNotWaitingRestore } if err := m.StateTable.ChangeGatewayState(state.Restoring, common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil { return err } // change back to WaitingRestore only err happened during restoring gateway app hanleErr := func(err error) error { m.StateTable.ChangeGatewayState(state.WaitingRestore, common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)) return err } // disconnect all connecting mqtt clients m.Cloud.DisconnectAllMQTTClients() // clear DB if err := m.Store.ClearDB(); err != nil { return hanleErr(err) } // onboard with gateway app if _, err := m.onboardgatewayApp(); err != nil { return hanleErr(err) } // restore gateway if err := m.restoreGateway(m.Config.MasterApp.Site, m.Config.MasterApp.AppID); err != nil { return hanleErr(err) } // change state of gateway app to DoneOnboard after restore if err := m.StateTable.ChangeGatewayState(state.DoneOnboard, common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil { return hanleErr(err) } // Restore all the end-node apps saved on cloud apps, err := m.ListAllEndnodeApps() if err != nil { return err } for _, a := range apps { m.StateTable.ChangeAppState(state.Restoring, common.LocalID(common.LocalAppID(a.ServerLocation, a.AppID))) err = m.RestoreEndnodeApp(a) if err != nil { return err } m.StateTable.ChangeAppState(state.DoneOnboard, common.LocalID(common.LocalAppID(a.ServerLocation, a.AppID))) } //change restoreMode to false m.StateTable.RestoreMode = false return nil }
func TestPendingEndnodesMapper_restoringGateway(t *testing.T) { mapper := newMapper() defer mapper.clear() restoreStates := []state.State{state.WaitingRestore, state.Restoring} for _, s := range restoreStates { mapper.StateTable = &state.Table{ Gateway: s, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.WaitingRestore, }, RestoreMode: true, } nodes, err := mapper.PendingEndnodes("jp", "app67890") if err == nil { t.Fatal("should fail") } if err.Error() != "state isn't expected one of WAITING_RESTORE nor RESTORING but actual: UNKNONWD_STATE" { t.Fatal("fail with unexpected error", err) } if len(nodes) != 0 { t.Fatal("nodes should not have items") } } }
func TestReplaceEndnodeMapper_basic(t *testing.T) { mapper := newMapper() defer mapper.clear() mapper.StateTable = &state.Table{ Gateway: state.DoneOnboard, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.DoneOnboard, }, } err := mapper.ReplaceEndnode("jp", "app67890", "T0001endnode", "th.0001endnode") if err != nil { t.Fatal("TestReplaceEndnodeMapper_basic failed", err) } if mapper.store.caddr.AppID != "app67890" { t.Error("AppID should be \"app67890\":", mapper.store.caddr.AppID) } if mapper.store.caddr.ServerLocation != "jp" { t.Error("ServerLocation should be \"jp\":", mapper.store.caddr.ServerLocation) } if mapper.store.caddr.ThingID != "th.0001endnode" { t.Error("ThingID should be \"th.0001endnode\":", mapper.store.caddr.ThingID) } if mapper.store.ea.AppID != "app67890" { t.Error("AppID should be \"app67890\":", mapper.store.ea.AppID) } if mapper.store.ea.ServerLocation != "jp" { t.Error("ServerLocation should be \"jp\":", mapper.store.ea.ServerLocation) } if mapper.store.ea.VendorThingID != "T0001endnode" { t.Error("VendorThingID should be \"T0001endnode\":", mapper.store.ea.VendorThingID) } }
func TestRestoreGatewayApp_ENAppFail(t *testing.T) { mapper := newMapper() defer mapper.clear() allEndnodes := []common.App{ {ServerLocation: "jp", AppID: "id1", AppKey: "key1"}, } mapper.StateTable = &state.Table{ Gateway: state.WaitingRestore, Apps: map[common.LocalID]state.State{}, } mapper.cloud.err4OnboardEndnodeApp = errors.New("onboard endnode app fail") mapper.cloud.apps4ListAllEndnodeApps = allEndnodes err := mapper.RestoreGatewayApp() if err == nil { t.Error("should fail", err) } else { if err.Error() != "onboard endnode app fail" { t.Error("fail with other error", err) } } if mapper.StateTable.Gateway != state.DoneOnboard { t.Error("state of gateway app should be DoneOnboard", mapper.StateTable.Gateway) } enState := mapper.StateTable.Apps[common.LocalID(common.LocalAppID("jp", "id1"))] if enState != state.Restoring { t.Error("state of endnode app is not Restoring", enState) } }
func TestCompleteEndnodeOnboardingMapper_ENAppNotDoneOnboard(t *testing.T) { mapper := newMapper() defer mapper.clear() mapper.StateTable = &state.Table{ Gateway: state.DoneOnboard, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.Onboarding, }, } err := mapper.CompleteEndnodeOnboarding("jp", "app67890", "T0001endnode", "th.0001endnode") if err == nil { t.Fatal("TestCompleteEndnodeOnboardingMapper_restoringGateway should fail") } if err.Error() != "state is expected one of DONE_ONBOARD but actual: UNKNONWD_STATE" { t.Fatal("fail with other error", err) } }
// test GetGatewayID func TestGetGatewayIDMapper_basic(t *testing.T) { mapper := newMapper() defer mapper.clear() mapper.StateTable = &state.Table{ Gateway: state.DoneOnboard, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.DoneOnboard, }, } id, err := mapper.GetGatewayID("jp", "app67890") if err != nil { t.Fatal("TestGetGatewayIDMapper_basic failed", err) } if id != "th.0002gateway" { t.Error("ThingID should be \"th.0002gateway\":", id) } if mapper.store.appID4FindGatewayByAppID != "app67890" { t.Error("AppID should be \"app67890\":", mapper.store.appID) } }
func TestGetGatewayIDMapper_ENAppNotDoneOnboard(t *testing.T) { mapper := newMapper() defer mapper.clear() mapper.StateTable = &state.Table{ Gateway: state.DoneOnboard, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.Onboarding, }, } id, err := mapper.GetGatewayID("jp", "app67890") if err == nil { t.Fatal("should fail") } if id != "" { t.Fatal("id should be empty") } if err.Error() != "state is expected one of DONE_ONBOARD but actual: UNKNONWD_STATE" { t.Fatal("faild with other error", err) } }
func TestCompleteEndnodeOnboardingMapper_restoringGateway(t *testing.T) { mapper := newMapper() defer mapper.clear() restoreStates := []state.State{state.WaitingRestore, state.Restoring} for _, s := range restoreStates { mapper.StateTable = &state.Table{ Gateway: s, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.WaitingRestore, }, RestoreMode: true, } err := mapper.CompleteEndnodeOnboarding("jp", "app67890", "T0001endnode", "th.0001endnode") if err == nil { t.Fatal("TestCompleteEndnodeOnboardingMapper_restoringGateway should fail") } if err.Error() != "state isn't expected one of WAITING_RESTORE nor RESTORING but actual: UNKNONWD_STATE" { t.Fatal("fail with other error", err) } } }
func TestGetGatewayIDMapper_restoringGateway(t *testing.T) { mapper := newMapper() defer mapper.clear() mapper.StateTable = &state.Table{ Gateway: state.WaitingRestore, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.WaitingRestore, }, RestoreMode: true, } id, err := mapper.GetGatewayID("jp", "app67890") if err == nil { t.Fatal("should fail") } if id != "" { t.Fatal("id should be empty") } if err.Error() != "state isn't expected one of WAITING_RESTORE nor RESTORING but actual: UNKNONWD_STATE" { t.Fatal("faild with other error", err) } }
func TestPendingEndnodesMapper_gatewayNotReady(t *testing.T) { mapper := newMapper() defer mapper.clear() mapper.StateTable = &state.Table{ Gateway: state.Onboarding, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.DoneOnboard, }, } nodes, err := mapper.PendingEndnodes("jp", "app67890") if err == nil { t.Fatal("should fail") } if err.Error() != "state is expected one of DONE_ONBOARD but actual: UNKNONWD_STATE" { t.Fatal("fail with unexpected error", err) } if len(nodes) != 0 { t.Fatal("nodes should not have items") } }
// test PendingEndnodes func TestPendingEndnodesMapper_basic(t *testing.T) { mapper := newMapper() mapper.StateTable = &state.Table{ Gateway: state.DoneOnboard, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): state.DoneOnboard, }, } defer mapper.clear() nodes, err := mapper.PendingEndnodes("jp", "app67890") if err != nil { t.Fatal("TestPendingEndnodesMapper_basic failed", err) } if mapper.store.serverLocation != "jp" { t.Error("ServerLocation should be \"en\":", mapper.store.serverLocation) } if mapper.store.appID != "app67890" { t.Error("AppID should be \"app67890\":", mapper.store.appID) } if len(nodes) != 2 { t.Error("number of pending nodes should be 2:", len(nodes)) } }
func TestOnboardedEndnodesMapper_ENAppNotDoneOnboard(t *testing.T) { mapper := newMapper() defer mapper.clear() restoreStates := []state.State{state.WaitingOnboard, state.Onboarding} for _, s := range restoreStates { mapper.StateTable = &state.Table{ Gateway: state.DoneOnboard, Apps: map[common.LocalID]state.State{ common.LocalID(common.LocalAppID("jp", "app67890")): s, }, } nodes, err := mapper.OnboardedEndnodes("jp", "app67890") if err == nil { t.Fatal("should fail") } if err.Error() != "state is expected one of DONE_ONBOARD but actual: UNKNONWD_STATE" { t.Fatal("fail with unexpected error", err) } if len(nodes) != 0 { t.Fatal("nodes should not have items") } } }
// OnboardGatewayApp onboards the Gateway for the Gateway App func (m *Mapper) OnboardGatewayApp() (string, error) { // verify state if m.StateTable.RestoreMode { return "", state.ErrRestoringGateway } if err := m.StateTable.CheckGatewayState(state.Onboarding); err == nil { return "", state.ErrOnboarding } // start to onboard // change state to Onboarding before onboard if err := m.StateTable.ChangeGatewayState(state.Onboarding, common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil { return "", err } // change state of gateway app to onboarding before onboard gwLocalID := common.LocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID) if err := m.StateTable.ChangeAppState(state.Onboarding, common.LocalID(gwLocalID)); err != nil { return "", err } handleErr := func(err error) (string, error) { m.StateTable.ChangeGatewayState(state.WaitingOnboard, common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)) m.StateTable.ChangeAppState(state.Onboarding, common.LocalID(gwLocalID)) return "", err } // for multiple onboard, need to delete gateway from DB first if _, err := m.Store.FindGatewayByAppID(m.Config.MasterApp.AppID); err == nil { // disconnect mqtt connection if err := m.Cloud.DisconnectMQTTClient(common.App{ AppID: m.Config.MasterApp.AppID, ServerLocation: m.Config.MasterApp.Site, }); err != nil { return handleErr(err) } // delete gateway if err := m.Store.DeleteGateway(m.Config.MasterApp.AppID); err != nil { return handleErr(err) } } gwID, err := m.onboardgatewayApp() if err != nil { return handleErr(err) } // change state of gateway app to DoneOnboard after onboard if err := m.StateTable.ChangeAppState(state.DoneOnboard, common.LocalID(gwLocalID)); err != nil { return handleErr(err) } // change state to DoneOnboard after onboard if err := m.StateTable.ChangeGatewayState(state.DoneOnboard, common.ToLocalAppID(m.Config.MasterApp.Site, m.Config.MasterApp.AppID)); err != nil { return handleErr(err) } return gwID, nil }