diff --git a/cmd/serve.go b/cmd/serve.go index 153f0d9..42a6a9b 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -38,7 +38,8 @@ var serveCmd = &cobra.Command{ if config.Webserver.Enable { log.Println("starting webserver on", config.Webserver.Bind) srv := webserver.New(config.Webserver.Bind, config.Webserver.Webroot) - go srv.Close() + go webserver.Start(srv) + defer srv.Close() } if config.Respondd.Enable { diff --git a/database/all/internel_test.go b/database/all/internel_test.go new file mode 100644 index 0000000..1a6c647 --- /dev/null +++ b/database/all/internel_test.go @@ -0,0 +1 @@ +package all diff --git a/database/database_test.go b/database/database_test.go new file mode 100644 index 0000000..f6f39b7 --- /dev/null +++ b/database/database_test.go @@ -0,0 +1,18 @@ +package database + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNow(t *testing.T) { + assert := assert.New(t) + assert.Len(Adapters, 0) + + RegisterAdapter("blub", func(config interface{}) (Connection, error) { + return nil, nil + }) + + assert.Len(Adapters, 1) +} diff --git a/database/logging/file_test.go b/database/logging/file_test.go new file mode 100644 index 0000000..2b43acc --- /dev/null +++ b/database/logging/file_test.go @@ -0,0 +1 @@ +package logging diff --git a/rrd/rrd_test.go b/rrd/rrd_test.go new file mode 100644 index 0000000..1f2dba9 --- /dev/null +++ b/rrd/rrd_test.go @@ -0,0 +1 @@ +package rrd diff --git a/runtime/config_test.go b/runtime/config_test.go index a5110a3..9183b7c 100644 --- a/runtime/config_test.go +++ b/runtime/config_test.go @@ -36,4 +36,12 @@ func TestReadConfig(t *testing.T) { assert.Len(dbs, 1, "more graphitedb are given") graphitedb = dbs[0].(map[string]interface{}) assert.Equal(graphitedb["address"], "localhost:2003") + + _, err = ReadConfigFile("testdata/config_failed.toml") + assert.Error(err, "not unmarshalable") + assert.Contains(err.Error(), "Near line ") + + _, err = ReadConfigFile("testdata/adsa.toml") + assert.Error(err, "not found able") + assert.Contains(err.Error(), "no such file or directory") } diff --git a/runtime/duration_test.go b/runtime/duration_test.go index d1a76b8..340fe47 100644 --- a/runtime/duration_test.go +++ b/runtime/duration_test.go @@ -44,4 +44,14 @@ func TestDuration(t *testing.T) { assert.EqualError(err, test.err) } } + + d := Duration{} + err := d.UnmarshalTOML(3) + assert.Error(err) + assert.Contains(err.Error(), "invalid duration") + + err = d.UnmarshalTOML("am") + assert.Error(err) + assert.Contains(err.Error(), "unable to parse duration") + } diff --git a/runtime/node_test.go b/runtime/node_test.go new file mode 100644 index 0000000..00c696e --- /dev/null +++ b/runtime/node_test.go @@ -0,0 +1,24 @@ +package runtime + +import ( + "testing" + + "github.com/FreifunkBremen/yanic/data" + "github.com/stretchr/testify/assert" +) + +func TestNode(t *testing.T) { + assert := assert.New(t) + + node := &Node{} + assert.False(node.IsGateway()) + + node.Nodeinfo = &data.NodeInfo{} + assert.False(node.IsGateway()) + + node.Nodeinfo.VPN = true + assert.True(node.IsGateway()) + + node.Nodeinfo.VPN = false + assert.False(node.IsGateway()) +} diff --git a/runtime/nodes_test.go b/runtime/nodes_test.go index d8c583e..7104b0f 100644 --- a/runtime/nodes_test.go +++ b/runtime/nodes_test.go @@ -9,13 +9,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/FreifunkBremen/yanic/data" + "github.com/FreifunkBremen/yanic/jsontime" ) func TestExpire(t *testing.T) { assert := assert.New(t) config := &Config{} config.Nodes.OfflineAfter.Duration = time.Minute * 10 - config.Nodes.PruneAfter.Duration = time.Hour * 24 * 6 + // to get default (100%) path of testing + // config.Nodes.PruneAfter.Duration = time.Hour * 24 * 6 nodes := &Nodes{ config: config, List: make(map[string]*Node), @@ -27,9 +29,9 @@ func TestExpire(t *testing.T) { nodes.Update("online", &data.ResponseData{}) // should stay online expire := nodes.List["expire"] - expire.Lastseen = expire.Lastseen.Add((-6 * time.Hour * 24) - time.Minute) + expire.Lastseen = expire.Lastseen.Add((-7 * time.Hour * 24) - time.Minute) offline := nodes.List["offline"] - offline.Lastseen = offline.Lastseen.Add((-6 * time.Hour * 24) + time.Minute) + offline.Lastseen = offline.Lastseen.Add((-7 * time.Hour * 24) + time.Minute) nodes.expire() @@ -50,16 +52,37 @@ func TestLoadAndSave(t *testing.T) { assert := assert.New(t) config := &Config{} - config.Nodes.StatePath = "testdata/nodes.json" + // not autoload without StatePath + NewNodes(config) + // Test unmarshalable /dev/null - autolead with StatePath + config.Nodes.StatePath = "/dev/null" nodes := NewNodes(config) + // Test unopen able + config.Nodes.StatePath = "/root/nodes.json" + nodes.load() + // works ;) + config.Nodes.StatePath = "testdata/nodes.json" nodes.load() tmpfile, _ := ioutil.TempFile("/tmp", "nodes") - SaveJSON(nodes, tmpfile.Name()) + config.Nodes.StatePath = tmpfile.Name() + nodes.save() os.Remove(tmpfile.Name()) - assert.Len(nodes.List, 1) + assert.PanicsWithValue("open /dev/null.tmp: permission denied", func() { + SaveJSON(nodes, "/dev/null") + }) + + tmpfile, _ = ioutil.TempFile("/tmp", "nodes") + assert.PanicsWithValue("json: unsupported type: func() string", func() { + SaveJSON(tmpfile.Name, tmpfile.Name()) + }) + os.Remove(tmpfile.Name()) + + //TODO how to test easy a failing renaming + + assert.Len(nodes.List, 2) } func TestUpdateNodes(t *testing.T) { @@ -72,10 +95,97 @@ func TestUpdateNodes(t *testing.T) { res := &data.ResponseData{ Neighbours: &data.Neighbours{}, - Statistics: &data.Statistics{}, - NodeInfo: &data.NodeInfo{}, + Statistics: &data.Statistics{ + Wireless: data.WirelessStatistics{ + &data.WirelessAirtime{}, + }, + }, + NodeInfo: &data.NodeInfo{}, } nodes.Update("abcdef012345", res) + // Update wireless statistics by running SetUtilization + nodes.Update("abcdef012345", res) + assert.Len(nodes.List, 1) } + +func TestSelectNodes(t *testing.T) { + assert := assert.New(t) + + config := &Config{} + config.Nodes.StatePath = "testdata/nodes.json" + + nodes := NewNodes(config) + + selectedNodes := nodes.Select(func(n *Node) bool { + return true + }) + assert.Len(selectedNodes, 2) + + selectedNodes = nodes.Select(func(n *Node) bool { + return false + }) + assert.Len(selectedNodes, 0) + + selectedNodes = nodes.Select(func(n *Node) bool { + return n.Nodeinfo.NodeID == "f4f26dd7a30a" + }) + assert.Len(selectedNodes, 1) + time := jsontime.Time{} + time.UnmarshalJSON([]byte("2017-03-10T12:12:01")) + assert.Equal(time, selectedNodes[0].Firstseen) +} + +func TestLinksNodes(t *testing.T) { + assert := assert.New(t) + + nodes := &Nodes{ + List: make(map[string]*Node), + ifaceToNodeID: make(map[string]string), + } + assert.Len(nodes.List, 0) + + nodes.Update("f4f26dd7a30a", &data.ResponseData{ + NodeInfo: &data.NodeInfo{ + NodeID: "f4f26dd7a30a", + Network: data.Network{ + Mac: "f4:f2:6d:d7:a3:0a", + }, + }, + }) + + nodes.Update("f4f26dd7a30b", &data.ResponseData{ + NodeInfo: &data.NodeInfo{ + NodeID: "f4f26dd7a30b", + }, + Neighbours: &data.Neighbours{ + NodeID: "f4f26dd7a30b", + Batadv: map[string]data.BatadvNeighbours{ + "f4:f2:6d:d7:a3:0b": data.BatadvNeighbours{ + Neighbours: map[string]data.BatmanLink{ + "f4:f2:6d:d7:a3:0a": data.BatmanLink{ + Tq: 200, Lastseen: 0.42, + }, + }, + }, + }, + }, + }) + + node := nodes.List["f4f26dd7a30a"] + assert.NotNil(node) + links := nodes.NodeLinks(node) + assert.Len(links, 0) + + node = nodes.List["f4f26dd7a30b"] + assert.NotNil(node) + links = nodes.NodeLinks(node) + assert.Len(links, 1) + link := links[0] + assert.Equal(link.SourceID, "f4f26dd7a30b") + assert.Equal(link.SourceMAC, "f4:f2:6d:d7:a3:0b") + assert.Equal(link.TargetID, "f4f26dd7a30a") + assert.Equal(link.TargetMAC, "f4:f2:6d:d7:a3:0a") + assert.Equal(link.TQ, 200) +} diff --git a/runtime/testdata/config_failed.toml b/runtime/testdata/config_failed.toml new file mode 100644 index 0000000..0247eeb --- /dev/null +++ b/runtime/testdata/config_failed.toml @@ -0,0 +1 @@ +asdas diff --git a/runtime/testdata/nodes.json b/runtime/testdata/nodes.json index a7d7671..1cd51f2 100644 --- a/runtime/testdata/nodes.json +++ b/runtime/testdata/nodes.json @@ -1 +1,34 @@ -{"nodes": {"f4f26dd7a30a": {"firstseen": "2016-03-10T12:12:01"}}} +{ + "nodes": { + "f4f26dd7a30a": { + "firstseen": "2017-03-10T12:12:01", + "nodeinfo": { + "node_id":"f4f26dd7a30a", + "network":{ + "mesh":{ + "bat0":{ + "interfaces":{ + "wireless":["a"] + } + } + } + } + } + }, + "f4f26dd7a30b": { + "firstseen": "2016-03-10T12:12:01", + "nodeinfo": { + "node_id":"f4f26dd7a30b", + "network":{ + "mesh":{ + "bat0":{ + "interfaces":{ + "wireless":["a"] + } + } + } + } + } + } + } +} diff --git a/webserver/webserver.go b/webserver/webserver.go index 53af047..54e9dce 100644 --- a/webserver/webserver.go +++ b/webserver/webserver.go @@ -8,17 +8,15 @@ import ( // New creates a new webserver and starts it func New(bindAddr, webroot string) *http.Server { - srv := &http.Server{ + return &http.Server{ Addr: bindAddr, Handler: gziphandler.GzipHandler(http.FileServer(http.Dir(webroot))), } - - go func() { - // service connections - if err := srv.ListenAndServe(); err != nil { - panic(err) - } - }() - - return srv +} + +func Start(srv *http.Server) { + // service connections + if err := srv.ListenAndServe(); err != http.ErrServerClosed { + panic(err) + } } diff --git a/webserver/webserver_test.go b/webserver/webserver_test.go new file mode 100644 index 0000000..66d0e2b --- /dev/null +++ b/webserver/webserver_test.go @@ -0,0 +1,25 @@ +package webserver + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestWebserver(t *testing.T) { + assert := assert.New(t) + + srv := New(":8080", "/tmp") + assert.NotNil(srv) + + go Start(srv) + + time.Sleep(time.Millisecond * 200) + + assert.Panics(func() { + Start(srv) + }, "not allowed to listen twice") + + srv.Close() +}