Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

237 řádky
6.0 KiB

  1. package bridge
  2. import (
  3. "encoding/json"
  4. "testing"
  5. "time"
  6. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  7. "github.com/AFASystems/presence/internal/pkg/model"
  8. )
  9. // TestHelper provides utility functions for testing
  10. type TestHelper struct {
  11. t *testing.T
  12. appState *appcontext.AppState
  13. }
  14. // NewTestHelper creates a new test helper instance
  15. func NewTestHelper(t *testing.T) *TestHelper {
  16. return &TestHelper{
  17. t: t,
  18. appState: appcontext.NewAppState(),
  19. }
  20. }
  21. // GetAppState returns the appState instance
  22. func (th *TestHelper) GetAppState() *appcontext.AppState {
  23. return th.appState
  24. }
  25. // AddTestBeacon adds a beacon with the given MAC and ID to the lookup
  26. func (th *TestHelper) AddTestBeacon(mac, id string) {
  27. th.appState.AddBeaconToLookup(mac, id)
  28. }
  29. // CreateRawReading creates a test RawReading with default values
  30. func (th *TestHelper) CreateRawReading(mac string, rssi int) model.RawReading {
  31. return model.RawReading{
  32. Timestamp: time.Now().Format(time.RFC3339),
  33. Type: "BLE",
  34. MAC: mac,
  35. RSSI: rssi,
  36. RawData: "0201060302A0",
  37. }
  38. }
  39. // CreateRawReadingWithCustomData creates a test RawReading with custom raw data
  40. func (th *TestHelper) CreateRawReadingWithCustomData(mac string, rssi int, rawData string) model.RawReading {
  41. return model.RawReading{
  42. Timestamp: time.Now().Format(time.RFC3339),
  43. Type: "BLE",
  44. MAC: mac,
  45. RSSI: rssi,
  46. RawData: rawData,
  47. }
  48. }
  49. // CreateGatewayReading creates a Gateway type reading
  50. func (th *TestHelper) CreateGatewayReading(mac string) model.RawReading {
  51. return model.RawReading{
  52. Timestamp: time.Now().Format(time.RFC3339),
  53. Type: "Gateway",
  54. MAC: mac,
  55. RSSI: -50,
  56. RawData: "020106",
  57. }
  58. }
  59. // MarshalReadings marshals a slice of readings to JSON
  60. func (th *TestHelper) MarshalReadings(readings []model.RawReading) []byte {
  61. data, err := json.Marshal(readings)
  62. if err != nil {
  63. th.t.Fatalf("Failed to marshal readings: %v", err)
  64. }
  65. return data
  66. }
  67. // CreateMQTTMessage creates a complete MQTT message with readings
  68. func (th *TestHelper) CreateMQTTMessage(topic string, readings []model.RawReading) (string, []byte) {
  69. data := th.MarshalReadings(readings)
  70. return topic, data
  71. }
  72. // AssertBeaconAdvertisement asserts that a beacon advertisement matches expected values
  73. func (th *TestHelper) AssertBeaconAdvertisement(adv model.BeaconAdvertisement, expectedID, expectedHostname, expectedMAC string, expectedRSSI int64) {
  74. if adv.ID != expectedID {
  75. th.t.Errorf("Expected ID '%s', got '%s'", expectedID, adv.ID)
  76. }
  77. if adv.Hostname != expectedHostname {
  78. th.t.Errorf("Expected hostname '%s', got '%s'", expectedHostname, adv.Hostname)
  79. }
  80. if adv.MAC != expectedMAC {
  81. th.t.Errorf("Expected MAC '%s', got '%s'", expectedMAC, adv.MAC)
  82. }
  83. if adv.RSSI != expectedRSSI {
  84. th.t.Errorf("Expected RSSI %d, got %d", expectedRSSI, adv.RSSI)
  85. }
  86. }
  87. // GenerateTestMAC generates a test MAC address from an index
  88. func GenerateTestMAC(index int) string {
  89. return "AA:BB:CC:DD:" + toHex(index>>8) + ":" + toHex(index&0xFF)
  90. }
  91. // GenerateTestID generates a test beacon ID from an index
  92. func GenerateTestID(index int) string {
  93. return "test-beacon-" + toHex(index)
  94. }
  95. // toHex converts a number to a 2-digit hex string
  96. func toHex(n int) string {
  97. return formatInt(n, 16)
  98. }
  99. // Helper function to format int as hex string
  100. func formatInt(n, base int) string {
  101. const digits = "0123456789ABCDEF"
  102. if n == 0 {
  103. return "00"
  104. }
  105. result := ""
  106. for n > 0 {
  107. remainder := n % base
  108. result = string(digits[remainder]) + result
  109. n = n / base
  110. }
  111. // Pad to 2 digits
  112. for len(result) < 2 {
  113. result = "0" + result
  114. }
  115. return result
  116. }
  117. // CreateMockMessage creates a mock MQTT message for testing
  118. type MockMessage struct {
  119. topic string
  120. payload []byte
  121. }
  122. // NewMockMessage creates a new mock message
  123. func NewMockMessage(topic string, payload []byte) *MockMessage {
  124. return &MockMessage{
  125. topic: topic,
  126. payload: payload,
  127. }
  128. }
  129. // Topic returns the message topic
  130. func (m *MockMessage) Topic() string {
  131. return m.topic
  132. }
  133. // Payload returns the message payload
  134. func (m *MockMessage) Payload() []byte {
  135. return m.payload
  136. }
  137. // Asserted returns a flag (not used in mock)
  138. func (m *MockMessage) Asserted() bool {
  139. return false
  140. }
  141. // Duplicate returns a flag (not used in mock)
  142. func (m *MockMessage) Duplicate() bool {
  143. return false
  144. }
  145. // QoS returns the QoS level (not used in mock)
  146. func (m *MockMessage) QoS() byte {
  147. return 0
  148. }
  149. // Retained returns retained flag (not used in mock)
  150. func (m *MockMessage) Retained() bool {
  151. return false
  152. }
  153. // MessageID returns message ID (not used in mock)
  154. func (m *MockMessage) MessageID() uint16 {
  155. return 0
  156. }
  157. // SetupTestBeacons configures the appState with a standard set of test beacons
  158. func SetupTestBeacons(appState *appcontext.AppState) {
  159. beacons := []struct {
  160. mac string
  161. id string
  162. }{
  163. {"AA:BB:CC:DD:EE:FF", "beacon-1"},
  164. {"11:22:33:44:55:66", "beacon-2"},
  165. {"77:88:99:AA:BB:CC", "beacon-3"},
  166. {"DD:EE:FF:00:11:22", "beacon-4"},
  167. }
  168. for _, b := range beacons {
  169. appState.AddBeaconToLookup(b.mac, b.id)
  170. }
  171. }
  172. // CreateTestReadings creates a slice of test readings
  173. func CreateTestReadings(count int) []model.RawReading {
  174. readings := make([]model.RawReading, count)
  175. for i := 0; i < count; i++ {
  176. readings[i] = model.RawReading{
  177. Timestamp: time.Now().Format(time.RFC3339),
  178. Type: "BLE",
  179. MAC: GenerateTestMAC(i),
  180. RSSI: -60 - i,
  181. RawData: "0201060302A0",
  182. }
  183. }
  184. return readings
  185. }
  186. // CleanupTestState cleans up the appState lookup
  187. func CleanupTestState(appState *appcontext.AppState) {
  188. appState.CleanLookup()
  189. }
  190. // AssertKafkaMessageCount asserts that the mock writer received the expected number of messages
  191. func AssertKafkaMessageCount(t *testing.T, writer *MockKafkaWriter, expected int) {
  192. if len(writer.Messages) != expected {
  193. t.Errorf("Expected %d Kafka message(s), got %d", expected, len(writer.Messages))
  194. }
  195. }
  196. // AssertNoKafkaMessages asserts that no messages were written to Kafka
  197. func AssertNoKafkaMessages(t *testing.T, writer *MockKafkaWriter) {
  198. AssertKafkaMessageCount(t, writer, 0)
  199. }