Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

322 rindas
8.5 KiB

  1. package decoder
  2. import (
  3. "context"
  4. "testing"
  5. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  6. "github.com/AFASystems/presence/internal/pkg/model"
  7. "github.com/segmentio/kafka-go"
  8. )
  9. // MockKafkaWriter is a mock implementation of kafkaWriter for testing
  10. type MockKafkaWriter struct {
  11. Messages []kafka.Message
  12. }
  13. func (m *MockKafkaWriter) WriteMessages(ctx context.Context, msgs ...kafka.Message) error {
  14. m.Messages = append(m.Messages, msgs...)
  15. return nil
  16. }
  17. // TestHelper provides utility functions for decoder testing
  18. type TestHelper struct {
  19. t *testing.T
  20. appState *appcontext.AppState
  21. parserRegistry *model.ParserRegistry
  22. }
  23. // NewTestHelper creates a new test helper instance
  24. func NewTestHelper(t *testing.T) *TestHelper {
  25. return &TestHelper{
  26. t: t,
  27. appState: appcontext.NewAppState(),
  28. parserRegistry: &model.ParserRegistry{},
  29. }
  30. }
  31. // GetAppState returns the appState instance
  32. func (th *TestHelper) GetAppState() *appcontext.AppState {
  33. return th.appState
  34. }
  35. // GetParserRegistry returns the parser registry
  36. func (th *TestHelper) GetParserRegistry() *model.ParserRegistry {
  37. return th.parserRegistry
  38. }
  39. // RegisterTestParser registers a parser with default test configuration
  40. func (th *TestHelper) RegisterTestParser(name string) {
  41. config := model.Config{
  42. Name: name,
  43. Min: 2,
  44. Max: 20,
  45. Pattern: []string{"02"},
  46. Configs: map[string]model.ParserConfig{
  47. "length": {Length: 2, Offset: 0, Order: "big"},
  48. },
  49. }
  50. th.parserRegistry.Register(name, config)
  51. }
  52. // CreateBeaconAdvertisement creates a test beacon advertisement
  53. func (th *TestHelper) CreateBeaconAdvertisement(id, data string) model.BeaconAdvertisement {
  54. return model.BeaconAdvertisement{
  55. ID: id,
  56. Data: data,
  57. }
  58. }
  59. // CreateValidHexAdvertisement creates a beacon with valid hex data
  60. func (th *TestHelper) CreateValidHexAdvertisement(id string) model.BeaconAdvertisement {
  61. return model.BeaconAdvertisement{
  62. ID: id,
  63. Data: "020106",
  64. }
  65. }
  66. // CreateInvalidHexAdvertisement creates a beacon with invalid hex data
  67. func (th *TestHelper) CreateInvalidHexAdvertisement(id string) model.BeaconAdvertisement {
  68. return model.BeaconAdvertisement{
  69. ID: id,
  70. Data: "INVALID_HEX",
  71. }
  72. }
  73. // CreateEmptyAdvertisement creates a beacon with empty data
  74. func (th *TestHelper) CreateEmptyAdvertisement(id string) model.BeaconAdvertisement {
  75. return model.BeaconAdvertisement{
  76. ID: id,
  77. Data: "",
  78. }
  79. }
  80. // AssertParserExists asserts that a parser exists in the registry
  81. func (th *TestHelper) AssertParserExists(name string) {
  82. if _, exists := th.parserRegistry.ParserList[name]; !exists {
  83. th.t.Errorf("Parser '%s' should exist in registry", name)
  84. }
  85. }
  86. // AssertParserNotExists asserts that a parser does not exist in the registry
  87. func (th *TestHelper) AssertParserNotExists(name string) {
  88. if _, exists := th.parserRegistry.ParserList[name]; exists {
  89. th.t.Errorf("Parser '%s' should not exist in registry", name)
  90. }
  91. }
  92. // AssertEventExists asserts that an event exists in appState
  93. func (th *TestHelper) AssertEventExists(id string) model.BeaconEvent {
  94. event, exists := th.appState.GetBeaconEvent(id)
  95. if !exists {
  96. th.t.Errorf("Event for beacon '%s' should exist in appState", id)
  97. return model.BeaconEvent{}
  98. }
  99. return event
  100. }
  101. // AssertEventNotExists asserts that an event does not exist in appState
  102. func (th *TestHelper) AssertEventNotExists(id string) {
  103. _, exists := th.appState.GetBeaconEvent(id)
  104. if exists {
  105. th.t.Errorf("Event for beacon '%s' should not exist in appState", id)
  106. }
  107. }
  108. // AssertParserCount asserts the number of parsers in the registry
  109. func (th *TestHelper) AssertParserCount(expected int) {
  110. if len(th.parserRegistry.ParserList) != expected {
  111. th.t.Errorf("Expected %d parsers in registry, got %d", expected, len(th.parserRegistry.ParserList))
  112. }
  113. }
  114. // Helper functions for creating test configurations
  115. // CreateTestConfig creates a test parser configuration
  116. func CreateTestConfig(name string, min, max int, pattern []string) model.Config {
  117. return model.Config{
  118. Name: name,
  119. Min: min,
  120. Max: max,
  121. Pattern: pattern,
  122. Configs: map[string]model.ParserConfig{
  123. "length": {Length: 2, Offset: 0, Order: "big"},
  124. },
  125. }
  126. }
  127. // CreateKafkaParserMessage creates a Kafka parser message for testing
  128. func CreateKafkaParserMessage(id, name string, config model.Config) model.KafkaParser {
  129. return model.KafkaParser{
  130. ID: id,
  131. Name: name,
  132. Config: config,
  133. }
  134. }
  135. // AssertNoError asserts that an error is nil
  136. func AssertNoError(t *testing.T, err error, msg string) {
  137. if err != nil {
  138. t.Errorf("%s: %v", msg, err)
  139. }
  140. }
  141. // AssertError asserts that an error is not nil
  142. func AssertError(t *testing.T, err error, msg string) {
  143. if err == nil {
  144. t.Errorf("%s: expected error but got nil", msg)
  145. }
  146. }
  147. // Common test data
  148. // Valid hex strings for testing
  149. var ValidHexStrings = []string{
  150. "020106", // Simple AD structure
  151. "0201060302A0", // AD structure with flags
  152. "1AFF0C01", // iBeacon-like data
  153. "0201061AFF0C01", // Multiple AD structures
  154. }
  155. // Invalid hex strings for testing
  156. var InvalidHexStrings = []string{
  157. "INVALID_HEX",
  158. "02016ZZZ",
  159. "GGGGGG",
  160. "NOT-HEX",
  161. }
  162. // Empty or whitespace data for testing
  163. var EmptyTestData = []string{
  164. "",
  165. " ",
  166. "\t\n",
  167. }
  168. // CreateMockWriter creates a mock Kafka writer
  169. func CreateMockWriter() *MockKafkaWriter {
  170. return &MockKafkaWriter{Messages: []kafka.Message{}}
  171. }
  172. // Beacon event test helpers
  173. // AssertEventFields asserts that event fields match expected values
  174. func AssertEventFields(t *testing.T, event model.BeaconEvent, expectedID, expectedType string) {
  175. if event.ID != expectedID {
  176. t.Errorf("Expected event ID '%s', got '%s'", expectedID, event.ID)
  177. }
  178. if event.Type != expectedType {
  179. t.Errorf("Expected event type '%s', got '%s'", expectedType, event.Type)
  180. }
  181. }
  182. // SetupTestParsers registers a standard set of test parsers
  183. func SetupTestParsers(registry *model.ParserRegistry) {
  184. parsers := []model.Config{
  185. {Name: "parser-1", Min: 2, Max: 20, Pattern: []string{"02"}},
  186. {Name: "parser-2", Min: 3, Max: 25, Pattern: []string{"03"}},
  187. {Name: "parser-3", Min: 4, Max: 30, Pattern: []string{"04"}},
  188. }
  189. for _, p := range parsers {
  190. registry.Register(p.Name, p)
  191. }
  192. }
  193. // CleanupTestParsers removes all parsers from the registry
  194. func CleanupTestParsers(registry *model.ParserRegistry) {
  195. for name := range registry.ParserList {
  196. registry.Unregister(name)
  197. }
  198. }
  199. // CreateTestBeaconEvent creates a test beacon event
  200. func CreateTestBeaconEvent(id, eventType string) model.BeaconEvent {
  201. return model.BeaconEvent{
  202. ID: id,
  203. Type: eventType,
  204. Battery: 100,
  205. Event: 1,
  206. AccX: 0,
  207. AccY: 0,
  208. AccZ: 0,
  209. }
  210. }
  211. // AssertKafkaMessageCount asserts the number of Kafka messages
  212. func AssertKafkaMessageCount(t *testing.T, writer *MockKafkaWriter, expected int) {
  213. if len(writer.Messages) != expected {
  214. t.Errorf("Expected %d Kafka message(s), got %d", expected, len(writer.Messages))
  215. }
  216. }
  217. // AssertNoKafkaMessages asserts that no messages were written to Kafka
  218. func AssertNoKafkaMessages(t *testing.T, writer *MockKafkaWriter) {
  219. AssertKafkaMessageCount(t, writer, 0)
  220. }
  221. // Parser registry test helpers
  222. // SimulateEventLoopParserUpdate simulates the event loop's parser update logic
  223. func SimulateEventLoopParserUpdate(msg model.KafkaParser, registry *model.ParserRegistry) {
  224. switch msg.ID {
  225. case "add":
  226. config := msg.Config
  227. registry.Register(config.Name, config)
  228. case "delete":
  229. registry.Unregister(msg.Name)
  230. case "update":
  231. config := msg.Config
  232. registry.Register(config.Name, config)
  233. }
  234. }
  235. // CreateParserAddMessage creates a parser add message
  236. func CreateParserAddMessage(name string, min, max int) model.KafkaParser {
  237. return model.KafkaParser{
  238. ID: "add",
  239. Name: name,
  240. Config: model.Config{
  241. Name: name,
  242. Min: min,
  243. Max: max,
  244. Pattern: []string{"02"},
  245. },
  246. }
  247. }
  248. // CreateParserDeleteMessage creates a parser delete message
  249. func CreateParserDeleteMessage(name string) model.KafkaParser {
  250. return model.KafkaParser{
  251. ID: "delete",
  252. Name: name,
  253. }
  254. }
  255. // CreateParserUpdateMessage creates a parser update message
  256. func CreateParserUpdateMessage(name string, min, max int) model.KafkaParser {
  257. return model.KafkaParser{
  258. ID: "update",
  259. Name: name,
  260. Config: model.Config{
  261. Name: name,
  262. Min: min,
  263. Max: max,
  264. Pattern: []string{"02"},
  265. },
  266. }
  267. }
  268. // GenerateTestBeaconID generates a test beacon ID
  269. func GenerateTestBeaconID(index int) string {
  270. return "test-beacon-" + string(rune('A'+index))
  271. }
  272. // GenerateTestHexData generates test hex data
  273. func GenerateTestHexData(index int) string {
  274. prefix := "02"
  275. value := string(rune('6' + index))
  276. return prefix + "01" + value
  277. }