[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:
parent
d5aa4772a0
commit
12a09716fc
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
25
models/testdata/node4.json
vendored
Normal 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}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user