analysis_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * Copyright (c) 2018, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package analysis
  20. import (
  21. "reflect"
  22. "testing"
  23. )
  24. func TestAllLogModelsAndSorting(t *testing.T) {
  25. l := parseLogsAndTestExpectations(logLinesWithExpectations(), t)
  26. logs, _ := l.SortLogModels(true, true, true)
  27. var prevLogCount uint
  28. for _, x := range logs {
  29. var count uint
  30. switch v := x.(type) {
  31. case MessageLogModelStats:
  32. count = v.Count
  33. case MetricsLogModelStats:
  34. count = v.Count
  35. case UnknownLogModelStats:
  36. count = v.Count
  37. default:
  38. t.Errorf("Encountered unexpected struct of type %v\n", reflect.TypeOf(v))
  39. }
  40. if prevLogCount != 0 && prevLogCount > count {
  41. t.Errorf("Expected list to be sorted in ascending order")
  42. }
  43. prevLogCount = count
  44. }
  45. }
  46. func TestMessageLogsWithErrorAndContext(t *testing.T) {
  47. logs := []LogLineWithExpectation{
  48. // The following messages should parse into 4 distinct log models
  49. messageLogExpectation(`{"msg":"a", "level":"info"}`),
  50. messageLogExpectation(`{"msg":"a", "level":"info"}`),
  51. messageLogExpectation(`{"msg":"a", "level":"info", "error": "b"}`),
  52. messageLogExpectation(`{"msg":"a", "level":"info", "error": "b"}`),
  53. messageLogExpectation(`{"msg":"a", "level":"info", "context": "c"}`),
  54. messageLogExpectation(`{"msg":"a", "level":"info", "context": "c"}`),
  55. messageLogExpectation(`{"msg":"a", "level":"info", "error": "b", "context": "c"}`),
  56. messageLogExpectation(`{"msg":"a", "level":"info", "error": "b", "context": "c"}`),
  57. // The following messages should parse into 2 distinct log models
  58. messageLogExpectation(`{"msg":"b", "level":"info", "error": "b"}`),
  59. messageLogExpectation(`{"msg":"b", "level":"info", "context": "b"}`),
  60. // The following messages should parse into 2 distinct log models
  61. messageLogExpectation(`{"msg":"c", "level":"info"}`),
  62. messageLogExpectation(`{"msg":"c", "level":"warning"}`),
  63. }
  64. l := parseLogsAndTestExpectations(logs, t)
  65. numLogModels := len(l.MessageLogModels.modelStats)
  66. expectedUniqueModels := 8
  67. if numLogModels != expectedUniqueModels {
  68. t.Errorf("Expected %d message log models but found %d\n", expectedUniqueModels, numLogModels)
  69. }
  70. }
  71. func TestMessageLogsWithRedactedIpAddresses(t *testing.T) {
  72. logs := []LogLineWithExpectation{
  73. // The following messages should parse into 1 distinct log model
  74. messageLogExpectation(`{"msg":"a", "level":"info", "error": "1.1.1.1->2.2.2.2"}`),
  75. messageLogExpectation(`{"msg":"a", "level":"info", "error": "3.3.3.3->4.4.4.4"}`),
  76. messageLogExpectation(`{"msg":"a", "level":"info", "error": "1.1.1.1->2.2.2.2:1"}`),
  77. messageLogExpectation(`{"msg":"a", "level":"info", "error": "1.1.1.1->2.2.2.2:65535"}`),
  78. }
  79. l := parseLogsAndTestExpectations(logs, t)
  80. numLogModels := len(l.MessageLogModels.modelStats)
  81. expectedUniqueModels := 1
  82. if numLogModels != expectedUniqueModels {
  83. t.Errorf("Expected %d message log models but found %d\n", expectedUniqueModels, numLogModels)
  84. }
  85. }
  86. // Helpers
  87. type LogLineWithExpectation struct {
  88. log string
  89. expects parseLineExpectation
  90. }
  91. type parseLineExpectation struct {
  92. error bool
  93. message bool
  94. metrics bool
  95. unknown bool
  96. }
  97. func parseLogsAndTestExpectations(expectations []LogLineWithExpectation, t *testing.T) (l *LogStats) {
  98. l = NewLogStats()
  99. for _, expectation := range expectations {
  100. snapshot := *l
  101. err := l.ParseLogLine(expectation.log)
  102. // Check that the expectation is valid
  103. if !(expectation.expects.error || expectation.expects.message ||
  104. expectation.expects.metrics || expectation.expects.unknown) {
  105. t.Errorf("Malformed expectation expects nothing")
  106. t.FailNow()
  107. }
  108. // Check error expectation
  109. if err != nil {
  110. if expectation.expects.error != true {
  111. t.Errorf("Unexpected error: < %s >, from log line: \"%s\"\n", err, expectation.log)
  112. }
  113. }
  114. // Check message expectation
  115. if expectation.expects.message {
  116. if l.MessageLogModels.Count != snapshot.MessageLogModels.Count+1 {
  117. t.Errorf("Expected message log from: \"%s\"\n", expectation.log)
  118. }
  119. }
  120. // Check metric expectation
  121. if expectation.expects.metrics {
  122. if l.MetricsLogModels.Count != snapshot.MetricsLogModels.Count+1 {
  123. t.Errorf("Expected metric log model from: \"%s\"\n", expectation.log)
  124. }
  125. }
  126. // Check unknown expectation
  127. if expectation.expects.unknown {
  128. if l.UnknownLogModels.Count != snapshot.UnknownLogModels.Count+1 {
  129. t.Errorf("Expected unknown log model from: \"%s\"\n", expectation.log)
  130. }
  131. }
  132. }
  133. return l
  134. }
  135. func logLinesWithExpectations() (l []LogLineWithExpectation) {
  136. l = []LogLineWithExpectation{
  137. // ************
  138. // Message logs
  139. // ************
  140. // Test collision of basic message logs
  141. messageLogExpectation(`{"msg":"a", "level":"info"}`),
  142. messageLogExpectation(`{"msg":"a", "level":"info"}`),
  143. // Different valid levels
  144. messageLogExpectation(`{"msg":"a", "level":"debug"}`),
  145. messageLogExpectation(`{"msg":"a", "level":"warning"}`),
  146. messageLogExpectation(`{"msg":"a", "level":"error"}`),
  147. // ************
  148. // Metrics logs
  149. // ************
  150. // Test collision of basic metrics logs
  151. metricsLogExpectation(`{"event_name":"a"}`),
  152. metricsLogExpectation(`{"event_name":"a"}`),
  153. // ************
  154. // Unknown logs
  155. // ************
  156. unknownLogExpectation(`{}`),
  157. unknownLogExpectation(`{"a":"b"}`),
  158. // Test collision of unknown logs with depth
  159. unknownLogExpectation(`{"a":{"b":[{"c":{}}]}}`),
  160. unknownLogExpectation(`{"a":{"b":[{"c":{}}]}}`),
  161. // Message log line missing level field
  162. unknownLogExpectation(`{"msg":"a"}`),
  163. // **************
  164. // Malformed logs
  165. // **************
  166. malformedLogExpectation(`{`),
  167. // Invalid message log levels
  168. malformedLogExpectation(`{"msg":"a", "level":"{"}`),
  169. malformedLogExpectation(`{"msg":"a", "level":"unknown"}`),
  170. }
  171. return l
  172. }
  173. func messageLogExpectation(log string) LogLineWithExpectation {
  174. return LogLineWithExpectation{
  175. log: log,
  176. expects: parseLineExpectation{
  177. message: true,
  178. },
  179. }
  180. }
  181. func metricsLogExpectation(log string) LogLineWithExpectation {
  182. return LogLineWithExpectation{
  183. log: log,
  184. expects: parseLineExpectation{
  185. metrics: true,
  186. },
  187. }
  188. }
  189. func unknownLogExpectation(log string) LogLineWithExpectation {
  190. return LogLineWithExpectation{
  191. log: log,
  192. expects: parseLineExpectation{
  193. unknown: true,
  194. },
  195. }
  196. }
  197. func malformedLogExpectation(log string) LogLineWithExpectation {
  198. return LogLineWithExpectation{
  199. log: log,
  200. expects: parseLineExpectation{
  201. error: true,
  202. },
  203. }
  204. }