Commit 49fc6cea authored by Michel Roy's avatar Michel Roy Committed by Kevin Di Lallo
Browse files

added node/edge getters

parent 4d1f2f06
Loading
Loading
Loading
Loading
+76 −36
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package model
import (
	"encoding/json"
	"errors"
	"reflect"
	"strings"

	ceModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model"
@@ -80,8 +81,8 @@ func NewModel(dbAddr string, module string, name string) (m *Model, err error) {
	return m, nil
}

// SetModel - Initialize model from JSON string
func (m *Model) SetModel(j []byte) (err error) {
// SetScenario - Initialize model from JSON string
func (m *Model) SetScenario(j []byte) (err error) {
	err = json.Unmarshal(j, m.scenario)
	if err != nil {
		log.Error(err.Error())
@@ -98,9 +99,10 @@ func (m *Model) SetModel(j []byte) (err error) {
	return nil
}

// GetModel - Get model pointer
func (m *Model) GetModel() *ceModel.Scenario {
	return m.scenario
// GetScenario - Get Scenario JSON string
func (m *Model) GetScenario() (j []byte, err error) {
	j, err = json.Marshal(m.scenario)
	return j, err
}

// Activate - Make scenario the active scenario
@@ -167,25 +169,6 @@ func (m *Model) Listen(handler func(string, string)) (err error) {
	return nil
}

func (m *Model) internalListener(channel string, payload string) {
	// An update was received - Update the object state and call the external Handler
	// Retrieve active scenario from DB
	j, err := m.rc.JSONGetEntry(activeScenarioKey, ".")
	log.Debug("Scenario Event:", j)
	if err != nil {
		// Scenario was deleted
		m.scenario = new(ceModel.Scenario)
		m.nodeMap = NewNodeMap()
		m.parseNodes()
		m.updateSvcMap()
	} else {
		m.SetModel([]byte(j))
	}

	// external listener
	m.listener(channel, payload)
}

// MoveNode - Move a specific UE in the scenario
func (m *Model) MoveNode(nodeName string, destName string) (oldLocName string, newLocName string, err error) {
	moveNode := m.nodeMap.FindByName(nodeName)
@@ -213,18 +196,6 @@ func (m *Model) MoveNode(nodeName string, destName string) (oldLocName string, n
	return oldLocName, newLocName, nil
}

//FindUE - return a UE
func (m *Model) FindUE(name string) (ue *ceModel.PhysicalLocation, err error) {
	ueNode := m.nodeMap.FindByName(name)
	// fmt.Printf("+++ ueNode: %+v\n", ueNode)
	if ueNode == nil {
		return nil, errors.New("Did not find ue " + name + " in scenario " + m.name)
	}
	ue = ueNode.object.(*ceModel.PhysicalLocation)
	return ue, nil

}

// GetServiceMaps - Extracts the model service maps
func (m *Model) GetServiceMaps() []ceModel.NodeServiceMaps {
	return m.svcMap
@@ -309,9 +280,59 @@ func (m *Model) UpdateNetChar(nc *ceModel.EventNetworkCharacteristicsUpdate) (er
		}
	}
	return nil
}

//GetScenarioName - Get the scenario name
func (m *Model) GetScenarioName() string {
	return m.scenario.Name
}

//GetNodeNames - Get the list of nodes of a certain type; "" or "ANY" returns all
func (m *Model) GetNodeNames(typ string) []string {
	var l int
	var nm map[string]*Node
	if typ == "" || typ == "ANY" {
		nm = m.nodeMap.nameMap
		l = len(nm)
	} else {
		nm = m.nodeMap.typeMap[typ]
		l = len(nm)
	}
	list := make([]string, 0, l)
	for k := range nm {
		list = append(list, k)
	}
	return list
}

//GetNodeEdges - Get a map of node edges for the current scenario
func (m *Model) GetEdges() (edgeMap map[string]string) {
	edgeMap = make(map[string]string)
	for k, node := range m.nodeMap.nameMap {
		p := reflect.ValueOf(node.parent)
		pName := reflect.Indirect(p).FieldByName("Name")
		if pName.IsValid() {
			edgeMap[k] = pName.String()
			// fmt.Printf("%s (%T) \t\t %s(%T)\n", k, node.object, pName, node.parent)
		}
	}
	return edgeMap
}

// GetNode - Get a node by its name
// 		Returned value is of type interface{}
//    Good practice: returned node should be type asserted with val,ok := node.(someType) to prevent panic
func (m *Model) GetNode(name string) (node interface{}) {
	node = nil
	n := m.nodeMap.nameMap[name]
	if n != nil {
		node = n.object
	}
	return node
}

//---Internal Funcs---

func (m *Model) parseNodes() (err error) {
	if m.scenario.Deployment != nil {
		if m.scenario.Deployment != nil {
@@ -499,3 +520,22 @@ func (m *Model) moveProc(node *Node, destName string) (oldLocName string, newLoc

	return oldPL.Name, newPL.Name, nil
}

func (m *Model) internalListener(channel string, payload string) {
	// An update was received - Update the object state and call the external Handler
	// Retrieve active scenario from DB
	j, err := m.rc.JSONGetEntry(activeScenarioKey, ".")
	log.Debug("Scenario Event:", j)
	if err != nil {
		// Scenario was deleted
		m.scenario = new(ceModel.Scenario)
		m.nodeMap = NewNodeMap()
		m.parseNodes()
		m.updateSvcMap()
	} else {
		m.SetScenario([]byte(j))
	}

	// external listener
	m.listener(channel, payload)
}
+154 −72
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package model

import (
	"encoding/json"
	"fmt"
	"testing"
	"time"
@@ -66,7 +65,7 @@ func TestNewModel(t *testing.T) {
	}
}

func TestGetSetModel(t *testing.T) {
func TestGetSetScenario(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

@@ -85,22 +84,25 @@ func TestGetSetModel(t *testing.T) {
	}

	fmt.Println("Set Model")
	err = m.SetModel([]byte(testScenario))
	err = m.SetScenario([]byte(testScenario))
	if err != nil {
		t.Errorf("Error setting model")
	}
	if m.scenario.Name != "demo1" {
		t.Errorf("SetModel failed")
		t.Errorf("SetScenario failed")
	}

	fmt.Println("Get Model")
	s := m.GetModel()
	if s == nil {
		t.Errorf("Error getting model")
	s, err := m.GetScenario()
	if err != nil {
		t.Errorf("Error getting scenario")
	}
	if s.Name != "demo1" {
		t.Errorf("GetModel failed")
	if s == nil {
		t.Errorf("Error getting scenario")
	}
	// if s.Name != "demo1" {
	// 	t.Errorf("GetModel failed")
	// }

	fmt.Println("GetSvcMap - existing")
	svcMap = m.GetServiceMaps()
@@ -110,9 +112,9 @@ func TestGetSetModel(t *testing.T) {

	fmt.Println("Set Model - deleted scenario")
	m.scenario = nil
	err = m.SetModel([]byte(testScenario))
	err = m.SetScenario([]byte(testScenario))
	if err == nil {
		t.Errorf("SetModel should have failed (nil scenario)")
		t.Errorf("SetScenario should have failed (nil scenario)")
	}
}

@@ -128,12 +130,12 @@ func TestActivateDeactivate(t *testing.T) {
		t.Errorf("Unable to create model")
	}
	fmt.Println("Set model")
	err = m.SetModel([]byte(testScenario))
	err = m.SetScenario([]byte(testScenario))
	if err != nil {
		t.Errorf("Error setting model")
	}
	if m.scenario.Name != "demo1" {
		t.Errorf("SetModel failed")
		t.Errorf("SetScenario failed")
	}
	fmt.Println("Activate model")
	err = m.Activate()
@@ -141,7 +143,7 @@ func TestActivateDeactivate(t *testing.T) {
		t.Errorf("Error activating model")
	}
	fmt.Println("Set model")
	err = m.SetModel([]byte(testScenario))
	err = m.SetScenario([]byte(testScenario))
	if err != nil {
		t.Errorf("Error updating model")
	}
@@ -164,12 +166,12 @@ func TestMoveNode(t *testing.T) {
		t.Errorf("Unable to create model")
	}
	fmt.Println("Set Model")
	err = m.SetModel([]byte(testScenario))
	err = m.SetScenario([]byte(testScenario))
	if err != nil {
		t.Errorf("Error setting model")
	}
	if m.scenario.Name != "demo1" {
		t.Errorf("SetModel failed")
		t.Errorf("SetScenario failed")
	}
	fmt.Println("Move ue1")
	old, new, err := m.MoveNode("ue1", "zone2-poa1")
@@ -287,50 +289,6 @@ func TestMoveNode(t *testing.T) {

}

func TestFindUE(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

	// Switch to a different table for testing
	redisTable = modelRedisTestTable

	m, err := NewModel(modelRedisAddr, "test-mod", modelName)
	if err != nil {
		t.Errorf("Unable to create model")
	}
	fmt.Println("Set Model")
	err = m.SetModel([]byte(testScenario))
	if err != nil {
		t.Errorf("Error setting model")
	}
	if m.scenario.Name != "demo1" {
		t.Errorf("SetModel failed")
	}

	fmt.Println("Find ue1")
	ue, err := m.FindUE("ue1")
	if err != nil {
		t.Errorf("Error finding UE")
	}
	if ue.Name != "ue1" {
		t.Errorf("Found wrong ue")
	}
	fmt.Println("Find ue2-ext")
	ue, err = m.FindUE("ue2-ext")
	if err != nil {
		t.Errorf("Error finding UE")
	}
	if ue.Name != "ue2-ext" {
		t.Errorf("Found wrong ue")
	}
	fmt.Println("Find Not-a-UE")
	ue, err = m.FindUE("Not-a-UE")
	if err == nil {
		t.Errorf("Found inexisting UE")
	}

}

func TestUpdateNetChar(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())
@@ -343,12 +301,12 @@ func TestUpdateNetChar(t *testing.T) {
		t.Errorf("Unable to create model")
	}
	fmt.Println("Set Model")
	err = m.SetModel([]byte(testScenario))
	err = m.SetScenario([]byte(testScenario))
	if err != nil {
		t.Errorf("Error setting model")
	}
	if m.scenario.Name != "demo1" {
		t.Errorf("SetModel failed")
		t.Errorf("SetScenario failed")
	}

	var nc ceModel.EventNetworkCharacteristicsUpdate
@@ -647,12 +605,18 @@ func TestListenModel(t *testing.T) {
	if err != nil {
		t.Errorf("Unable to create model")
	}
	if mPub.GetScenarioName() != "" {
		t.Errorf("Scenario name should be empty")
	}

	fmt.Println("Create Listener")
	mLis, err := NewModel(modelRedisAddr, moduleName+"-Lis", "Active")
	if err != nil {
		t.Errorf("Unable to create model")
	}
	if mLis.GetScenarioName() != "" {
		t.Errorf("Scenario name should be empty")
	}

	fmt.Println("Register listener (no handler)")
	err = mLis.Listen(nil)
@@ -671,26 +635,32 @@ func TestListenModel(t *testing.T) {
	fmt.Println("Activate")
	testCount++
	mPub.Activate()
	time.Sleep(time.Second)
	time.Sleep(50 * time.Millisecond)
	if eventCount != testCount {
		t.Errorf("No event received for Activate")
	}

	fmt.Println("Set Model")
	testCount++
	err = mPub.SetModel([]byte(testScenario))
	time.Sleep(time.Second)
	err = mPub.SetScenario([]byte(testScenario))
	time.Sleep(50 * time.Millisecond)
	if err != nil {
		t.Errorf("Error setting model")
	}
	if eventCount != testCount {
		t.Errorf("No event received for SetModel")
		t.Errorf("No event received for SetScenario")
	}
	lis, _ := json.Marshal(*(mLis.GetModel()).Deployment)
	pub, _ := json.Marshal(*mPub.GetModel().Deployment)
	lis, _ := mLis.GetScenario()
	pub, _ := mPub.GetScenario()
	if string(lis) != string(pub) {
		t.Errorf("Published model different than received one")
	}
	if mPub.GetScenarioName() != "demo1" {
		t.Errorf("Scenario name should be demo1")
	}
	if mLis.GetScenarioName() != "demo1" {
		t.Errorf("Scenario name should be demo1")
	}

	// MoveNode
	fmt.Println("Move ue1")
@@ -705,7 +675,7 @@ func TestListenModel(t *testing.T) {
	if new != "zone2-poa1" {
		t.Errorf("Move Node - wrong destination Location " + new)
	}
	time.Sleep(time.Second)
	time.Sleep(50 * time.Millisecond)
	if eventCount != testCount {
		t.Errorf("No event received for MoveUE")
	}
@@ -729,7 +699,7 @@ func TestListenModel(t *testing.T) {
	if err != nil {
		t.Errorf("Update " + nc.ElementType + " failed")
	}
	time.Sleep(time.Second)
	time.Sleep(50 * time.Millisecond)
	if eventCount != testCount {
		t.Errorf("No event received for UpdateNetChar")
	}
@@ -749,13 +719,35 @@ func TestListenModel(t *testing.T) {
	fmt.Println("Dectivate")
	testCount++
	mPub.Deactivate()
	time.Sleep(time.Second)
	time.Sleep(50 * time.Millisecond)
	if eventCount != testCount {
		t.Errorf("No event received for Activate")
	}
	if mLis.GetModel().Deployment != nil {
	lis, _ = mLis.GetScenario()
	if string(lis) != "{}" {
		t.Errorf("Deployment should be nil")
	}
	if mPub.GetScenarioName() != "demo1" {
		t.Errorf("Scenario name should be demo1")
	}
	if mLis.GetScenarioName() != "" {
		t.Errorf("Scenario name should be empty")
	}

	fmt.Println("Re-Activate")
	testCount++
	mPub.Activate()
	time.Sleep(50 * time.Millisecond)
	if eventCount != testCount {
		t.Errorf("No event received for Activate")
	}
	if mPub.GetScenarioName() != "demo1" {
		t.Errorf("Scenario name should be demo1")
	}
	if mLis.GetScenarioName() != "demo1" {
		t.Errorf("Scenario name should be demo1")
	}

}

var eventChannel string
@@ -768,3 +760,93 @@ func eventHandler(channel string, payload string) {
	eventCount++
	fmt.Println("Event#", eventCount, " ch:", channel)
}

func TestGetters(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

	// Switch to a different table for testing
	redisTable = modelRedisTestTable

	fmt.Println("Create Model")
	m, err := NewModel(modelRedisAddr, moduleName, modelName)
	if err != nil {
		t.Errorf("Unable to create model")
	}

	fmt.Println("Get Node Names (empty)")
	l := m.GetNodeNames("")
	if len(l) != 0 {
		t.Errorf("Node name list should be empty")
	}

	fmt.Println("Set Model")
	err = m.SetScenario([]byte(testScenario))
	if err != nil {
		t.Errorf("Error setting model")
	}

	fmt.Println("Get Node Names")
	l = m.GetNodeNames("ANY")
	if len(l) != 29 {
		t.Errorf("Node name list should not be empty")
	}
	fmt.Println(l)
	fmt.Println(len(l))

	fmt.Println("Get UE Node Names")
	l = m.GetNodeNames("UE")
	if len(l) != 2 {
		t.Errorf("UE node name list should be 2")
	}
	fmt.Println(l)
	fmt.Println(len(l))

	fmt.Println("Get POA Node Names")
	l = m.GetNodeNames("POA")
	if len(l) != 3 {
		t.Errorf("POA node name list should be 3")
	}
	fmt.Println(l)
	fmt.Println(len(l))

	fmt.Println("Get Zone Node Names")
	l = m.GetNodeNames("ZONE")
	if len(l) != 2 {
		t.Errorf("Zone node name list should be 2")
	}
	fmt.Println(l)
	fmt.Println(len(l))

	fmt.Println("Get invalid node")
	n := m.GetNode("NOT-A-NODE")
	if n != nil {
		t.Errorf("Node should not exist")
	}

	fmt.Println("Get ue1 node")
	n = m.GetNode("ue1")
	if n == nil {
		t.Errorf("Failed getting ue1 node")
	}
	pl, ok := n.(*ceModel.PhysicalLocation)
	if !ok {
		t.Errorf("ue1 has wrong type %T -- expected *model.PhysicalLocation", n)
	}
	if pl.Name != "ue1" {
		t.Errorf("Could not find ue1")
	}

	fmt.Println("Get edges")
	edges := m.GetEdges()
	if len(edges) != 27 {
		t.Errorf("Missing edges - expected 27")
	}
	if edges["ue1"] != "zone1-poa1" {
		t.Errorf("UE1 edge - expected zone1-poa1 -- got %s", edges["ue1"])
	}
	if edges["zone1"] != "operator1" {
		t.Errorf("Zone1 edge - expected operator1 -- got %s", edges["zone1"])
	}

}