Beispiel #1
0
// 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 TestOnboardEndnodeAppMapper_gatewayNotReady(t *testing.T) {
	mapper := newMapper()
	defer mapper.clear()
	app := common.App{
		AppID:          "app67890",
		AppKey:         "app0987654321abcdefghijklmn",
		ServerLocation: "jp",
	}
	mapper.StateTable = &state.Table{
		Gateway: state.Onboarding,
		Apps: map[common.LocalID]state.State{
			common.LocalID(app.LocalID()): state.DoneOnboard,
		},
	}
	id, err := mapper.OnboardEndnodeApp(app)
	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("fail with unexpected error", err)
	}
}
func TestOnboardEndnodeAppMapper_restoringGateway(t *testing.T) {
	mapper := newMapper()
	defer mapper.clear()
	app := common.App{
		AppID:          "app67890",
		AppKey:         "app0987654321abcdefghijklmn",
		ServerLocation: "jp",
	}
	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(app.LocalID()): state.WaitingRestore,
			},
			RestoreMode: true,
		}
		id, err := mapper.OnboardEndnodeApp(app)
		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("fail with unexpected error", err)
		}
	}
}
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 TestOnboardEndnodeAppMapper_wrongPassword(t *testing.T) {
	mapper := newMapper()
	defer mapper.clear()
	app := common.App{
		AppID:          "app67890",
		AppKey:         "app0987654321abcdefghijklmn",
		ServerLocation: "jp",
	}
	mapper.StateTable = &state.Table{
		Gateway: state.DoneOnboard,
		Apps: map[common.LocalID]state.State{
			common.LocalID(app.LocalID()): state.DoneOnboard,
		},
	}
	mapper.cloud.err4OnboardEndnodeApp = common.ErrWrongPassword
	id, err := mapper.OnboardEndnodeApp(app)
	if err == nil {
		t.Fatal("should fail")
	}
	if id != "" {
		t.Fatal("id should be empty")
	}
	if err.Error() != "wrong password of gateway" {
		t.Fatal("fail with unexpected error", err)
	}
}
// test OnboardEndnodeApp
func TestOnboardEndnodeAppMapper_basic(t *testing.T) {
	mapper := newMapper()
	defer mapper.clear()
	app := common.App{
		AppID:          "app67890",
		AppKey:         "app0987654321abcdefghijklmn",
		ServerLocation: "jp",
	}
	mapper.StateTable = &state.Table{
		Gateway: state.DoneOnboard,
		Apps: map[common.LocalID]state.State{
			common.LocalID(app.LocalID()): state.WaitingOnboard,
		},
	}
	id, err := mapper.OnboardEndnodeApp(app)
	if err != nil {
		t.Fatal("TestOnboardEndnodeAppMapper_basic failed", err)
	}
	if id != "th.0001endnode" {
		t.Error("ThingID should be \"th.0001endnode\":", id)
	}
	if mapper.store.appID != "app67890" {
		t.Error("AppID should be \"app67890\":", mapper.store.appID)
	}
	if mapper.cloud.app.AppID != "app67890" {
		t.Error("AppID should be \"app67890\":", mapper.cloud.app.AppID)
	}
	if mapper.cloud.app.AppKey != "app0987654321abcdefghijklmn" {
		t.Error("AppKey should be \"app0987654321abcdefghijklmn\":", mapper.cloud.app.AppKey)
	}
	if mapper.cloud.app.ServerLocation != "jp" {
		t.Error("ServerLocation should be \"jp\":", mapper.cloud.app.ServerLocation)
	}
	if mapper.cloud.called4SaveEndnodeApp != true {
		t.Error("endnode app should be saved on gateway app")
	}

	if mapper.StateTable.Apps[common.LocalID(app.LocalID())] != state.DoneOnboard {
		t.Fatal("endnode app should be DoneOnboard", mapper.StateTable.Apps[common.LocalID(app.LocalID())])
	}
}
// LoadTable load state table from store
func LoadTable(s store.Store, gwID common.LocalID, restoreMode bool) (*Table, error) {
	allStates := map[common.LocalID]State{}

	onboardedApps, err := s.GetAllOnboardedApp()
	if err != nil {
		return nil, err
	}

	// defaultState is for the gateway already onboarded
	var defaultState State
	if restoreMode {
		defaultState = WaitingRestore
	} else {
		defaultState = DoneOnboard
	}

	var gwState State
	for _, gateway := range onboardedApps {
		if gwID == common.LocalID(gateway.LocalID()) {
			gwState = defaultState
		}
		allStates[common.LocalID(gateway.LocalID())] = defaultState
	}

	// if gateway is not onboarded, the value under normal mode is WaitingOnboard
	if gwState == 0 {
		if restoreMode {
			gwState = WaitingRestore
		} else {
			gwState = WaitingOnboard
		}
	}
	st := &Table{
		Gateway:     gwState,
		Apps:        allStates,
		RestoreMode: restoreMode,
	}
	return st, nil
}
Beispiel #10
0
// OnboardEndnodeApp onboards the Gateway for the Endnode App
func (m *Mapper) OnboardEndnodeApp(app common.App) (string, error) {

	if app.ServerLocation == m.Config.MasterApp.Site && app.AppID == m.Config.MasterApp.AppID {
		return m.OnboardGatewayApp()
	}
	// verify state first
	if m.StateTable.RestoreMode {
		return "", state.ErrRestoringGateway
	}
	// if gateway state is not DoneOnboard, then resturn err
	if err := m.StateTable.CheckGatewayState(state.DoneOnboard); err != nil {
		return "", state.ErrGatewayAppGatewayNotReady
	}
	if err := m.StateTable.CheckAppState(common.LocalID(app.LocalID()), state.Onboarding); err == nil {
		return "", state.ErrOnboarding
	}

	// change state of endnode app to onboarding before onboard
	if err := m.StateTable.ChangeAppState(state.Onboarding, common.LocalID(app.LocalID())); err != nil {
		return "", err
	}

	handleErr := func(err error) (string, error) {
		m.StateTable.ChangeAppState(state.WaitingOnboard, common.LocalID(app.LocalID()))
		return "", err
	}
	gwID, err := m.onboardGateway(app, true)
	if err != nil {
		return handleErr(err)
	}

	// change state of endnode app to DoneOnboard after onboard
	if err := m.StateTable.ChangeAppState(state.DoneOnboard, common.LocalID(app.LocalID())); err != nil {
		return handleErr(err)
	}

	return gwID, nil
}
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 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")
	}

}
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)
	}
}
// 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")
		}
	}
}
Beispiel #19
0
// 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
}