[TASK] Remove nodes without links from graph.json (#22)

* [TASK] [models] graph.json should only save nodes with links

* [TASK] [models] graph.json should only save nodes with links and there main mac (with tests)
This commit is contained in:
Geno 2017-03-06 09:52:39 +01:00 committed by GitHub
parent d5aa4772a0
commit 12a09716fc
5 changed files with 86 additions and 28 deletions

View File

@ -34,6 +34,7 @@ type GraphLink struct {
// GraphBuilder a temporaty struct during fill the graph from the node neighbours // GraphBuilder a temporaty struct during fill the graph from the node neighbours
type graphBuilder struct { type graphBuilder struct {
macToID map[string]string // mapping from MAC address to node id macToID map[string]string // mapping from MAC address to node id
idToMac map[string]string // mapping from node id to one MAC address
links map[string]*GraphLink // mapping from $idA-$idB to existing link links map[string]*GraphLink // mapping from $idA-$idB to existing link
vpn map[string]interface{} // IDs/addresses of VPN servers vpn map[string]interface{} // IDs/addresses of VPN servers
} }
@ -42,11 +43,14 @@ type graphBuilder struct {
func (nodes *Nodes) BuildGraph() *Graph { func (nodes *Nodes) BuildGraph() *Graph {
builder := &graphBuilder{ builder := &graphBuilder{
macToID: make(map[string]string), macToID: make(map[string]string),
idToMac: make(map[string]string),
links: make(map[string]*GraphLink), links: make(map[string]*GraphLink),
vpn: make(map[string]interface{}), vpn: make(map[string]interface{}),
} }
nodes.RLock()
builder.readNodes(nodes.List) builder.readNodes(nodes.List)
nodes.RUnlock()
graph := &Graph{Version: 1} graph := &Graph{Version: 1}
graph.Batadv.Directed = false graph.Batadv.Directed = false
@ -63,6 +67,10 @@ func (builder *graphBuilder) readNodes(nodes map[string]*Node) {
builder.vpn[sourceID] = nil builder.vpn[sourceID] = nil
} }
if len(nodeinfo.Network.Mac) > 0 {
builder.macToID[sourceID] = nodeinfo.Network.Mac
}
// Batman neighbours // Batman neighbours
for _, batinterface := range nodeinfo.Network.Mesh { for _, batinterface := range nodeinfo.Network.Mesh {
interfaces := batinterface.Interfaces interfaces := batinterface.Interfaces
@ -107,34 +115,49 @@ func (builder *graphBuilder) readNodes(nodes map[string]*Node) {
} }
} }
func (builder *graphBuilder) extract() ([]*GraphNode, []*GraphLink) { type graphNodeCache struct {
links := make([]*GraphLink, len(builder.links)) idToMac map[string]string
nodes := make([]*GraphNode, len(builder.macToID)) idToIndex map[string]int
idToIndex := make(map[string]int) count int
Nodes []*GraphNode
}
// collect nodes and create mapping to index func newGraphNodeCache(idToMac map[string]string) *graphNodeCache {
i := 0 return &graphNodeCache{
for mac, nodeID := range builder.macToID { idToMac: idToMac,
nodes[i] = &GraphNode{ idToIndex: make(map[string]int),
ID: mac, }
}
func (gn *graphNodeCache) getIndex(nodeID string) int {
index, ok := gn.idToIndex[nodeID]
if !ok {
node := &GraphNode{
ID: gn.idToMac[nodeID],
NodeID: nodeID, NodeID: nodeID,
} }
idToIndex[nodeID] = i gn.Nodes = append(gn.Nodes, node)
i++ gn.idToIndex[nodeID] = gn.count
index = gn.count
gn.count++
}
return index
} }
func (builder *graphBuilder) extract() ([]*GraphNode, []*GraphLink) {
links := make([]*GraphLink, len(builder.links))
cache := newGraphNodeCache(builder.idToMac)
// collect links // collect links
i = 0 i := 0
for key, link := range builder.links { for key, link := range builder.links {
pos := strings.IndexByte(key, '-') pos := strings.IndexByte(key, '-')
link.Source = cache.getIndex(key[:pos])
link.Source = idToIndex[key[:pos]] link.Target = cache.getIndex(key[pos+1:])
link.Target = idToIndex[key[pos+1:]]
links[i] = link links[i] = link
i++ i++
} }
return cache.Nodes, links
return nodes, links
} }
func (builder *graphBuilder) isVPN(ids ...string) bool { func (builder *graphBuilder) isVPN(ids ...string) bool {

View File

@ -17,15 +17,16 @@ type TestNode struct {
func TestGenerateGraph(t *testing.T) { func TestGenerateGraph(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
nodes := testGetNodesByFile("node1.json", "node2.json", "node3.json") nodes := testGetNodesByFile("node1.json", "node2.json", "node3.json", "node4.json")
graph := nodes.BuildGraph() graph := nodes.BuildGraph()
assert.NotNil(graph) assert.NotNil(graph)
assert.Equal(1, graph.Version, "Wrong Version") assert.Equal(1, graph.Version, "Wrong Version")
assert.NotNil(graph.Batadv, "no Batadv") assert.NotNil(graph.Batadv, "no Batadv")
assert.Equal(false, graph.Batadv.Directed, "directed batadv") assert.Equal(false, graph.Batadv.Directed, "directed batadv")
assert.Equal(3, len(graph.Batadv.Nodes), "wrong Nodes count") assert.Len(graph.Batadv.Links, 3, "wrong Links count")
assert.Equal(2, len(graph.Batadv.Links), "wrong Links count") assert.Equal(4, testNodesCountWithLinks(graph.Batadv.Links), "wrong unneed nodes in graph")
assert.Len(graph.Batadv.Nodes, 4, "wrong Nodes count")
// TODO more tests required // TODO more tests required
} }
@ -65,3 +66,12 @@ func testfile(name string, obj interface{}) {
panic(err) panic(err)
} }
} }
func testNodesCountWithLinks(links []*GraphLink) int {
indexMap := make(map[int]bool)
for _, l := range links {
indexMap[l.Source] = true
indexMap[l.Target] = true
}
return len(indexMap)
}

View File

@ -33,7 +33,7 @@ func TestExpire(t *testing.T) {
nodes.expire() nodes.expire()
// one expired? // one expired?
assert.Equal(2, len(nodes.List)) assert.Len(nodes.List, 2)
assert.Nil(nodes.List["expire"]) assert.Nil(nodes.List["expire"])
// one offline? // one offline?
@ -58,13 +58,13 @@ func TestLoadAndSave(t *testing.T) {
save(nodes, tmpfile.Name()) save(nodes, tmpfile.Name())
os.Remove(tmpfile.Name()) os.Remove(tmpfile.Name())
assert.Equal(1, len(nodes.List)) assert.Len(nodes.List, 1)
} }
func TestUpdateNodes(t *testing.T) { func TestUpdateNodes(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
nodes := &Nodes{List: make(map[string]*Node)} nodes := &Nodes{List: make(map[string]*Node)}
assert.Equal(0, len(nodes.List)) assert.Len(nodes.List, 0)
res := &data.ResponseData{ res := &data.ResponseData{
Neighbours: &data.Neighbours{}, Neighbours: &data.Neighbours{},
@ -73,5 +73,5 @@ func TestUpdateNodes(t *testing.T) {
} }
nodes.Update("abcdef012345", res) nodes.Update("abcdef012345", res)
assert.Equal(1, len(nodes.List)) assert.Len(nodes.List, 1)
} }

View File

@ -17,12 +17,12 @@ func TestGlobalStats(t *testing.T) {
assert.EqualValues(25, stats.Clients) assert.EqualValues(25, stats.Clients)
// check models // check models
assert.EqualValues(2, len(stats.Models)) assert.Len(stats.Models, 2)
assert.EqualValues(2, stats.Models["TP-Link 841"]) assert.EqualValues(2, stats.Models["TP-Link 841"])
assert.EqualValues(1, stats.Models["Xeon Multi-Core"]) assert.EqualValues(1, stats.Models["Xeon Multi-Core"])
// check firmwares // check firmwares
assert.EqualValues(1, len(stats.Firmwares)) assert.Len(stats.Firmwares, 1)
assert.EqualValues(1, stats.Firmwares["2016.1.6+entenhausen1"]) assert.EqualValues(1, stats.Firmwares["2016.1.6+entenhausen1"])
fields := stats.Fields() fields := stats.Fields()
@ -35,13 +35,13 @@ func TestNodesV1(t *testing.T) {
nodes := createTestNodes().GetNodesV1() nodes := createTestNodes().GetNodesV1()
assert := assert.New(t) assert := assert.New(t)
assert.Equal(2, len(nodes.List)) assert.Len(nodes.List, 2)
} }
func TestNodesV2(t *testing.T) { func TestNodesV2(t *testing.T) {
nodes := createTestNodes().GetNodesV2() nodes := createTestNodes().GetNodesV2()
assert := assert.New(t) assert := assert.New(t)
assert.Equal(2, len(nodes.List)) assert.Len(nodes.List, 2)
} }
func createTestNodes() *Nodes { func createTestNodes() *Nodes {

25
models/testdata/node4.json vendored Normal file
View File

@ -0,0 +1,25 @@
{
"nodeinfo":{
"node_id":"node4.json",
"network":{
"mesh":{
"bat0":{
"interfaces":{
"wireless":["unneed","unneed2"],
"tunnel":["d"]
}
}
}
}
},
"neighbours":{
"batadv":{
"d":{
"neighbours":{
"a":{"tq":200,"lastseen":0.42}
}
}
}
}
}