dashboard_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package dashboard
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/flashmob/go-guerrilla/log"
  7. "github.com/gorilla/websocket"
  8. "net/url"
  9. "os"
  10. "regexp"
  11. "strings"
  12. "sync"
  13. "testing"
  14. "time"
  15. )
  16. var testlog log.Logger
  17. func init() {
  18. testlog, _ = log.GetLogger(log.OutputOff.String(), log.InfoLevel.String())
  19. }
  20. func TestRunStop(t *testing.T) {
  21. config := &Config{
  22. Enabled: true,
  23. ListenInterface: ":8082",
  24. TickInterval: "5s",
  25. MaxWindow: "24h",
  26. RankingUpdateInterval: "6h",
  27. }
  28. var wg sync.WaitGroup
  29. wg.Add(1)
  30. go func() {
  31. Run(config, testlog)
  32. wg.Done()
  33. }()
  34. // give Run some time to start
  35. time.Sleep(time.Second)
  36. Stop()
  37. // Wait for Run() to exit
  38. wg.Wait()
  39. }
  40. // Test if starting with a bad interface address
  41. func TestRunStopBadAddress(t *testing.T) {
  42. config := &Config{
  43. Enabled: true,
  44. ListenInterface: "1.1.1.1:0",
  45. TickInterval: "5s",
  46. MaxWindow: "24h",
  47. RankingUpdateInterval: "6h",
  48. }
  49. var wg sync.WaitGroup
  50. wg.Add(1)
  51. go func() {
  52. Run(config, testlog)
  53. wg.Done()
  54. }()
  55. time.Sleep(time.Second * 2)
  56. Stop()
  57. // Wait for Run() to exit
  58. wg.Wait()
  59. }
  60. // Run a simulation from an already captured log
  61. func TestSimulationRun(t *testing.T) {
  62. config := &Config{
  63. Enabled: true,
  64. ListenInterface: ":8082",
  65. TickInterval: "1s",
  66. MaxWindow: "24h",
  67. RankingUpdateInterval: "6h",
  68. }
  69. var wg sync.WaitGroup
  70. wg.Add(1)
  71. go func() {
  72. Run(config, testlog)
  73. wg.Done()
  74. }()
  75. // give Run some time to start
  76. time.Sleep(time.Second)
  77. simulateEvents(t)
  78. Stop()
  79. // Wait for Run() to exit
  80. wg.Wait()
  81. }
  82. func simulateEvents(t *testing.T) {
  83. file, err := os.Open("simulation.log")
  84. if err != nil {
  85. panic(err.Error())
  86. }
  87. defer file.Close()
  88. reader := bufio.NewReader(file)
  89. scanner := bufio.NewScanner(reader)
  90. scanner.Split(bufio.ScanLines)
  91. testlog.AddHook(LogHook)
  92. // match with quotes or without, ie. time="..." or level=
  93. r := regexp.MustCompile(`(.+?)=("[^"]*"|\S*)\s*`)
  94. simStart := time.Now()
  95. var start time.Time
  96. for scanner.Scan() {
  97. fields := map[string]interface{}{}
  98. line := scanner.Text()
  99. items := r.FindAllString(line, -1)
  100. msg := ""
  101. var logElapsed time.Duration
  102. for i := range items {
  103. key, val := parseItem(items[i])
  104. //fmt.Println(key, val)
  105. if key != "time" && key != "level" && key != "msg" {
  106. fields[key] = val
  107. }
  108. if key == "msg" {
  109. msg = val
  110. }
  111. if key == "time" {
  112. tv, err := time.Parse(time.RFC3339, val)
  113. if err != nil {
  114. t.Error("invalid time", tv)
  115. }
  116. if start.IsZero() {
  117. start = tv
  118. }
  119. fields["start"] = start
  120. logElapsed = tv.Sub(start)
  121. }
  122. }
  123. diff := time.Now().Sub(simStart) - logElapsed
  124. time.Sleep(diff) // wait so that we don't go too fast
  125. simStart = simStart.Add(diff) // catch up
  126. testlog.WithFields(fields).Info(msg)
  127. }
  128. }
  129. // parseItem parses a log item, eg time="2017-03-24T11:55:44+11:00" will be:
  130. // key = time and val will be 2017-03-24T11:55:44+11:00
  131. func parseItem(item string) (key string, val string) {
  132. arr := strings.Split(item, "=")
  133. if len(arr) == 2 {
  134. key = arr[0]
  135. if arr[1][0:1] == "\"" {
  136. pos := len(arr[1]) - 2
  137. val = arr[1][1:pos]
  138. } else {
  139. val = arr[1]
  140. }
  141. }
  142. val = strings.TrimSpace(val)
  143. return
  144. }
  145. // Run a simulation from an already captured log
  146. // Then open a websocket and validate that we are getting some data from it
  147. func TestWebsocket(t *testing.T) {
  148. config := &Config{
  149. Enabled: true,
  150. ListenInterface: "127.0.0.1:8082",
  151. TickInterval: "1s",
  152. MaxWindow: "24h",
  153. RankingUpdateInterval: "6h",
  154. }
  155. var wg sync.WaitGroup
  156. wg.Add(1)
  157. go func() {
  158. Run(config, testlog)
  159. wg.Done()
  160. }()
  161. var simWg sync.WaitGroup
  162. go func() {
  163. simWg.Add(1)
  164. simulateEvents(t)
  165. simWg.Done()
  166. }()
  167. time.Sleep(time.Second)
  168. // lets talk to the websocket
  169. u := url.URL{Scheme: "ws", Host: "127.0.0.1:8082", Path: "/ws"}
  170. c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
  171. if err != nil {
  172. t.Error("cant conect':", err)
  173. return
  174. }
  175. simWg.Add(1)
  176. go func() {
  177. defer func() {
  178. simWg.Done()
  179. }()
  180. i := 0
  181. for {
  182. c.SetReadDeadline(time.Now().Add(time.Second + 5))
  183. _, msg, err := c.ReadMessage()
  184. if err != nil {
  185. fmt.Println("socket err:", err)
  186. t.Error("websocket failed to connect")
  187. return
  188. }
  189. var objmap map[string]*json.RawMessage
  190. json.Unmarshal(msg, &objmap)
  191. if pl, ok := objmap["payload"]; ok {
  192. df := &dataFrame{}
  193. json.Unmarshal(*pl, &df)
  194. if df.NClients.Y > 10 && len(df.TopHelo) > 10 && len(df.TopDomain) > 10 && len(df.TopIP) > 10 {
  195. return
  196. }
  197. }
  198. fmt.Println("recv:", string(msg))
  199. i++
  200. if i > 2 {
  201. t.Error("Websocket did get find expected result")
  202. return
  203. }
  204. }
  205. }()
  206. simWg.Wait() // wait for sim to exit, wait for websocket to finish reading
  207. Stop()
  208. // Wait for Run() to exit
  209. wg.Wait()
  210. c.Close()
  211. }