dashboard_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. // run test
  78. simulateEvents(t)
  79. Stop()
  80. // Wait for Run() to exit
  81. wg.Wait()
  82. }
  83. func simulateEvents(t *testing.T) {
  84. file, err := os.OpenFile("simulation.log", os.O_CREATE|os.O_RDWR, 0644)
  85. if err != nil {
  86. panic(err.Error())
  87. }
  88. defer func() {
  89. if err := file.Close(); err != nil {
  90. t.Error(err)
  91. }
  92. if err := os.Remove("simulation.log"); err != nil {
  93. t.Error(err)
  94. }
  95. }()
  96. reader := bufio.NewReader(file)
  97. scanner := bufio.NewScanner(reader)
  98. scanner.Split(bufio.ScanLines)
  99. testlog.AddHook(LogHook)
  100. // match with quotes or without, ie. time="..." or level=
  101. r := regexp.MustCompile(`(.+?)=("[^"]*"|\S*)\s*`)
  102. simStart := time.Now()
  103. var start time.Time
  104. for scanner.Scan() {
  105. fields := map[string]interface{}{}
  106. line := scanner.Text()
  107. items := r.FindAllString(line, -1)
  108. msg := ""
  109. var logElapsed time.Duration
  110. for i := range items {
  111. key, val := parseItem(items[i])
  112. //fmt.Println(key, val)
  113. if key != "time" && key != "level" && key != "msg" {
  114. fields[key] = val
  115. }
  116. if key == "msg" {
  117. msg = val
  118. }
  119. if key == "time" {
  120. tv, err := time.Parse(time.RFC3339, val)
  121. if err != nil {
  122. t.Error("invalid time", tv)
  123. }
  124. if start.IsZero() {
  125. start = tv
  126. }
  127. fields["start"] = start
  128. logElapsed = tv.Sub(start)
  129. }
  130. }
  131. diff := time.Now().Sub(simStart) - logElapsed
  132. time.Sleep(diff) // wait so that we don't go too fast
  133. simStart = simStart.Add(diff) // catch up
  134. testlog.WithFields(fields).Info(msg)
  135. }
  136. }
  137. // parseItem parses a log item, eg time="2017-03-24T11:55:44+11:00" will be:
  138. // key = time and val will be 2017-03-24T11:55:44+11:00
  139. func parseItem(item string) (key string, val string) {
  140. arr := strings.Split(item, "=")
  141. if len(arr) == 2 {
  142. key = arr[0]
  143. if arr[1][0:1] == "\"" {
  144. pos := len(arr[1]) - 2
  145. val = arr[1][1:pos]
  146. } else {
  147. val = arr[1]
  148. }
  149. }
  150. val = strings.TrimSpace(val)
  151. return
  152. }
  153. // Run a simulation from an already captured log
  154. // Then open a websocket and validate that we are getting some data from it
  155. func TestWebsocket(t *testing.T) {
  156. config := &Config{
  157. Enabled: true,
  158. ListenInterface: "127.0.0.1:8082",
  159. TickInterval: "1s",
  160. MaxWindow: "24h",
  161. RankingUpdateInterval: "6h",
  162. }
  163. var wg sync.WaitGroup
  164. wg.Add(1)
  165. go func() {
  166. Run(config, testlog)
  167. wg.Done()
  168. }()
  169. var simWg sync.WaitGroup
  170. go func() {
  171. simWg.Add(1)
  172. simulateEvents(t)
  173. simWg.Done()
  174. }()
  175. time.Sleep(time.Second)
  176. // lets talk to the websocket
  177. u := url.URL{Scheme: "ws", Host: "127.0.0.1:8082", Path: "/ws"}
  178. c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
  179. if err != nil {
  180. t.Error("cant connect':", err)
  181. return
  182. }
  183. simWg.Add(1)
  184. go func() {
  185. defer func() {
  186. simWg.Done()
  187. }()
  188. i := 0
  189. for {
  190. if err := c.SetReadDeadline(time.Now().Add(time.Second + 5)); err != nil {
  191. t.Error(err)
  192. }
  193. _, msg, err := c.ReadMessage()
  194. s := string(msg)
  195. _ = s
  196. if err != nil {
  197. fmt.Println("socket err:", err)
  198. t.Error("websocket failed to connect")
  199. return
  200. }
  201. var objmap map[string]*json.RawMessage
  202. if err := json.Unmarshal(msg, &objmap); err != nil {
  203. t.Error(err)
  204. }
  205. if pl, ok := objmap["payload"]; ok {
  206. if i == 0 {
  207. ifr := &initFrame{}
  208. if err := json.Unmarshal(*pl, &ifr); err != nil {
  209. t.Error(err, i)
  210. }
  211. // initial data frame
  212. } else {
  213. df := &dataFrame{}
  214. if err := json.Unmarshal(*pl, &df); err != nil {
  215. t.Error(err, i)
  216. }
  217. if df.NClients.Y > 10 && len(df.TopHelo) > 10 && len(df.TopDomain) > 10 && len(df.TopIP) > 10 {
  218. return
  219. }
  220. }
  221. }
  222. fmt.Println("recv:", string(msg))
  223. i++
  224. if i > 2 {
  225. //t.Error("websocket did get find expected result", i)
  226. return
  227. }
  228. }
  229. }()
  230. simWg.Wait() // wait for sim to exit, wait for websocket to finish reading
  231. Stop()
  232. // Wait for Run() to exit
  233. wg.Wait()
  234. if err := c.Close(); err != nil {
  235. t.Error(err)
  236. }
  237. }