valkey_test.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package valkey
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "os"
  6. "testing"
  7. "github.com/TecharoHQ/anubis/lib/store/storetest"
  8. "github.com/testcontainers/testcontainers-go"
  9. "github.com/testcontainers/testcontainers-go/wait"
  10. )
  11. func TestImpl(t *testing.T) {
  12. if os.Getenv("DONT_USE_NETWORK") != "" {
  13. t.Skip("test requires network egress")
  14. return
  15. }
  16. testcontainers.SkipIfProviderIsNotHealthy(t)
  17. valkeyC, err := testcontainers.Run(
  18. t.Context(), "valkey/valkey:8",
  19. testcontainers.WithExposedPorts("6379/tcp"),
  20. testcontainers.WithWaitStrategy(
  21. wait.ForListeningPort("6379/tcp"),
  22. wait.ForLog("Ready to accept connections"),
  23. ),
  24. )
  25. testcontainers.CleanupContainer(t, valkeyC)
  26. if err != nil {
  27. t.Fatal(err)
  28. }
  29. endpoint, err := valkeyC.PortEndpoint(t.Context(), "6379/tcp", "redis")
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. data, err := json.Marshal(Config{
  34. URL: endpoint,
  35. })
  36. if err != nil {
  37. t.Fatal(err)
  38. }
  39. storetest.Common(t, Factory{}, json.RawMessage(data))
  40. }
  41. func TestFactoryValid(t *testing.T) {
  42. tests := []struct {
  43. name string
  44. jsonData string
  45. expectError error
  46. }{
  47. {
  48. name: "empty config",
  49. jsonData: `{}`,
  50. expectError: ErrNoURL,
  51. },
  52. {
  53. name: "valid URL only",
  54. jsonData: `{"url": "redis://localhost:6379"}`,
  55. expectError: nil,
  56. },
  57. {
  58. name: "invalid URL",
  59. jsonData: `{"url": "invalid-url"}`,
  60. expectError: ErrBadURL,
  61. },
  62. {
  63. name: "valid sentinel config",
  64. jsonData: `{"sentinel": {"masterName": "mymaster", "addr": ["localhost:26379"], "password": "mypass"}}`,
  65. expectError: nil,
  66. },
  67. {
  68. name: "sentinel missing masterName",
  69. jsonData: `{"sentinel": {"addr": ["localhost:26379"], "password": "mypass"}}`,
  70. expectError: ErrSentinelMasterNameRequired,
  71. },
  72. {
  73. name: "sentinel missing addr",
  74. jsonData: `{"sentinel": {"masterName": "mymaster", "password": "mypass"}}`,
  75. expectError: ErrSentinelAddrRequired,
  76. },
  77. {
  78. name: "sentinel empty addr",
  79. jsonData: `{"sentinel": {"masterName": "mymaster", "addr": [""], "password": "mypass"}}`,
  80. expectError: ErrSentinelAddrEmpty,
  81. },
  82. {
  83. name: "sentinel missing password",
  84. jsonData: `{"sentinel": {"masterName": "mymaster", "addr": ["localhost:26379"]}}`,
  85. expectError: nil,
  86. },
  87. {
  88. name: "sentinel with optional fields",
  89. jsonData: `{"sentinel": {"masterName": "mymaster", "addr": ["localhost:26379"], "password": "mypass", "clientName": "myclient", "username": "myuser"}}`,
  90. expectError: nil,
  91. },
  92. {
  93. name: "sentinel single address (not array)",
  94. jsonData: `{"sentinel": {"masterName": "mymaster", "addr": "localhost:26379", "password": "mypass"}}`,
  95. expectError: nil,
  96. },
  97. {
  98. name: "sentinel mixed empty and valid addresses",
  99. jsonData: `{"sentinel": {"masterName": "mymaster", "addr": ["", "localhost:26379", ""], "password": "mypass"}}`,
  100. expectError: nil,
  101. },
  102. }
  103. for _, tt := range tests {
  104. t.Run(tt.name, func(t *testing.T) {
  105. factory := Factory{}
  106. err := factory.Valid(json.RawMessage(tt.jsonData))
  107. if tt.expectError == nil {
  108. if err != nil {
  109. t.Errorf("expected no error, got: %v", err)
  110. }
  111. } else {
  112. if err == nil {
  113. t.Errorf("expected error %v, got nil", tt.expectError)
  114. } else if !errors.Is(err, tt.expectError) {
  115. t.Errorf("expected error %v, got: %v", tt.expectError, err)
  116. }
  117. }
  118. })
  119. }
  120. }