mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-12 05:32:36 +00:00
Gofmt the codebase.
This commit is contained in:
@@ -39,7 +39,7 @@ func (suite *Tests) Test_PeriodicallyReloadBannedUsers() {
|
|||||||
bannedUsersIDsMutex.Lock()
|
bannedUsersIDsMutex.Lock()
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
bannedUsersIDsMutex.Unlock()
|
bannedUsersIDsMutex.Unlock()
|
||||||
|
|
||||||
// Execute reloader once
|
// Execute reloader once
|
||||||
go testPeriodicallyReloadBannedUsers()
|
go testPeriodicallyReloadBannedUsers()
|
||||||
<-done
|
<-done
|
||||||
@@ -52,7 +52,7 @@ func (suite *Tests) Test_PeriodicallyReloadBannedUsers() {
|
|||||||
bannedUsersIDsMutex.RLock()
|
bannedUsersIDsMutex.RLock()
|
||||||
mapSize := len(bannedUsersIDs)
|
mapSize := len(bannedUsersIDs)
|
||||||
bannedUsersIDsMutex.RUnlock()
|
bannedUsersIDsMutex.RUnlock()
|
||||||
|
|
||||||
// Verify map is still empty
|
// Verify map is still empty
|
||||||
assert.Equal(0, mapSize)
|
assert.Equal(0, mapSize)
|
||||||
})
|
})
|
||||||
@@ -83,7 +83,7 @@ func (suite *Tests) Test_PeriodicallyReloadBannedUsers() {
|
|||||||
value1 := bannedUsersIDs["test-user-reload-1"]
|
value1 := bannedUsersIDs["test-user-reload-1"]
|
||||||
value2 := bannedUsersIDs["test-user-reload-2"]
|
value2 := bannedUsersIDs["test-user-reload-2"]
|
||||||
bannedUsersIDsMutex.RUnlock()
|
bannedUsersIDsMutex.RUnlock()
|
||||||
|
|
||||||
// Verify banned users map was loaded
|
// Verify banned users map was loaded
|
||||||
assert.Equal(2, mapSize)
|
assert.Equal(2, mapSize)
|
||||||
assert.Equal("reason reload 1", value1)
|
assert.Equal("reason reload 1", value1)
|
||||||
@@ -114,7 +114,7 @@ func (suite *Tests) Test_PeriodicallyReloadBannedUsers() {
|
|||||||
mapSize := len(bannedUsersIDs)
|
mapSize := len(bannedUsersIDs)
|
||||||
initialValue := bannedUsersIDs["test-user-initial"]
|
initialValue := bannedUsersIDs["test-user-initial"]
|
||||||
bannedUsersIDsMutex.RUnlock()
|
bannedUsersIDsMutex.RUnlock()
|
||||||
|
|
||||||
// Verify initial data was loaded
|
// Verify initial data was loaded
|
||||||
assert.Equal(1, mapSize)
|
assert.Equal(1, mapSize)
|
||||||
assert.Equal("initial reason", initialValue)
|
assert.Equal("initial reason", initialValue)
|
||||||
@@ -139,7 +139,7 @@ func (suite *Tests) Test_PeriodicallyReloadBannedUsers() {
|
|||||||
value2 := bannedUsersIDs["test-user-updated-2"]
|
value2 := bannedUsersIDs["test-user-updated-2"]
|
||||||
_, exists := bannedUsersIDs["test-user-initial"]
|
_, exists := bannedUsersIDs["test-user-initial"]
|
||||||
bannedUsersIDsMutex.RUnlock()
|
bannedUsersIDsMutex.RUnlock()
|
||||||
|
|
||||||
// Verify updated data was loaded
|
// Verify updated data was loaded
|
||||||
assert.Equal(2, mapSize)
|
assert.Equal(2, mapSize)
|
||||||
assert.Equal("updated reason 1", value1)
|
assert.Equal("updated reason 1", value1)
|
||||||
@@ -228,4 +228,4 @@ func (suite *Tests) Test_LoadUnloadBannedUsers() {
|
|||||||
assert.Equal("reason4", reason4)
|
assert.Equal("reason4", reason4)
|
||||||
assert.False(user1Exists)
|
assert.False(user1Exists)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+78
-78
@@ -23,86 +23,86 @@ func (suite *Tests) Test_apiBanUser() {
|
|||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
||||||
|
|
||||||
// Create a test Fiber app
|
// Create a test Fiber app
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
app.Post("/api/user-ban", apiBanUser)
|
app.Post("/api/user-ban", apiBanUser)
|
||||||
|
|
||||||
// Test valid ban request
|
// Test valid ban request
|
||||||
suite.Run("valid ban request", func() {
|
suite.Run("valid ban request", func() {
|
||||||
// Clear banned users map
|
// Clear banned users map
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
|
|
||||||
reqBody := `{"user_id": "test-user-123", "reason": "testing"}`
|
reqBody := `{"user_id": "test-user-123", "reason": "testing"}`
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(200, resp.StatusCode)
|
assert.Equal(200, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "OK: user banned")
|
assert.Contains(string(body), "OK: user banned")
|
||||||
|
|
||||||
// Verify user was added to banned users map
|
// Verify user was added to banned users map
|
||||||
bannedUsersIDsMutex.RLock()
|
bannedUsersIDsMutex.RLock()
|
||||||
reason, exists := bannedUsersIDs["test-user-123"]
|
reason, exists := bannedUsersIDs["test-user-123"]
|
||||||
bannedUsersIDsMutex.RUnlock()
|
bannedUsersIDsMutex.RUnlock()
|
||||||
|
|
||||||
assert.True(exists)
|
assert.True(exists)
|
||||||
assert.Equal("testing", reason)
|
assert.Equal("testing", reason)
|
||||||
|
|
||||||
// Verify file was created
|
// Verify file was created
|
||||||
_, err = os.Stat(cfg.Api.BannedUsersFile)
|
_, err = os.Stat(cfg.Api.BannedUsersFile)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test missing user_id
|
// Test missing user_id
|
||||||
suite.Run("missing user_id", func() {
|
suite.Run("missing user_id", func() {
|
||||||
reqBody := `{"reason": "testing"}`
|
reqBody := `{"reason": "testing"}`
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(400, resp.StatusCode)
|
assert.Equal(400, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "user_id and reason are required")
|
assert.Contains(string(body), "user_id and reason are required")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test missing reason
|
// Test missing reason
|
||||||
suite.Run("missing reason", func() {
|
suite.Run("missing reason", func() {
|
||||||
reqBody := `{"user_id": "test-user-123"}`
|
reqBody := `{"user_id": "test-user-123"}`
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(400, resp.StatusCode)
|
assert.Equal(400, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "user_id and reason are required")
|
assert.Contains(string(body), "user_id and reason are required")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test invalid JSON
|
// Test invalid JSON
|
||||||
suite.Run("invalid JSON", func() {
|
suite.Run("invalid JSON", func() {
|
||||||
reqBody := `{"user_id": "test-user-123", "reason": }`
|
reqBody := `{"user_id": "test-user-123", "reason": }`
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
req := httptest.NewRequest(http.MethodPost, "/api/user-ban", bytes.NewBufferString(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(400, resp.StatusCode)
|
assert.Equal(400, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "Invalid request payload")
|
assert.Contains(string(body), "Invalid request payload")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
os.Remove(cfg.Api.BannedUsersFile)
|
os.Remove(cfg.Api.BannedUsersFile)
|
||||||
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
||||||
@@ -114,67 +114,67 @@ func (suite *Tests) Test_apiUnbanUser() {
|
|||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
||||||
|
|
||||||
// Create a test Fiber app
|
// Create a test Fiber app
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
app.Post("/api/user-unban", apiUnbanUser)
|
app.Post("/api/user-unban", apiUnbanUser)
|
||||||
|
|
||||||
// Test valid unban request
|
// Test valid unban request
|
||||||
suite.Run("valid unban request", func() {
|
suite.Run("valid unban request", func() {
|
||||||
// Add a user to the banned list
|
// Add a user to the banned list
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
bannedUsersIDs["test-user-123"] = "testing"
|
bannedUsersIDs["test-user-123"] = "testing"
|
||||||
|
|
||||||
reqBody := `{"user_id": "test-user-123"}`
|
reqBody := `{"user_id": "test-user-123"}`
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/user-unban", bytes.NewBufferString(reqBody))
|
req := httptest.NewRequest(http.MethodPost, "/api/user-unban", bytes.NewBufferString(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(200, resp.StatusCode)
|
assert.Equal(200, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "OK: user unbanned")
|
assert.Contains(string(body), "OK: user unbanned")
|
||||||
|
|
||||||
// Verify user was removed from banned users map
|
// Verify user was removed from banned users map
|
||||||
bannedUsersIDsMutex.RLock()
|
bannedUsersIDsMutex.RLock()
|
||||||
_, exists := bannedUsersIDs["test-user-123"]
|
_, exists := bannedUsersIDs["test-user-123"]
|
||||||
bannedUsersIDsMutex.RUnlock()
|
bannedUsersIDsMutex.RUnlock()
|
||||||
|
|
||||||
assert.False(exists)
|
assert.False(exists)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test missing user_id
|
// Test missing user_id
|
||||||
suite.Run("missing user_id", func() {
|
suite.Run("missing user_id", func() {
|
||||||
reqBody := `{}`
|
reqBody := `{}`
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/user-unban", bytes.NewBufferString(reqBody))
|
req := httptest.NewRequest(http.MethodPost, "/api/user-unban", bytes.NewBufferString(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(400, resp.StatusCode)
|
assert.Equal(400, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "user_id is required")
|
assert.Contains(string(body), "user_id is required")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test invalid JSON
|
// Test invalid JSON
|
||||||
suite.Run("invalid JSON", func() {
|
suite.Run("invalid JSON", func() {
|
||||||
reqBody := `{"user_id": }`
|
reqBody := `{"user_id": }`
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/user-unban", bytes.NewBufferString(reqBody))
|
req := httptest.NewRequest(http.MethodPost, "/api/user-unban", bytes.NewBufferString(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(400, resp.StatusCode)
|
assert.Equal(400, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "Invalid request payload")
|
assert.Contains(string(body), "Invalid request payload")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
os.Remove(cfg.Api.BannedUsersFile)
|
os.Remove(cfg.Api.BannedUsersFile)
|
||||||
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
||||||
@@ -185,33 +185,33 @@ func (suite *Tests) Test_apiClearCache() {
|
|||||||
cfg = &config{}
|
cfg = &config{}
|
||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
|
|
||||||
// Initialize cache
|
// Initialize cache
|
||||||
libpack_cache.EnableCache(&libpack_cache.CacheConfig{
|
libpack_cache.EnableCache(&libpack_cache.CacheConfig{
|
||||||
Logger: cfg.Logger,
|
Logger: cfg.Logger,
|
||||||
TTL: 60,
|
TTL: 60,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add some items to cache
|
// Add some items to cache
|
||||||
libpack_cache.CacheStore("test-key-1", []byte("test-value-1"))
|
libpack_cache.CacheStore("test-key-1", []byte("test-value-1"))
|
||||||
libpack_cache.CacheStore("test-key-2", []byte("test-value-2"))
|
libpack_cache.CacheStore("test-key-2", []byte("test-value-2"))
|
||||||
|
|
||||||
// Create a test Fiber app
|
// Create a test Fiber app
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
app.Post("/api/cache-clear", apiClearCache)
|
app.Post("/api/cache-clear", apiClearCache)
|
||||||
|
|
||||||
// Test cache clear
|
// Test cache clear
|
||||||
suite.Run("clear cache", func() {
|
suite.Run("clear cache", func() {
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/cache-clear", nil)
|
req := httptest.NewRequest(http.MethodPost, "/api/cache-clear", nil)
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(200, resp.StatusCode)
|
assert.Equal(200, resp.StatusCode)
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(body), "OK: cache cleared")
|
assert.Contains(string(body), "OK: cache cleared")
|
||||||
|
|
||||||
// Verify cache was cleared
|
// Verify cache was cleared
|
||||||
stats := libpack_cache.GetCacheStats()
|
stats := libpack_cache.GetCacheStats()
|
||||||
assert.Equal(int64(0), stats.CachedQueries)
|
assert.Equal(int64(0), stats.CachedQueries)
|
||||||
@@ -223,35 +223,35 @@ func (suite *Tests) Test_apiCacheStats() {
|
|||||||
cfg = &config{}
|
cfg = &config{}
|
||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
|
|
||||||
// Initialize cache
|
// Initialize cache
|
||||||
libpack_cache.EnableCache(&libpack_cache.CacheConfig{
|
libpack_cache.EnableCache(&libpack_cache.CacheConfig{
|
||||||
Logger: cfg.Logger,
|
Logger: cfg.Logger,
|
||||||
TTL: 60,
|
TTL: 60,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add some items to cache and perform lookups
|
// Add some items to cache and perform lookups
|
||||||
libpack_cache.CacheStore("test-key-1", []byte("test-value-1"))
|
libpack_cache.CacheStore("test-key-1", []byte("test-value-1"))
|
||||||
libpack_cache.CacheStore("test-key-2", []byte("test-value-2"))
|
libpack_cache.CacheStore("test-key-2", []byte("test-value-2"))
|
||||||
libpack_cache.CacheLookup("test-key-1") // Hit
|
libpack_cache.CacheLookup("test-key-1") // Hit
|
||||||
libpack_cache.CacheLookup("test-key-3") // Miss
|
libpack_cache.CacheLookup("test-key-3") // Miss
|
||||||
|
|
||||||
// Create a test Fiber app
|
// Create a test Fiber app
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
app.Get("/api/cache-stats", apiCacheStats)
|
app.Get("/api/cache-stats", apiCacheStats)
|
||||||
|
|
||||||
// Test get cache stats
|
// Test get cache stats
|
||||||
suite.Run("get cache stats", func() {
|
suite.Run("get cache stats", func() {
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/cache-stats", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/cache-stats", nil)
|
||||||
|
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(200, resp.StatusCode)
|
assert.Equal(200, resp.StatusCode)
|
||||||
|
|
||||||
var stats libpack_cache.CacheStats
|
var stats libpack_cache.CacheStats
|
||||||
err = json.NewDecoder(resp.Body).Decode(&stats)
|
err = json.NewDecoder(resp.Body).Decode(&stats)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
assert.Equal(int64(2), stats.CachedQueries)
|
assert.Equal(int64(2), stats.CachedQueries)
|
||||||
assert.Equal(int64(1), stats.CacheHits)
|
assert.Equal(int64(1), stats.CacheHits)
|
||||||
assert.Equal(int64(1), stats.CacheMisses)
|
assert.Equal(int64(1), stats.CacheMisses)
|
||||||
@@ -263,26 +263,26 @@ func (suite *Tests) Test_checkIfUserIsBanned() {
|
|||||||
cfg = &config{}
|
cfg = &config{}
|
||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
|
|
||||||
// Create a test Fiber app and context
|
// Create a test Fiber app and context
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
ctx := app.AcquireCtx(&fasthttp.RequestCtx{})
|
ctx := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||||
defer app.ReleaseCtx(ctx)
|
defer app.ReleaseCtx(ctx)
|
||||||
|
|
||||||
// Test with non-banned user
|
// Test with non-banned user
|
||||||
suite.Run("non-banned user", func() {
|
suite.Run("non-banned user", func() {
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
|
|
||||||
isBanned := checkIfUserIsBanned(ctx, "non-banned-user")
|
isBanned := checkIfUserIsBanned(ctx, "non-banned-user")
|
||||||
assert.False(isBanned)
|
assert.False(isBanned)
|
||||||
assert.Equal(200, ctx.Response().StatusCode())
|
assert.Equal(200, ctx.Response().StatusCode())
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with banned user
|
// Test with banned user
|
||||||
suite.Run("banned user", func() {
|
suite.Run("banned user", func() {
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
bannedUsersIDs["banned-user"] = "testing"
|
bannedUsersIDs["banned-user"] = "testing"
|
||||||
|
|
||||||
isBanned := checkIfUserIsBanned(ctx, "banned-user")
|
isBanned := checkIfUserIsBanned(ctx, "banned-user")
|
||||||
assert.True(isBanned)
|
assert.True(isBanned)
|
||||||
assert.Equal(403, ctx.Response().StatusCode())
|
assert.Equal(403, ctx.Response().StatusCode())
|
||||||
@@ -295,23 +295,23 @@ func (suite *Tests) Test_loadBannedUsers() {
|
|||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
||||||
|
|
||||||
// Test with non-existent file (should create it)
|
// Test with non-existent file (should create it)
|
||||||
suite.Run("non-existent file", func() {
|
suite.Run("non-existent file", func() {
|
||||||
// Remove file if it exists
|
// Remove file if it exists
|
||||||
os.Remove(cfg.Api.BannedUsersFile)
|
os.Remove(cfg.Api.BannedUsersFile)
|
||||||
|
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
loadBannedUsers()
|
loadBannedUsers()
|
||||||
|
|
||||||
// Verify file was created
|
// Verify file was created
|
||||||
_, err := os.Stat(cfg.Api.BannedUsersFile)
|
_, err := os.Stat(cfg.Api.BannedUsersFile)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
// Verify banned users map is empty
|
// Verify banned users map is empty
|
||||||
assert.Equal(0, len(bannedUsersIDs))
|
assert.Equal(0, len(bannedUsersIDs))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with existing file
|
// Test with existing file
|
||||||
suite.Run("existing file", func() {
|
suite.Run("existing file", func() {
|
||||||
// Create file with test data
|
// Create file with test data
|
||||||
@@ -322,29 +322,29 @@ func (suite *Tests) Test_loadBannedUsers() {
|
|||||||
data, _ := json.Marshal(testData)
|
data, _ := json.Marshal(testData)
|
||||||
err := os.WriteFile(cfg.Api.BannedUsersFile, data, 0644)
|
err := os.WriteFile(cfg.Api.BannedUsersFile, data, 0644)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
loadBannedUsers()
|
loadBannedUsers()
|
||||||
|
|
||||||
// Verify banned users map was loaded
|
// Verify banned users map was loaded
|
||||||
assert.Equal(2, len(bannedUsersIDs))
|
assert.Equal(2, len(bannedUsersIDs))
|
||||||
assert.Equal("reason 1", bannedUsersIDs["test-user-1"])
|
assert.Equal("reason 1", bannedUsersIDs["test-user-1"])
|
||||||
assert.Equal("reason 2", bannedUsersIDs["test-user-2"])
|
assert.Equal("reason 2", bannedUsersIDs["test-user-2"])
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with invalid JSON
|
// Test with invalid JSON
|
||||||
suite.Run("invalid JSON", func() {
|
suite.Run("invalid JSON", func() {
|
||||||
// Create file with invalid JSON
|
// Create file with invalid JSON
|
||||||
err := os.WriteFile(cfg.Api.BannedUsersFile, []byte("{invalid json}"), 0644)
|
err := os.WriteFile(cfg.Api.BannedUsersFile, []byte("{invalid json}"), 0644)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
bannedUsersIDs = make(map[string]string)
|
bannedUsersIDs = make(map[string]string)
|
||||||
loadBannedUsers()
|
loadBannedUsers()
|
||||||
|
|
||||||
// Verify banned users map is empty (load failed)
|
// Verify banned users map is empty (load failed)
|
||||||
assert.Equal(0, len(bannedUsersIDs))
|
assert.Equal(0, len(bannedUsersIDs))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
os.Remove(cfg.Api.BannedUsersFile)
|
os.Remove(cfg.Api.BannedUsersFile)
|
||||||
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
||||||
@@ -356,7 +356,7 @@ func (suite *Tests) Test_storeBannedUsers() {
|
|||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
cfg.Api.BannedUsersFile = filepath.Join(os.TempDir(), "banned_users_test.json")
|
||||||
|
|
||||||
// Test storing banned users
|
// Test storing banned users
|
||||||
suite.Run("store banned users", func() {
|
suite.Run("store banned users", func() {
|
||||||
// Set up test data
|
// Set up test data
|
||||||
@@ -364,23 +364,23 @@ func (suite *Tests) Test_storeBannedUsers() {
|
|||||||
"test-user-1": "reason 1",
|
"test-user-1": "reason 1",
|
||||||
"test-user-2": "reason 2",
|
"test-user-2": "reason 2",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := storeBannedUsers()
|
err := storeBannedUsers()
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
// Verify file was created with correct content
|
// Verify file was created with correct content
|
||||||
data, err := os.ReadFile(cfg.Api.BannedUsersFile)
|
data, err := os.ReadFile(cfg.Api.BannedUsersFile)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
var loadedData map[string]string
|
var loadedData map[string]string
|
||||||
err = json.Unmarshal(data, &loadedData)
|
err = json.Unmarshal(data, &loadedData)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
assert.Equal(2, len(loadedData))
|
assert.Equal(2, len(loadedData))
|
||||||
assert.Equal("reason 1", loadedData["test-user-1"])
|
assert.Equal("reason 1", loadedData["test-user-1"])
|
||||||
assert.Equal("reason 2", loadedData["test-user-2"])
|
assert.Equal("reason 2", loadedData["test-user-2"])
|
||||||
})
|
})
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
os.Remove(cfg.Api.BannedUsersFile)
|
os.Remove(cfg.Api.BannedUsersFile)
|
||||||
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
os.Remove(fmt.Sprintf("%s.lock", cfg.Api.BannedUsersFile))
|
||||||
@@ -392,17 +392,17 @@ func (suite *Tests) Test_lockFile() {
|
|||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
lockPath := filepath.Join(os.TempDir(), "test_lock_file.lock")
|
lockPath := filepath.Join(os.TempDir(), "test_lock_file.lock")
|
||||||
|
|
||||||
// Test locking a file
|
// Test locking a file
|
||||||
suite.Run("lock file", func() {
|
suite.Run("lock file", func() {
|
||||||
fileLock := flock.New(lockPath)
|
fileLock := flock.New(lockPath)
|
||||||
|
|
||||||
err := lockFile(fileLock)
|
err := lockFile(fileLock)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
// Verify file is locked
|
// Verify file is locked
|
||||||
assert.True(fileLock.Locked())
|
assert.True(fileLock.Locked())
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
fileLock.Unlock()
|
fileLock.Unlock()
|
||||||
})
|
})
|
||||||
@@ -414,17 +414,17 @@ func (suite *Tests) Test_lockFileRead() {
|
|||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
lockPath := filepath.Join(os.TempDir(), "test_lock_file_read.lock")
|
lockPath := filepath.Join(os.TempDir(), "test_lock_file_read.lock")
|
||||||
|
|
||||||
// Test read-locking a file
|
// Test read-locking a file
|
||||||
suite.Run("read lock file", func() {
|
suite.Run("read lock file", func() {
|
||||||
fileLock := flock.New(lockPath)
|
fileLock := flock.New(lockPath)
|
||||||
|
|
||||||
err := lockFileRead(fileLock)
|
err := lockFileRead(fileLock)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
// Verify file is locked - use RLocked() instead of Locked()
|
// Verify file is locked - use RLocked() instead of Locked()
|
||||||
assert.True(fileLock.RLocked())
|
assert.True(fileLock.RLocked())
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
fileLock.Unlock()
|
fileLock.Unlock()
|
||||||
})
|
})
|
||||||
@@ -436,8 +436,8 @@ func (suite *Tests) Test_enableApi() {
|
|||||||
cfg = &config{}
|
cfg = &config{}
|
||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Server.EnableApi = false
|
cfg.Server.EnableApi = false
|
||||||
|
|
||||||
// This should return immediately without error
|
// This should return immediately without error
|
||||||
enableApi()
|
enableApi()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+60
-60
@@ -16,7 +16,7 @@ func (suite *Tests) Test_CalculateHash() {
|
|||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
ctx := app.AcquireCtx(&fasthttp.RequestCtx{})
|
ctx := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||||
defer app.ReleaseCtx(ctx)
|
defer app.ReleaseCtx(ctx)
|
||||||
|
|
||||||
// Test with empty body
|
// Test with empty body
|
||||||
suite.Run("empty body", func() {
|
suite.Run("empty body", func() {
|
||||||
ctx.Request().SetBody([]byte(""))
|
ctx.Request().SetBody([]byte(""))
|
||||||
@@ -24,7 +24,7 @@ func (suite *Tests) Test_CalculateHash() {
|
|||||||
assert.NotEmpty(hash)
|
assert.NotEmpty(hash)
|
||||||
assert.Equal(32, len(hash)) // MD5 hash is 32 characters
|
assert.Equal(32, len(hash)) // MD5 hash is 32 characters
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with non-empty body
|
// Test with non-empty body
|
||||||
suite.Run("non-empty body", func() {
|
suite.Run("non-empty body", func() {
|
||||||
ctx.Request().SetBody([]byte("test body"))
|
ctx.Request().SetBody([]byte("test body"))
|
||||||
@@ -32,15 +32,15 @@ func (suite *Tests) Test_CalculateHash() {
|
|||||||
assert.NotEmpty(hash)
|
assert.NotEmpty(hash)
|
||||||
assert.Equal(32, len(hash))
|
assert.Equal(32, len(hash))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with different bodies produce different hashes
|
// Test with different bodies produce different hashes
|
||||||
suite.Run("different bodies", func() {
|
suite.Run("different bodies", func() {
|
||||||
ctx.Request().SetBody([]byte("body1"))
|
ctx.Request().SetBody([]byte("body1"))
|
||||||
hash1 := CalculateHash(ctx)
|
hash1 := CalculateHash(ctx)
|
||||||
|
|
||||||
ctx.Request().SetBody([]byte("body2"))
|
ctx.Request().SetBody([]byte("body2"))
|
||||||
hash2 := CalculateHash(ctx)
|
hash2 := CalculateHash(ctx)
|
||||||
|
|
||||||
assert.NotEqual(hash1, hash2)
|
assert.NotEqual(hash1, hash2)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -52,43 +52,43 @@ func (suite *Tests) Test_CacheDelete() {
|
|||||||
Client: libpack_cache_memory.New(5 * time.Minute),
|
Client: libpack_cache_memory.New(5 * time.Minute),
|
||||||
TTL: 5,
|
TTL: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test deleting a cache entry
|
// Test deleting a cache entry
|
||||||
suite.Run("delete existing entry", func() {
|
suite.Run("delete existing entry", func() {
|
||||||
// Add an entry to cache
|
// Add an entry to cache
|
||||||
testKey := "test-delete-key"
|
testKey := "test-delete-key"
|
||||||
testValue := []byte("test-delete-value")
|
testValue := []byte("test-delete-value")
|
||||||
CacheStore(testKey, testValue)
|
CacheStore(testKey, testValue)
|
||||||
|
|
||||||
// Verify it was added
|
// Verify it was added
|
||||||
result := CacheLookup(testKey)
|
result := CacheLookup(testKey)
|
||||||
assert.Equal(testValue, result)
|
assert.Equal(testValue, result)
|
||||||
|
|
||||||
// Delete the entry
|
// Delete the entry
|
||||||
CacheDelete(testKey)
|
CacheDelete(testKey)
|
||||||
|
|
||||||
// Verify it was deleted
|
// Verify it was deleted
|
||||||
result = CacheLookup(testKey)
|
result = CacheLookup(testKey)
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test deleting a non-existent entry
|
// Test deleting a non-existent entry
|
||||||
suite.Run("delete non-existent entry", func() {
|
suite.Run("delete non-existent entry", func() {
|
||||||
// This should not cause any errors
|
// This should not cause any errors
|
||||||
CacheDelete("non-existent-key")
|
CacheDelete("non-existent-key")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with uninitialized cache
|
// Test with uninitialized cache
|
||||||
suite.Run("uninitialized cache", func() {
|
suite.Run("uninitialized cache", func() {
|
||||||
// Save current config
|
// Save current config
|
||||||
oldConfig := config
|
oldConfig := config
|
||||||
|
|
||||||
// Set config to nil
|
// Set config to nil
|
||||||
config = nil
|
config = nil
|
||||||
|
|
||||||
// This should not cause any errors
|
// This should not cause any errors
|
||||||
CacheDelete("any-key")
|
CacheDelete("any-key")
|
||||||
|
|
||||||
// Restore config
|
// Restore config
|
||||||
config = oldConfig
|
config = oldConfig
|
||||||
})
|
})
|
||||||
@@ -101,38 +101,38 @@ func (suite *Tests) Test_CacheStoreWithTTL() {
|
|||||||
Client: libpack_cache_memory.New(5 * time.Minute),
|
Client: libpack_cache_memory.New(5 * time.Minute),
|
||||||
TTL: 5,
|
TTL: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test storing with custom TTL
|
// Test storing with custom TTL
|
||||||
suite.Run("store with custom TTL", func() {
|
suite.Run("store with custom TTL", func() {
|
||||||
testKey := "test-ttl-key"
|
testKey := "test-ttl-key"
|
||||||
testValue := []byte("test-ttl-value")
|
testValue := []byte("test-ttl-value")
|
||||||
customTTL := 1 * time.Second
|
customTTL := 1 * time.Second
|
||||||
|
|
||||||
CacheStoreWithTTL(testKey, testValue, customTTL)
|
CacheStoreWithTTL(testKey, testValue, customTTL)
|
||||||
|
|
||||||
// Verify it was stored
|
// Verify it was stored
|
||||||
result := CacheLookup(testKey)
|
result := CacheLookup(testKey)
|
||||||
assert.Equal(testValue, result)
|
assert.Equal(testValue, result)
|
||||||
|
|
||||||
// Wait for TTL to expire
|
// Wait for TTL to expire
|
||||||
time.Sleep(1100 * time.Millisecond)
|
time.Sleep(1100 * time.Millisecond)
|
||||||
|
|
||||||
// Verify it was removed
|
// Verify it was removed
|
||||||
result = CacheLookup(testKey)
|
result = CacheLookup(testKey)
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with uninitialized cache
|
// Test with uninitialized cache
|
||||||
suite.Run("uninitialized cache", func() {
|
suite.Run("uninitialized cache", func() {
|
||||||
// Save current config
|
// Save current config
|
||||||
oldConfig := config
|
oldConfig := config
|
||||||
|
|
||||||
// Set config to nil
|
// Set config to nil
|
||||||
config = nil
|
config = nil
|
||||||
|
|
||||||
// This should not cause any errors
|
// This should not cause any errors
|
||||||
CacheStoreWithTTL("any-key", []byte("any-value"), 1*time.Second)
|
CacheStoreWithTTL("any-key", []byte("any-value"), 1*time.Second)
|
||||||
|
|
||||||
// Restore config
|
// Restore config
|
||||||
config = oldConfig
|
config = oldConfig
|
||||||
})
|
})
|
||||||
@@ -145,33 +145,33 @@ func (suite *Tests) Test_CacheGetQueries() {
|
|||||||
Client: libpack_cache_memory.New(5 * time.Minute),
|
Client: libpack_cache_memory.New(5 * time.Minute),
|
||||||
TTL: 5,
|
TTL: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test getting query count
|
// Test getting query count
|
||||||
suite.Run("get query count", func() {
|
suite.Run("get query count", func() {
|
||||||
// Clear cache
|
// Clear cache
|
||||||
CacheClear()
|
CacheClear()
|
||||||
|
|
||||||
// Add some entries
|
// Add some entries
|
||||||
CacheStore("test-key-1", []byte("test-value-1"))
|
CacheStore("test-key-1", []byte("test-value-1"))
|
||||||
CacheStore("test-key-2", []byte("test-value-2"))
|
CacheStore("test-key-2", []byte("test-value-2"))
|
||||||
|
|
||||||
// Get query count
|
// Get query count
|
||||||
count := CacheGetQueries()
|
count := CacheGetQueries()
|
||||||
assert.Equal(int64(2), count)
|
assert.Equal(int64(2), count)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with uninitialized cache
|
// Test with uninitialized cache
|
||||||
suite.Run("uninitialized cache", func() {
|
suite.Run("uninitialized cache", func() {
|
||||||
// Save current config
|
// Save current config
|
||||||
oldConfig := config
|
oldConfig := config
|
||||||
|
|
||||||
// Set config to nil
|
// Set config to nil
|
||||||
config = nil
|
config = nil
|
||||||
|
|
||||||
// This should return 0
|
// This should return 0
|
||||||
count := CacheGetQueries()
|
count := CacheGetQueries()
|
||||||
assert.Equal(int64(0), count)
|
assert.Equal(int64(0), count)
|
||||||
|
|
||||||
// Restore config
|
// Restore config
|
||||||
config = oldConfig
|
config = oldConfig
|
||||||
})
|
})
|
||||||
@@ -184,34 +184,34 @@ func (suite *Tests) Test_CacheClear() {
|
|||||||
Client: libpack_cache_memory.New(5 * time.Minute),
|
Client: libpack_cache_memory.New(5 * time.Minute),
|
||||||
TTL: 5,
|
TTL: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new CacheStats instance
|
// Create a new CacheStats instance
|
||||||
cacheStats = &CacheStats{
|
cacheStats = &CacheStats{
|
||||||
CachedQueries: 0,
|
CachedQueries: 0,
|
||||||
CacheHits: 0,
|
CacheHits: 0,
|
||||||
CacheMisses: 0,
|
CacheMisses: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test clearing cache
|
// Test clearing cache
|
||||||
suite.Run("clear cache", func() {
|
suite.Run("clear cache", func() {
|
||||||
// Add some entries
|
// Add some entries
|
||||||
CacheStore("test-key-1", []byte("test-value-1"))
|
CacheStore("test-key-1", []byte("test-value-1"))
|
||||||
CacheStore("test-key-2", []byte("test-value-2"))
|
CacheStore("test-key-2", []byte("test-value-2"))
|
||||||
|
|
||||||
// Verify they were added
|
// Verify they were added
|
||||||
assert.NotNil(CacheLookup("test-key-1"))
|
assert.NotNil(CacheLookup("test-key-1"))
|
||||||
assert.NotNil(CacheLookup("test-key-2"))
|
assert.NotNil(CacheLookup("test-key-2"))
|
||||||
|
|
||||||
// Get the current stats before clearing
|
// Get the current stats before clearing
|
||||||
beforeStats := GetCacheStats()
|
beforeStats := GetCacheStats()
|
||||||
|
|
||||||
// Clear cache
|
// Clear cache
|
||||||
CacheClear()
|
CacheClear()
|
||||||
|
|
||||||
// Verify cache was cleared
|
// Verify cache was cleared
|
||||||
assert.Nil(CacheLookup("test-key-1"))
|
assert.Nil(CacheLookup("test-key-1"))
|
||||||
assert.Nil(CacheLookup("test-key-2"))
|
assert.Nil(CacheLookup("test-key-2"))
|
||||||
|
|
||||||
// Verify stats were reset
|
// Verify stats were reset
|
||||||
afterStats := GetCacheStats()
|
afterStats := GetCacheStats()
|
||||||
assert.Equal(int64(0), afterStats.CachedQueries)
|
assert.Equal(int64(0), afterStats.CachedQueries)
|
||||||
@@ -227,39 +227,39 @@ func (suite *Tests) Test_GetCacheStats() {
|
|||||||
TTL: 5,
|
TTL: 5,
|
||||||
}
|
}
|
||||||
cacheStats = &CacheStats{}
|
cacheStats = &CacheStats{}
|
||||||
|
|
||||||
// Test getting cache stats
|
// Test getting cache stats
|
||||||
suite.Run("get cache stats", func() {
|
suite.Run("get cache stats", func() {
|
||||||
// Clear cache
|
// Clear cache
|
||||||
CacheClear()
|
CacheClear()
|
||||||
|
|
||||||
// Add some entries and perform lookups
|
// Add some entries and perform lookups
|
||||||
CacheStore("test-key-1", []byte("test-value-1"))
|
CacheStore("test-key-1", []byte("test-value-1"))
|
||||||
CacheStore("test-key-2", []byte("test-value-2"))
|
CacheStore("test-key-2", []byte("test-value-2"))
|
||||||
CacheLookup("test-key-1") // Hit
|
CacheLookup("test-key-1") // Hit
|
||||||
CacheLookup("test-key-3") // Miss
|
CacheLookup("test-key-3") // Miss
|
||||||
|
|
||||||
// Get stats
|
// Get stats
|
||||||
stats := GetCacheStats()
|
stats := GetCacheStats()
|
||||||
assert.Equal(int64(2), stats.CachedQueries)
|
assert.Equal(int64(2), stats.CachedQueries)
|
||||||
assert.Equal(int64(1), stats.CacheHits)
|
assert.Equal(int64(1), stats.CacheHits)
|
||||||
assert.Equal(int64(1), stats.CacheMisses)
|
assert.Equal(int64(1), stats.CacheMisses)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with uninitialized cache
|
// Test with uninitialized cache
|
||||||
suite.Run("uninitialized cache", func() {
|
suite.Run("uninitialized cache", func() {
|
||||||
// Save current config
|
// Save current config
|
||||||
oldConfig := config
|
oldConfig := config
|
||||||
|
|
||||||
// Set config to nil
|
// Set config to nil
|
||||||
config = nil
|
config = nil
|
||||||
|
|
||||||
// This should return empty stats
|
// This should return empty stats
|
||||||
stats := GetCacheStats()
|
stats := GetCacheStats()
|
||||||
assert.Equal(int64(0), stats.CachedQueries)
|
assert.Equal(int64(0), stats.CachedQueries)
|
||||||
assert.Equal(int64(0), stats.CacheHits)
|
assert.Equal(int64(0), stats.CacheHits)
|
||||||
assert.Equal(int64(0), stats.CacheMisses)
|
assert.Equal(int64(0), stats.CacheMisses)
|
||||||
|
|
||||||
// Restore config
|
// Restore config
|
||||||
config = oldConfig
|
config = oldConfig
|
||||||
})
|
})
|
||||||
@@ -272,12 +272,12 @@ func (suite *Tests) Test_CacheLookup_Compressed() {
|
|||||||
Client: libpack_cache_memory.New(5 * time.Minute),
|
Client: libpack_cache_memory.New(5 * time.Minute),
|
||||||
TTL: 5,
|
TTL: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test lookup with compressed data
|
// Test lookup with compressed data
|
||||||
suite.Run("lookup compressed data", func() {
|
suite.Run("lookup compressed data", func() {
|
||||||
testKey := "test-compressed-key"
|
testKey := "test-compressed-key"
|
||||||
testValue := []byte("test-compressed-value")
|
testValue := []byte("test-compressed-value")
|
||||||
|
|
||||||
// Compress the data
|
// Compress the data
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
gzWriter := gzip.NewWriter(&buf)
|
gzWriter := gzip.NewWriter(&buf)
|
||||||
@@ -286,15 +286,15 @@ func (suite *Tests) Test_CacheLookup_Compressed() {
|
|||||||
err = gzWriter.Close()
|
err = gzWriter.Close()
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
compressedData := buf.Bytes()
|
compressedData := buf.Bytes()
|
||||||
|
|
||||||
// Store compressed data directly
|
// Store compressed data directly
|
||||||
config.Client.Set(testKey, compressedData, time.Duration(config.TTL)*time.Second)
|
config.Client.Set(testKey, compressedData, time.Duration(config.TTL)*time.Second)
|
||||||
|
|
||||||
// Lookup should automatically decompress
|
// Lookup should automatically decompress
|
||||||
result := CacheLookup(testKey)
|
result := CacheLookup(testKey)
|
||||||
assert.Equal(testValue, result)
|
assert.Equal(testValue, result)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Skip the invalid compressed data test as it's causing issues
|
// Skip the invalid compressed data test as it's causing issues
|
||||||
// We'll mock the behavior instead
|
// We'll mock the behavior instead
|
||||||
suite.Run("lookup invalid compressed data", func() {
|
suite.Run("lookup invalid compressed data", func() {
|
||||||
@@ -313,16 +313,16 @@ func (suite *Tests) Test_ShouldUseRedisCache() {
|
|||||||
suite.Run("redis enabled", func() {
|
suite.Run("redis enabled", func() {
|
||||||
cfg := &CacheConfig{}
|
cfg := &CacheConfig{}
|
||||||
cfg.Redis.Enable = true
|
cfg.Redis.Enable = true
|
||||||
|
|
||||||
result := ShouldUseRedisCache(cfg)
|
result := ShouldUseRedisCache(cfg)
|
||||||
assert.True(result)
|
assert.True(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with Redis disabled
|
// Test with Redis disabled
|
||||||
suite.Run("redis disabled", func() {
|
suite.Run("redis disabled", func() {
|
||||||
cfg := &CacheConfig{}
|
cfg := &CacheConfig{}
|
||||||
cfg.Redis.Enable = false
|
cfg.Redis.Enable = false
|
||||||
|
|
||||||
result := ShouldUseRedisCache(cfg)
|
result := ShouldUseRedisCache(cfg)
|
||||||
assert.False(result)
|
assert.False(result)
|
||||||
})
|
})
|
||||||
@@ -335,22 +335,22 @@ func (suite *Tests) Test_IsCacheInitialized() {
|
|||||||
Logger: libpack_logger.New(),
|
Logger: libpack_logger.New(),
|
||||||
Client: libpack_cache_memory.New(5 * time.Minute),
|
Client: libpack_cache_memory.New(5 * time.Minute),
|
||||||
}
|
}
|
||||||
|
|
||||||
result := IsCacheInitialized()
|
result := IsCacheInitialized()
|
||||||
assert.True(result)
|
assert.True(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with nil config
|
// Test with nil config
|
||||||
suite.Run("nil config", func() {
|
suite.Run("nil config", func() {
|
||||||
oldConfig := config
|
oldConfig := config
|
||||||
config = nil
|
config = nil
|
||||||
|
|
||||||
result := IsCacheInitialized()
|
result := IsCacheInitialized()
|
||||||
assert.False(result)
|
assert.False(result)
|
||||||
|
|
||||||
config = oldConfig
|
config = oldConfig
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with nil client
|
// Test with nil client
|
||||||
suite.Run("nil client", func() {
|
suite.Run("nil client", func() {
|
||||||
oldConfig := config
|
oldConfig := config
|
||||||
@@ -358,10 +358,10 @@ func (suite *Tests) Test_IsCacheInitialized() {
|
|||||||
Logger: libpack_logger.New(),
|
Logger: libpack_logger.New(),
|
||||||
Client: nil,
|
Client: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
result := IsCacheInitialized()
|
result := IsCacheInitialized()
|
||||||
assert.False(result)
|
assert.False(result)
|
||||||
|
|
||||||
config = oldConfig
|
config = oldConfig
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+14
-14
@@ -17,8 +17,8 @@ const CompressionThreshold = 1024 // 1KB
|
|||||||
const MaxCacheSize = 10000
|
const MaxCacheSize = 10000
|
||||||
|
|
||||||
type CacheEntry struct {
|
type CacheEntry struct {
|
||||||
ExpiresAt time.Time
|
ExpiresAt time.Time
|
||||||
Value []byte
|
Value []byte
|
||||||
Compressed bool
|
Compressed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ func (c *Cache) cleanupRoutine(globalTTL time.Duration) {
|
|||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
c.CleanExpiredEntries()
|
c.CleanExpiredEntries()
|
||||||
|
|
||||||
// Trigger GC if we have a lot of entries
|
// Trigger GC if we have a lot of entries
|
||||||
if atomic.LoadInt64(&c.entryCount) > MaxCacheSize/2 {
|
if atomic.LoadInt64(&c.entryCount) > MaxCacheSize/2 {
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
@@ -74,7 +74,7 @@ func (c *Cache) Set(key string, value []byte, ttl time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expiresAt := time.Now().Add(ttl)
|
expiresAt := time.Now().Add(ttl)
|
||||||
|
|
||||||
// Only compress if the value is larger than the threshold
|
// Only compress if the value is larger than the threshold
|
||||||
var entry CacheEntry
|
var entry CacheEntry
|
||||||
if len(value) > CompressionThreshold {
|
if len(value) > CompressionThreshold {
|
||||||
@@ -100,13 +100,13 @@ func (c *Cache) Set(key string, value []byte, ttl time.Duration) {
|
|||||||
Compressed: false,
|
Compressed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a new entry
|
// Check if this is a new entry
|
||||||
_, exists := c.entries.Load(key)
|
_, exists := c.entries.Load(key)
|
||||||
if !exists {
|
if !exists {
|
||||||
atomic.AddInt64(&c.entryCount, 1)
|
atomic.AddInt64(&c.entryCount, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.entries.Store(key, entry)
|
c.entries.Store(key, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ func (c *Cache) Get(key string) ([]byte, bool) {
|
|||||||
}
|
}
|
||||||
return value, true
|
return value, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return cacheEntry.Value, true
|
return cacheEntry.Value, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ func (c *Cache) compress(data []byte) ([]byte, error) {
|
|||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
w := c.compressPool.Get().(*gzip.Writer)
|
w := c.compressPool.Get().(*gzip.Writer)
|
||||||
defer c.compressPool.Put(w)
|
defer c.compressPool.Put(w)
|
||||||
|
|
||||||
w.Reset(&buf)
|
w.Reset(&buf)
|
||||||
if _, err := w.Write(data); err != nil {
|
if _, err := w.Write(data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -170,7 +170,7 @@ func (c *Cache) compress(data []byte) ([]byte, error) {
|
|||||||
func (c *Cache) decompress(data []byte) ([]byte, error) {
|
func (c *Cache) decompress(data []byte) ([]byte, error) {
|
||||||
r, ok := c.decompressPool.Get().(*gzip.Reader)
|
r, ok := c.decompressPool.Get().(*gzip.Reader)
|
||||||
defer c.decompressPool.Put(r)
|
defer c.decompressPool.Put(r)
|
||||||
|
|
||||||
if !ok || r == nil {
|
if !ok || r == nil {
|
||||||
var err error
|
var err error
|
||||||
r, err = gzip.NewReader(bytes.NewReader(data))
|
r, err = gzip.NewReader(bytes.NewReader(data))
|
||||||
@@ -182,7 +182,7 @@ func (c *Cache) decompress(data []byte) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
return io.ReadAll(r)
|
return io.ReadAll(r)
|
||||||
}
|
}
|
||||||
@@ -203,10 +203,10 @@ func (c *Cache) CleanExpiredEntries() {
|
|||||||
// evictOldest removes the oldest n entries from the cache
|
// evictOldest removes the oldest n entries from the cache
|
||||||
func (c *Cache) evictOldest(n int) {
|
func (c *Cache) evictOldest(n int) {
|
||||||
type keyExpiry struct {
|
type keyExpiry struct {
|
||||||
key string
|
key string
|
||||||
expiresAt time.Time
|
expiresAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect all entries with their expiry times
|
// Collect all entries with their expiry times
|
||||||
entries := make([]keyExpiry, 0, n*2)
|
entries := make([]keyExpiry, 0, n*2)
|
||||||
c.entries.Range(func(k, v interface{}) bool {
|
c.entries.Range(func(k, v interface{}) bool {
|
||||||
@@ -215,7 +215,7 @@ func (c *Cache) evictOldest(n int) {
|
|||||||
entries = append(entries, keyExpiry{key, entry.ExpiresAt})
|
entries = append(entries, keyExpiry{key, entry.ExpiresAt})
|
||||||
return len(entries) < cap(entries)
|
return len(entries) < cap(entries)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Sort by expiry time (oldest first)
|
// Sort by expiry time (oldest first)
|
||||||
// Using a simple selection sort since we only need to find the n oldest
|
// Using a simple selection sort since we only need to find the n oldest
|
||||||
for i := 0; i < n && i < len(entries); i++ {
|
for i := 0; i < n && i < len(entries); i++ {
|
||||||
@@ -229,7 +229,7 @@ func (c *Cache) evictOldest(n int) {
|
|||||||
if oldest != i {
|
if oldest != i {
|
||||||
entries[i], entries[oldest] = entries[oldest], entries[i]
|
entries[i], entries[oldest] = entries[oldest], entries[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete this entry
|
// Delete this entry
|
||||||
if _, exists := c.entries.LoadAndDelete(entries[i].key); exists {
|
if _, exists := c.entries.LoadAndDelete(entries[i].key); exists {
|
||||||
atomic.AddInt64(&c.entryCount, -1)
|
atomic.AddInt64(&c.entryCount, -1)
|
||||||
|
|||||||
+19
-19
@@ -14,45 +14,45 @@ const (
|
|||||||
|
|
||||||
func TestMemoryCacheClear(t *testing.T) {
|
func TestMemoryCacheClear(t *testing.T) {
|
||||||
cache := New(DefaultTestExpiration)
|
cache := New(DefaultTestExpiration)
|
||||||
|
|
||||||
// Add some entries
|
// Add some entries
|
||||||
cache.Set("key1", []byte("value1"), DefaultTestExpiration)
|
cache.Set("key1", []byte("value1"), DefaultTestExpiration)
|
||||||
cache.Set("key2", []byte("value2"), DefaultTestExpiration)
|
cache.Set("key2", []byte("value2"), DefaultTestExpiration)
|
||||||
|
|
||||||
// Verify entries exist
|
// Verify entries exist
|
||||||
_, found := cache.Get("key1")
|
_, found := cache.Get("key1")
|
||||||
assert.True(t, found, "Expected key1 to exist before clearing cache")
|
assert.True(t, found, "Expected key1 to exist before clearing cache")
|
||||||
|
|
||||||
// Clear the cache
|
// Clear the cache
|
||||||
cache.Clear()
|
cache.Clear()
|
||||||
|
|
||||||
// Verify cache is empty
|
// Verify cache is empty
|
||||||
_, found = cache.Get("key1")
|
_, found = cache.Get("key1")
|
||||||
assert.False(t, found, "Expected key1 to be removed after clearing cache")
|
assert.False(t, found, "Expected key1 to be removed after clearing cache")
|
||||||
_, found = cache.Get("key2")
|
_, found = cache.Get("key2")
|
||||||
assert.False(t, found, "Expected key2 to be removed after clearing cache")
|
assert.False(t, found, "Expected key2 to be removed after clearing cache")
|
||||||
|
|
||||||
// Check that counter was reset
|
// Check that counter was reset
|
||||||
assert.Equal(t, int64(0), cache.CountQueries(), "Expected count to be 0 after clearing cache")
|
assert.Equal(t, int64(0), cache.CountQueries(), "Expected count to be 0 after clearing cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMemoryCacheCountQueries(t *testing.T) {
|
func TestMemoryCacheCountQueries(t *testing.T) {
|
||||||
cache := New(DefaultTestExpiration)
|
cache := New(DefaultTestExpiration)
|
||||||
|
|
||||||
// Check initial count
|
// Check initial count
|
||||||
assert.Equal(t, int64(0), cache.CountQueries(), "Expected initial count to be 0")
|
assert.Equal(t, int64(0), cache.CountQueries(), "Expected initial count to be 0")
|
||||||
|
|
||||||
// Add some entries
|
// Add some entries
|
||||||
cache.Set("key1", []byte("value1"), DefaultTestExpiration)
|
cache.Set("key1", []byte("value1"), DefaultTestExpiration)
|
||||||
cache.Set("key2", []byte("value2"), DefaultTestExpiration)
|
cache.Set("key2", []byte("value2"), DefaultTestExpiration)
|
||||||
cache.Set("key3", []byte("value3"), DefaultTestExpiration)
|
cache.Set("key3", []byte("value3"), DefaultTestExpiration)
|
||||||
|
|
||||||
// Check count
|
// Check count
|
||||||
assert.Equal(t, int64(3), cache.CountQueries(), "Expected count to be 3 after adding 3 entries")
|
assert.Equal(t, int64(3), cache.CountQueries(), "Expected count to be 3 after adding 3 entries")
|
||||||
|
|
||||||
// Delete an entry
|
// Delete an entry
|
||||||
cache.Delete("key1")
|
cache.Delete("key1")
|
||||||
|
|
||||||
// Check count after deletion
|
// Check count after deletion
|
||||||
assert.Equal(t, int64(2), cache.CountQueries(), "Expected count to be 2 after deleting 1 entry")
|
assert.Equal(t, int64(2), cache.CountQueries(), "Expected count to be 2 after deleting 1 entry")
|
||||||
}
|
}
|
||||||
@@ -60,31 +60,31 @@ func TestMemoryCacheCountQueries(t *testing.T) {
|
|||||||
func TestMemoryCacheCleanExpiredEntries(t *testing.T) {
|
func TestMemoryCacheCleanExpiredEntries(t *testing.T) {
|
||||||
// Create a cache with default expiration
|
// Create a cache with default expiration
|
||||||
cache := New(10 * time.Second)
|
cache := New(10 * time.Second)
|
||||||
|
|
||||||
// Add an entry that will expire quickly
|
// Add an entry that will expire quickly
|
||||||
cache.Set("expire-soon", []byte("value1"), 10*time.Millisecond)
|
cache.Set("expire-soon", []byte("value1"), 10*time.Millisecond)
|
||||||
|
|
||||||
// Add an entry that will not expire during the test
|
// Add an entry that will not expire during the test
|
||||||
cache.Set("expire-later", []byte("value3"), 10*time.Minute)
|
cache.Set("expire-later", []byte("value3"), 10*time.Minute)
|
||||||
|
|
||||||
// Initial count should be 2
|
// Initial count should be 2
|
||||||
assert.Equal(t, int64(2), cache.CountQueries(), "Expected count to be 2 after adding entries")
|
assert.Equal(t, int64(2), cache.CountQueries(), "Expected count to be 2 after adding entries")
|
||||||
|
|
||||||
// Wait for short expiration
|
// Wait for short expiration
|
||||||
time.Sleep(20 * time.Millisecond)
|
time.Sleep(20 * time.Millisecond)
|
||||||
|
|
||||||
// Get the expired key directly to verify it's expired
|
// Get the expired key directly to verify it's expired
|
||||||
_, expiredFound := cache.Get("expire-soon")
|
_, expiredFound := cache.Get("expire-soon")
|
||||||
assert.False(t, expiredFound, "Key 'expire-soon' should be expired now")
|
assert.False(t, expiredFound, "Key 'expire-soon' should be expired now")
|
||||||
|
|
||||||
// Verify the not-expired key is still there
|
// Verify the not-expired key is still there
|
||||||
val, nonExpiredFound := cache.Get("expire-later")
|
val, nonExpiredFound := cache.Get("expire-later")
|
||||||
assert.True(t, nonExpiredFound, "Key 'expire-later' should not be expired")
|
assert.True(t, nonExpiredFound, "Key 'expire-later' should not be expired")
|
||||||
assert.Equal(t, []byte("value3"), val, "Expected correct value for 'expire-later'")
|
assert.Equal(t, []byte("value3"), val, "Expected correct value for 'expire-later'")
|
||||||
|
|
||||||
// Manually clean expired entries
|
// Manually clean expired entries
|
||||||
cache.CleanExpiredEntries()
|
cache.CleanExpiredEntries()
|
||||||
|
|
||||||
// Count should be 1 now (only the non-expired entry)
|
// Count should be 1 now (only the non-expired entry)
|
||||||
assert.Equal(t, int64(1), cache.CountQueries(), "Expected count to be 1 after cleaning expired entries")
|
assert.Equal(t, int64(1), cache.CountQueries(), "Expected count to be 1 after cleaning expired entries")
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -47,4 +47,4 @@ func TestRedisClear(t *testing.T) {
|
|||||||
assert.False(t, found, "Key2 should be deleted after Clear")
|
assert.False(t, found, "Key2 should be deleted after Clear")
|
||||||
_, found = redisConfig.Get("key3")
|
_, found = redisConfig.Get("key3")
|
||||||
assert.False(t, found, "Key3 should be deleted after Clear")
|
assert.False(t, found, "Key3 should be deleted after Clear")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ func TestConfigConstants(t *testing.T) {
|
|||||||
// Verify package constants are defined
|
// Verify package constants are defined
|
||||||
assert.NotEmpty(t, PKG_NAME, "PKG_NAME should be defined")
|
assert.NotEmpty(t, PKG_NAME, "PKG_NAME should be defined")
|
||||||
assert.NotEmpty(t, PKG_VERSION, "PKG_VERSION should be defined")
|
assert.NotEmpty(t, PKG_VERSION, "PKG_VERSION should be defined")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ func enableHasuraEventCleaner() {
|
|||||||
if eventMetadataDb == "" {
|
if eventMetadataDb == "" {
|
||||||
logger := cfg.Logger
|
logger := cfg.Logger
|
||||||
cfgMutex.RUnlock()
|
cfgMutex.RUnlock()
|
||||||
|
|
||||||
logger.Warning(&libpack_logger.LogMessage{
|
logger.Warning(&libpack_logger.LogMessage{
|
||||||
Message: "Event metadata db URL not specified, event cleaner not active",
|
Message: "Event metadata db URL not specified, event cleaner not active",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clearOlderThan := cfg.HasuraEventCleaner.ClearOlderThan
|
clearOlderThan := cfg.HasuraEventCleaner.ClearOlderThan
|
||||||
logger := cfg.Logger
|
logger := cfg.Logger
|
||||||
cfgMutex.RUnlock()
|
cfgMutex.RUnlock()
|
||||||
|
|||||||
+14
-14
@@ -31,73 +31,73 @@ func (suite *EventsTestSuite) Test_EnableHasuraEventCleaner() {
|
|||||||
cfgMutex.RLock()
|
cfgMutex.RLock()
|
||||||
originalConfig := cfg.HasuraEventCleaner
|
originalConfig := cfg.HasuraEventCleaner
|
||||||
cfgMutex.RUnlock()
|
cfgMutex.RUnlock()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg.HasuraEventCleaner = originalConfig
|
cfg.HasuraEventCleaner = originalConfig
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Set up test condition with proper synchronization
|
// Set up test condition with proper synchronization
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg.HasuraEventCleaner.Enable = false
|
cfg.HasuraEventCleaner.Enable = false
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
|
|
||||||
// Test function
|
// Test function
|
||||||
enableHasuraEventCleaner()
|
enableHasuraEventCleaner()
|
||||||
|
|
||||||
// No assertions needed as we're just testing coverage
|
// No assertions needed as we're just testing coverage
|
||||||
// The function should return early without error
|
// The function should return early without error
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test case: missing database URL
|
// Test case: missing database URL
|
||||||
suite.Run("missing database URL", func() {
|
suite.Run("missing database URL", func() {
|
||||||
// Save original config with proper synchronization
|
// Save original config with proper synchronization
|
||||||
cfgMutex.RLock()
|
cfgMutex.RLock()
|
||||||
originalConfig := cfg.HasuraEventCleaner
|
originalConfig := cfg.HasuraEventCleaner
|
||||||
cfgMutex.RUnlock()
|
cfgMutex.RUnlock()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg.HasuraEventCleaner = originalConfig
|
cfg.HasuraEventCleaner = originalConfig
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Set up test condition with proper synchronization
|
// Set up test condition with proper synchronization
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg.HasuraEventCleaner.Enable = true
|
cfg.HasuraEventCleaner.Enable = true
|
||||||
cfg.HasuraEventCleaner.EventMetadataDb = ""
|
cfg.HasuraEventCleaner.EventMetadataDb = ""
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
|
|
||||||
// Test function
|
// Test function
|
||||||
enableHasuraEventCleaner()
|
enableHasuraEventCleaner()
|
||||||
|
|
||||||
// No assertions needed as we're just testing coverage
|
// No assertions needed as we're just testing coverage
|
||||||
// The function should log a warning and return early
|
// The function should log a warning and return early
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test case: database URL provided but we don't actually connect in the test
|
// Test case: database URL provided but we don't actually connect in the test
|
||||||
suite.Run("database URL provided", func() {
|
suite.Run("database URL provided", func() {
|
||||||
// Save original config with proper synchronization
|
// Save original config with proper synchronization
|
||||||
cfgMutex.RLock()
|
cfgMutex.RLock()
|
||||||
originalConfig := cfg.HasuraEventCleaner
|
originalConfig := cfg.HasuraEventCleaner
|
||||||
cfgMutex.RUnlock()
|
cfgMutex.RUnlock()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg.HasuraEventCleaner = originalConfig
|
cfg.HasuraEventCleaner = originalConfig
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Set up test condition with proper synchronization
|
// Set up test condition with proper synchronization
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg.HasuraEventCleaner.Enable = true
|
cfg.HasuraEventCleaner.Enable = true
|
||||||
cfg.HasuraEventCleaner.EventMetadataDb = "postgres://fake:fake@localhost:5432/fake"
|
cfg.HasuraEventCleaner.EventMetadataDb = "postgres://fake:fake@localhost:5432/fake"
|
||||||
cfg.HasuraEventCleaner.ClearOlderThan = 7
|
cfg.HasuraEventCleaner.ClearOlderThan = 7
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
|
|
||||||
// We're not going to call enableHasuraEventCleaner() here because it would
|
// We're not going to call enableHasuraEventCleaner() here because it would
|
||||||
// try to connect to a database. Instead, we're just increasing coverage
|
// try to connect to a database. Instead, we're just increasing coverage
|
||||||
// for the configuration path by setting these values.
|
// for the configuration path by setting these values.
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -178,20 +178,20 @@ func checkSelections(c *fiber.Ctx, selections []ast.Selection) bool {
|
|||||||
if len(selections) == 0 {
|
if len(selections) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast path: if no introspection blocking is configured, return immediately
|
// Fast path: if no introspection blocking is configured, return immediately
|
||||||
if !cfg.Security.BlockIntrospection {
|
if !cfg.Security.BlockIntrospection {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast path: if there are no allowed introspection queries, check only top level
|
// Fast path: if there are no allowed introspection queries, check only top level
|
||||||
hasAllowList := len(cfg.Security.IntrospectionAllowed) > 0
|
hasAllowList := len(cfg.Security.IntrospectionAllowed) > 0
|
||||||
|
|
||||||
for _, s := range selections {
|
for _, s := range selections {
|
||||||
switch sel := s.(type) {
|
switch sel := s.(type) {
|
||||||
case *ast.Field:
|
case *ast.Field:
|
||||||
fieldName := strings.ToLower(sel.Name.Value)
|
fieldName := strings.ToLower(sel.Name.Value)
|
||||||
|
|
||||||
// Check if this is an introspection query
|
// Check if this is an introspection query
|
||||||
if _, exists := introspectionQueries[fieldName]; exists {
|
if _, exists := introspectionQueries[fieldName]; exists {
|
||||||
if hasAllowList {
|
if hasAllowList {
|
||||||
@@ -203,14 +203,14 @@ func checkSelections(c *fiber.Ctx, selections []ast.Selection) bool {
|
|||||||
return true // Block if no allowlist exists
|
return true // Block if no allowlist exists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check nested selections if present
|
// Check nested selections if present
|
||||||
if sel.SelectionSet != nil && len(sel.GetSelectionSet().Selections) > 0 {
|
if sel.SelectionSet != nil && len(sel.GetSelectionSet().Selections) > 0 {
|
||||||
if checkSelections(c, sel.GetSelectionSet().Selections) {
|
if checkSelections(c, sel.GetSelectionSet().Selections) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.InlineFragment:
|
case *ast.InlineFragment:
|
||||||
// Check nested selections in fragments
|
// Check nested selections in fragments
|
||||||
if sel.SelectionSet != nil && len(sel.GetSelectionSet().Selections) > 0 {
|
if sel.SelectionSet != nil && len(sel.GetSelectionSet().Selections) > 0 {
|
||||||
@@ -220,18 +220,18 @@ func checkSelections(c *fiber.Ctx, selections []ast.Selection) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkIfContainsIntrospection(c *fiber.Ctx, query string) bool {
|
func checkIfContainsIntrospection(c *fiber.Ctx, query string) bool {
|
||||||
blocked := false
|
blocked := false
|
||||||
|
|
||||||
// Enable introspection blocking for tests
|
// Enable introspection blocking for tests
|
||||||
if !cfg.Security.BlockIntrospection {
|
if !cfg.Security.BlockIntrospection {
|
||||||
cfg.Security.BlockIntrospection = true
|
cfg.Security.BlockIntrospection = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try parsing as a complete query first
|
// Try parsing as a complete query first
|
||||||
p, err := parser.Parse(parser.ParseParams{Source: query})
|
p, err := parser.Parse(parser.ParseParams{Source: query})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -59,33 +59,33 @@ func (suite *LoggerAdditionalTestSuite) TestSetFieldName() {
|
|||||||
for k, v := range fieldNames {
|
for k, v := range fieldNames {
|
||||||
originalFieldNames[k] = v
|
originalFieldNames[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore original field names after test
|
// Restore original field names after test
|
||||||
defer func() {
|
defer func() {
|
||||||
for k, v := range originalFieldNames {
|
for k, v := range originalFieldNames {
|
||||||
fieldNames[k] = v
|
fieldNames[k] = v
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Test with custom field names
|
// Test with custom field names
|
||||||
customTimestampField := "time"
|
customTimestampField := "time"
|
||||||
customLevelField := "severity"
|
customLevelField := "severity"
|
||||||
customMessageField := "text"
|
customMessageField := "text"
|
||||||
|
|
||||||
suite.logger.SetFieldName("timestamp", customTimestampField)
|
suite.logger.SetFieldName("timestamp", customTimestampField)
|
||||||
suite.logger.SetFieldName("level", customLevelField)
|
suite.logger.SetFieldName("level", customLevelField)
|
||||||
suite.logger.SetFieldName("message", customMessageField)
|
suite.logger.SetFieldName("message", customMessageField)
|
||||||
|
|
||||||
// Verify field names were changed
|
// Verify field names were changed
|
||||||
suite.assert.Equal(customTimestampField, fieldNames["timestamp"])
|
suite.assert.Equal(customTimestampField, fieldNames["timestamp"])
|
||||||
suite.assert.Equal(customLevelField, fieldNames["level"])
|
suite.assert.Equal(customLevelField, fieldNames["level"])
|
||||||
suite.assert.Equal(customMessageField, fieldNames["message"])
|
suite.assert.Equal(customMessageField, fieldNames["message"])
|
||||||
|
|
||||||
// Test logging with custom field names
|
// Test logging with custom field names
|
||||||
suite.output.Reset()
|
suite.output.Reset()
|
||||||
suite.logger.Info(&LogMessage{Message: "test custom fields"})
|
suite.logger.Info(&LogMessage{Message: "test custom fields"})
|
||||||
output := suite.output.String()
|
output := suite.output.String()
|
||||||
|
|
||||||
// Check if custom field names are used in the output
|
// Check if custom field names are used in the output
|
||||||
suite.assert.Contains(output, customTimestampField)
|
suite.assert.Contains(output, customTimestampField)
|
||||||
suite.assert.Contains(output, customLevelField)
|
suite.assert.Contains(output, customLevelField)
|
||||||
@@ -99,20 +99,20 @@ func (suite *LoggerAdditionalTestSuite) TestSetFieldName() {
|
|||||||
func (suite *LoggerAdditionalTestSuite) TestSetShowCaller() {
|
func (suite *LoggerAdditionalTestSuite) TestSetShowCaller() {
|
||||||
// Make sure caller info is disabled
|
// Make sure caller info is disabled
|
||||||
suite.logger.SetShowCaller(false)
|
suite.logger.SetShowCaller(false)
|
||||||
|
|
||||||
// Test with caller info disabled
|
// Test with caller info disabled
|
||||||
suite.output.Reset()
|
suite.output.Reset()
|
||||||
suite.logger.Info(&LogMessage{Message: "test without cal__ler"})
|
suite.logger.Info(&LogMessage{Message: "test without cal__ler"})
|
||||||
output := suite.output.String()
|
output := suite.output.String()
|
||||||
suite.assert.NotContains(output, "caller")
|
suite.assert.NotContains(output, "caller")
|
||||||
|
|
||||||
// Test with caller info enabled
|
// Test with caller info enabled
|
||||||
suite.output.Reset()
|
suite.output.Reset()
|
||||||
suite.logger.SetShowCaller(true)
|
suite.logger.SetShowCaller(true)
|
||||||
suite.logger.Info(&LogMessage{Message: "test with caller"})
|
suite.logger.Info(&LogMessage{Message: "test with caller"})
|
||||||
output = suite.output.String()
|
output = suite.output.String()
|
||||||
suite.assert.Contains(output, "caller")
|
suite.assert.Contains(output, "caller")
|
||||||
|
|
||||||
// Verify the caller info format (file:line)
|
// Verify the caller info format (file:line)
|
||||||
suite.assert.Regexp(`"caller":"[^:]+:\d+"`, output)
|
suite.assert.Regexp(`"caller":"[^:]+:\d+"`, output)
|
||||||
}
|
}
|
||||||
@@ -152,27 +152,27 @@ func (suite *LoggerAdditionalTestSuite) TestCritical() {
|
|||||||
// Safely intercept os.Exit call with proper synchronization
|
// Safely intercept os.Exit call with proper synchronization
|
||||||
exitMutex.Lock()
|
exitMutex.Lock()
|
||||||
originalOsExit := osExit
|
originalOsExit := osExit
|
||||||
|
|
||||||
var exitCode int
|
var exitCode int
|
||||||
osExit = func(code int) {
|
osExit = func(code int) {
|
||||||
exitCode = code
|
exitCode = code
|
||||||
// Don't actually exit
|
// Don't actually exit
|
||||||
}
|
}
|
||||||
exitMutex.Unlock()
|
exitMutex.Unlock()
|
||||||
|
|
||||||
// Ensure we restore the original osExit function
|
// Ensure we restore the original osExit function
|
||||||
defer func() {
|
defer func() {
|
||||||
exitMutex.Lock()
|
exitMutex.Lock()
|
||||||
osExit = originalOsExit
|
osExit = originalOsExit
|
||||||
exitMutex.Unlock()
|
exitMutex.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
suite.output.Reset()
|
suite.output.Reset()
|
||||||
msg := &LogMessage{Message: "test critical"}
|
msg := &LogMessage{Message: "test critical"}
|
||||||
suite.logger.Critical(msg)
|
suite.logger.Critical(msg)
|
||||||
output := suite.output.String()
|
output := suite.output.String()
|
||||||
|
|
||||||
suite.assert.Contains(output, "fatal")
|
suite.assert.Contains(output, "fatal")
|
||||||
suite.assert.Contains(output, "test critical")
|
suite.assert.Contains(output, "test critical")
|
||||||
suite.assert.Equal(1, exitCode)
|
suite.assert.Equal(1, exitCode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,17 +21,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cfg *config
|
cfg *config
|
||||||
cfgMutex sync.RWMutex
|
cfgMutex sync.RWMutex
|
||||||
once sync.Once
|
once sync.Once
|
||||||
tracer *libpack_tracing.TracingSetup
|
tracer *libpack_tracing.TracingSetup
|
||||||
)
|
)
|
||||||
|
|
||||||
// getDetailsFromEnv retrieves the value from the environment or returns the default.
|
// getDetailsFromEnv retrieves the value from the environment or returns the default.
|
||||||
// It first checks for a prefixed environment variable (GMP_KEY), then falls back to the unprefixed version.
|
// It first checks for a prefixed environment variable (GMP_KEY), then falls back to the unprefixed version.
|
||||||
func getDetailsFromEnv[T any](key string, defaultValue T) T {
|
func getDetailsFromEnv[T any](key string, defaultValue T) T {
|
||||||
prefixedKey := "GMP_" + key
|
prefixedKey := "GMP_" + key
|
||||||
|
|
||||||
switch v := any(defaultValue).(type) {
|
switch v := any(defaultValue).(type) {
|
||||||
case string:
|
case string:
|
||||||
if val, ok := os.LookupEnv(prefixedKey); ok {
|
if val, ok := os.LookupEnv(prefixedKey); ok {
|
||||||
@@ -121,7 +121,7 @@ func parseConfig() {
|
|||||||
// Tracing configuration
|
// Tracing configuration
|
||||||
c.Tracing.Enable = getDetailsFromEnv("ENABLE_TRACE", false)
|
c.Tracing.Enable = getDetailsFromEnv("ENABLE_TRACE", false)
|
||||||
c.Tracing.Endpoint = getDetailsFromEnv("TRACE_ENDPOINT", "localhost:4317")
|
c.Tracing.Endpoint = getDetailsFromEnv("TRACE_ENDPOINT", "localhost:4317")
|
||||||
|
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg = &c
|
cfg = &c
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
@@ -180,14 +180,14 @@ func parseConfig() {
|
|||||||
func main() {
|
func main() {
|
||||||
// Parse configuration
|
// Parse configuration
|
||||||
parseConfig()
|
parseConfig()
|
||||||
|
|
||||||
// Setup graceful shutdown
|
// Setup graceful shutdown
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Create a wait group to manage goroutines
|
// Create a wait group to manage goroutines
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
// Setup signal handling for graceful shutdown
|
// Setup signal handling for graceful shutdown
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
|
||||||
@@ -198,37 +198,37 @@ func main() {
|
|||||||
})
|
})
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Start monitoring server in a goroutine
|
// Start monitoring server in a goroutine
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
StartMonitoringServer()
|
StartMonitoringServer()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Give monitoring server time to initialize
|
// Give monitoring server time to initialize
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
// Start HTTP proxy in a goroutine
|
// Start HTTP proxy in a goroutine
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
StartHTTPProxy()
|
StartHTTPProxy()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for context cancellation
|
// Wait for context cancellation
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
||||||
// Perform cleanup
|
// Perform cleanup
|
||||||
cfg.Logger.Info(&libpack_logging.LogMessage{
|
cfg.Logger.Info(&libpack_logging.LogMessage{
|
||||||
Message: "Shutting down services...",
|
Message: "Shutting down services...",
|
||||||
})
|
})
|
||||||
|
|
||||||
// Cleanup tracing
|
// Cleanup tracing
|
||||||
if tracer != nil {
|
if tracer != nil {
|
||||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer shutdownCancel()
|
defer shutdownCancel()
|
||||||
|
|
||||||
if err := tracer.Shutdown(shutdownCtx); err != nil {
|
if err := tracer.Shutdown(shutdownCtx); err != nil {
|
||||||
cfg.Logger.Error(&libpack_logging.LogMessage{
|
cfg.Logger.Error(&libpack_logging.LogMessage{
|
||||||
Message: "Error shutting down tracer",
|
Message: "Error shutting down tracer",
|
||||||
@@ -236,14 +236,14 @@ func main() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all goroutines to finish (with timeout)
|
// Wait for all goroutines to finish (with timeout)
|
||||||
waitCh := make(chan struct{})
|
waitCh := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(waitCh)
|
close(waitCh)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-waitCh:
|
case <-waitCh:
|
||||||
cfg.Logger.Info(&libpack_logging.LogMessage{
|
cfg.Logger.Info(&libpack_logging.LogMessage{
|
||||||
|
|||||||
+2
-2
@@ -42,13 +42,13 @@ func (suite *Tests) SetupTest() {
|
|||||||
parseConfig()
|
parseConfig()
|
||||||
enableApi()
|
enableApi()
|
||||||
StartMonitoringServer()
|
StartMonitoringServer()
|
||||||
|
|
||||||
// Update logger with proper synchronization
|
// Update logger with proper synchronization
|
||||||
logger := libpack_logging.New().SetMinLogLevel(libpack_logging.GetLogLevel(getDetailsFromEnv("LOG_LEVEL", "info")))
|
logger := libpack_logging.New().SetMinLogLevel(libpack_logging.GetLogLevel(getDetailsFromEnv("LOG_LEVEL", "info")))
|
||||||
cfgMutex.Lock()
|
cfgMutex.Lock()
|
||||||
cfg.Logger = logger
|
cfg.Logger = logger
|
||||||
cfgMutex.Unlock()
|
cfgMutex.Unlock()
|
||||||
|
|
||||||
// Setup environment variables here if needed
|
// Setup environment variables here if needed
|
||||||
os.Setenv("GMP_TEST_STRING", "testValue")
|
os.Setenv("GMP_TEST_STRING", "testValue")
|
||||||
os.Setenv("GMP_TEST_INT", "123")
|
os.Setenv("GMP_TEST_INT", "123")
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ func (suite *MonitoringAdditionalTestSuite) TestListActiveMetrics() {
|
|||||||
// Register metrics directly to the set to ensure they're there
|
// Register metrics directly to the set to ensure they're there
|
||||||
suite.ms.metrics_set_custom.GetOrCreateCounter("test_counter{label=\"value\"}")
|
suite.ms.metrics_set_custom.GetOrCreateCounter("test_counter{label=\"value\"}")
|
||||||
suite.ms.metrics_set_custom.GetOrCreateGauge("test_gauge{label=\"value\"}", func() float64 { return 42.0 })
|
suite.ms.metrics_set_custom.GetOrCreateGauge("test_gauge{label=\"value\"}", func() float64 { return 42.0 })
|
||||||
|
|
||||||
// Get list of metrics
|
// Get list of metrics
|
||||||
metricsList := suite.ms.ListActiveMetrics()
|
metricsList := suite.ms.ListActiveMetrics()
|
||||||
|
|
||||||
// Verify metrics were registered - the metrics_set_custom doesn't get listed by ListActiveMetrics,
|
// Verify metrics were registered - the metrics_set_custom doesn't get listed by ListActiveMetrics,
|
||||||
// so we'll just check that the function runs without error
|
// so we'll just check that the function runs without error
|
||||||
assert.NotNil(suite.T(), metricsList, "Metrics list should not be nil")
|
assert.NotNil(suite.T(), metricsList, "Metrics list should not be nil")
|
||||||
@@ -46,10 +46,10 @@ func (suite *MonitoringAdditionalTestSuite) TestRegisterFloatCounter() {
|
|||||||
"label1": "value1",
|
"label1": "value1",
|
||||||
})
|
})
|
||||||
assert.NotNil(suite.T(), counter)
|
assert.NotNil(suite.T(), counter)
|
||||||
|
|
||||||
// Test using the counter
|
// Test using the counter
|
||||||
counter.Add(42.5)
|
counter.Add(42.5)
|
||||||
|
|
||||||
// We don't need to test invalid metric names since they log a critical message
|
// We don't need to test invalid metric names since they log a critical message
|
||||||
// which can cause the test to exit, and that's the expected behavior
|
// which can cause the test to exit, and that's the expected behavior
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func (suite *MonitoringAdditionalTestSuite) TestRegisterMetricsSummary() {
|
|||||||
"label1": "value1",
|
"label1": "value1",
|
||||||
})
|
})
|
||||||
assert.NotNil(suite.T(), summary)
|
assert.NotNil(suite.T(), summary)
|
||||||
|
|
||||||
// Test using the summary
|
// Test using the summary
|
||||||
summary.Update(42.5)
|
summary.Update(42.5)
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ func (suite *MonitoringAdditionalTestSuite) TestRegisterMetricsHistogram() {
|
|||||||
"label1": "value1",
|
"label1": "value1",
|
||||||
})
|
})
|
||||||
assert.NotNil(suite.T(), histogram)
|
assert.NotNil(suite.T(), histogram)
|
||||||
|
|
||||||
// Test using the histogram
|
// Test using the histogram
|
||||||
histogram.Update(42.5)
|
histogram.Update(42.5)
|
||||||
}
|
}
|
||||||
@@ -85,11 +85,11 @@ func (suite *MonitoringAdditionalTestSuite) TestUpdateDuration() {
|
|||||||
labels := map[string]string{
|
labels := map[string]string{
|
||||||
"label1": "value1",
|
"label1": "value1",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use UpdateDuration
|
// Use UpdateDuration
|
||||||
startTime := time.Now().Add(-time.Second) // 1 second ago
|
startTime := time.Now().Add(-time.Second) // 1 second ago
|
||||||
suite.ms.UpdateDuration(metricName, labels, startTime)
|
suite.ms.UpdateDuration(metricName, labels, startTime)
|
||||||
|
|
||||||
// Since we can't easily verify the duration was recorded correctly in a test,
|
// Since we can't easily verify the duration was recorded correctly in a test,
|
||||||
// we'll just verify the method doesn't crash
|
// we'll just verify the method doesn't crash
|
||||||
}
|
}
|
||||||
@@ -99,15 +99,15 @@ func (suite *MonitoringAdditionalTestSuite) TestUpdateDuration() {
|
|||||||
func (suite *MonitoringAdditionalTestSuite) TestPurgeMetrics() {
|
func (suite *MonitoringAdditionalTestSuite) TestPurgeMetrics() {
|
||||||
// Register a custom metric
|
// Register a custom metric
|
||||||
suite.ms.RegisterMetricsCounter("test_purge_counter", nil)
|
suite.ms.RegisterMetricsCounter("test_purge_counter", nil)
|
||||||
|
|
||||||
// Purge the metrics
|
// Purge the metrics
|
||||||
suite.ms.PurgeMetrics()
|
suite.ms.PurgeMetrics()
|
||||||
|
|
||||||
// Verify the custom metrics were purged
|
// Verify the custom metrics were purged
|
||||||
// We need to check the actual customSet instead of calling ListActiveMetrics
|
// We need to check the actual customSet instead of calling ListActiveMetrics
|
||||||
customMetrics := suite.ms.metrics_set_custom.ListMetricNames()
|
customMetrics := suite.ms.metrics_set_custom.ListMetricNames()
|
||||||
|
|
||||||
// The metrics might not be immediately cleared due to internal implementation details,
|
// The metrics might not be immediately cleared due to internal implementation details,
|
||||||
// so this test might be flaky. We'll check that it doesn't panic instead.
|
// so this test might be flaky. We'll check that it doesn't panic instead.
|
||||||
assert.NotNil(suite.T(), customMetrics, "Custom metrics list shouldn't be nil")
|
assert.NotNil(suite.T(), customMetrics, "Custom metrics list shouldn't be nil")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ func TestNewMonitoring(t *testing.T) {
|
|||||||
|
|
||||||
func TestAddMetricsPrefix(t *testing.T) {
|
func TestAddMetricsPrefix(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test adding prefix to a name
|
// Test adding prefix to a name
|
||||||
mon.AddMetricsPrefix("test")
|
mon.AddMetricsPrefix("test")
|
||||||
assert.Equal(t, "test", mon.metrics_prefix)
|
assert.Equal(t, "test", mon.metrics_prefix)
|
||||||
|
|
||||||
// Test with empty prefix
|
// Test with empty prefix
|
||||||
mon.AddMetricsPrefix("")
|
mon.AddMetricsPrefix("")
|
||||||
assert.Equal(t, "", mon.metrics_prefix)
|
assert.Equal(t, "", mon.metrics_prefix)
|
||||||
@@ -35,11 +35,11 @@ func TestAddMetricsPrefix(t *testing.T) {
|
|||||||
|
|
||||||
func TestRegisterMetricsGauge(t *testing.T) {
|
func TestRegisterMetricsGauge(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test registering a gauge
|
// Test registering a gauge
|
||||||
gauge := mon.RegisterMetricsGauge("valid_gauge", map[string]string{"label1": "value1"}, 42.0)
|
gauge := mon.RegisterMetricsGauge("valid_gauge", map[string]string{"label1": "value1"}, 42.0)
|
||||||
assert.NotNil(t, gauge)
|
assert.NotNil(t, gauge)
|
||||||
|
|
||||||
// Test with invalid metric name - we'll skip this test since it causes fatal errors
|
// Test with invalid metric name - we'll skip this test since it causes fatal errors
|
||||||
// gauge = mon.RegisterMetricsGauge("invalid metric name", map[string]string{"label1": "value1"}, 42.0)
|
// gauge = mon.RegisterMetricsGauge("invalid metric name", map[string]string{"label1": "value1"}, 42.0)
|
||||||
// assert.Nil(t, gauge)
|
// assert.Nil(t, gauge)
|
||||||
@@ -47,11 +47,11 @@ func TestRegisterMetricsGauge(t *testing.T) {
|
|||||||
|
|
||||||
func TestRegisterMetricsCounter(t *testing.T) {
|
func TestRegisterMetricsCounter(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test registering a counter
|
// Test registering a counter
|
||||||
counter := mon.RegisterMetricsCounter("valid_counter", map[string]string{"label1": "value1"})
|
counter := mon.RegisterMetricsCounter("valid_counter", map[string]string{"label1": "value1"})
|
||||||
assert.NotNil(t, counter)
|
assert.NotNil(t, counter)
|
||||||
|
|
||||||
// Test with default metrics
|
// Test with default metrics
|
||||||
counter = mon.RegisterMetricsCounter(MetricsSucceeded, map[string]string{"label1": "value1"})
|
counter = mon.RegisterMetricsCounter(MetricsSucceeded, map[string]string{"label1": "value1"})
|
||||||
assert.NotNil(t, counter)
|
assert.NotNil(t, counter)
|
||||||
@@ -59,7 +59,7 @@ func TestRegisterMetricsCounter(t *testing.T) {
|
|||||||
|
|
||||||
func TestRegisterFloatCounter(t *testing.T) {
|
func TestRegisterFloatCounter(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test registering a float counter
|
// Test registering a float counter
|
||||||
counter := mon.RegisterFloatCounter("valid_float_counter", map[string]string{"label1": "value1"})
|
counter := mon.RegisterFloatCounter("valid_float_counter", map[string]string{"label1": "value1"})
|
||||||
assert.NotNil(t, counter)
|
assert.NotNil(t, counter)
|
||||||
@@ -67,7 +67,7 @@ func TestRegisterFloatCounter(t *testing.T) {
|
|||||||
|
|
||||||
func TestRegisterMetricsSummary(t *testing.T) {
|
func TestRegisterMetricsSummary(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test registering a summary
|
// Test registering a summary
|
||||||
summary := mon.RegisterMetricsSummary("valid_summary", map[string]string{"label1": "value1"})
|
summary := mon.RegisterMetricsSummary("valid_summary", map[string]string{"label1": "value1"})
|
||||||
assert.NotNil(t, summary)
|
assert.NotNil(t, summary)
|
||||||
@@ -75,7 +75,7 @@ func TestRegisterMetricsSummary(t *testing.T) {
|
|||||||
|
|
||||||
func TestRegisterMetricsHistogram(t *testing.T) {
|
func TestRegisterMetricsHistogram(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test registering a histogram
|
// Test registering a histogram
|
||||||
histogram := mon.RegisterMetricsHistogram("valid_histogram", map[string]string{"label1": "value1"})
|
histogram := mon.RegisterMetricsHistogram("valid_histogram", map[string]string{"label1": "value1"})
|
||||||
assert.NotNil(t, histogram)
|
assert.NotNil(t, histogram)
|
||||||
@@ -83,59 +83,59 @@ func TestRegisterMetricsHistogram(t *testing.T) {
|
|||||||
|
|
||||||
func TestIncrement(t *testing.T) {
|
func TestIncrement(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test incrementing a counter
|
// Test incrementing a counter
|
||||||
mon.Increment("increment_counter", map[string]string{"label1": "value1"})
|
mon.Increment("increment_counter", map[string]string{"label1": "value1"})
|
||||||
|
|
||||||
// We can't easily verify the value was incremented in a test,
|
// We can't easily verify the value was incremented in a test,
|
||||||
// but we can verify the function doesn't panic
|
// but we can verify the function doesn't panic
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIncrementFloat(t *testing.T) {
|
func TestIncrementFloat(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test incrementing a float counter
|
// Test incrementing a float counter
|
||||||
mon.IncrementFloat("float_counter", map[string]string{"label1": "value1"}, 1.5)
|
mon.IncrementFloat("float_counter", map[string]string{"label1": "value1"}, 1.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
func TestSet(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test setting a gauge
|
// Test setting a gauge
|
||||||
mon.Set("set_gauge", map[string]string{"label1": "value1"}, 42)
|
mon.Set("set_gauge", map[string]string{"label1": "value1"}, 42)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdate(t *testing.T) {
|
func TestUpdate(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test updating a histogram
|
// Test updating a histogram
|
||||||
mon.Update("update_histogram", map[string]string{"label1": "value1"}, 42.0)
|
mon.Update("update_histogram", map[string]string{"label1": "value1"}, 42.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateSummary(t *testing.T) {
|
func TestUpdateSummary(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test updating a summary
|
// Test updating a summary
|
||||||
mon.UpdateSummary("update_summary", map[string]string{"label1": "value1"}, 42.0)
|
mon.UpdateSummary("update_summary", map[string]string{"label1": "value1"}, 42.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoveMetrics(t *testing.T) {
|
func TestRemoveMetrics(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Register a metric first
|
// Register a metric first
|
||||||
mon.RegisterMetricsGauge("remove_gauge", map[string]string{"label1": "value1"}, 42.0)
|
mon.RegisterMetricsGauge("remove_gauge", map[string]string{"label1": "value1"}, 42.0)
|
||||||
|
|
||||||
// Test removing a metric
|
// Test removing a metric
|
||||||
mon.RemoveMetrics("remove_gauge", map[string]string{"label1": "value1"})
|
mon.RemoveMetrics("remove_gauge", map[string]string{"label1": "value1"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPurgeMetrics(t *testing.T) {
|
func TestPurgeMetrics(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Register some metrics first
|
// Register some metrics first
|
||||||
mon.RegisterMetricsGauge("purge_gauge1", map[string]string{"label1": "value1"}, 42.0)
|
mon.RegisterMetricsGauge("purge_gauge1", map[string]string{"label1": "value1"}, 42.0)
|
||||||
mon.RegisterMetricsGauge("purge_gauge2", map[string]string{"label1": "value1"}, 42.0)
|
mon.RegisterMetricsGauge("purge_gauge2", map[string]string{"label1": "value1"}, 42.0)
|
||||||
|
|
||||||
// Test purging all metrics
|
// Test purging all metrics
|
||||||
mon.PurgeMetrics()
|
mon.PurgeMetrics()
|
||||||
}
|
}
|
||||||
@@ -143,15 +143,15 @@ func TestPurgeMetrics(t *testing.T) {
|
|||||||
func TestListActiveMetrics(t *testing.T) {
|
func TestListActiveMetrics(t *testing.T) {
|
||||||
// Skip this test as it's causing issues with the metrics registry
|
// Skip this test as it's causing issues with the metrics registry
|
||||||
t.Skip("Skipping test due to issues with metrics registry")
|
t.Skip("Skipping test due to issues with metrics registry")
|
||||||
|
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Register some metrics first - use the default metrics set
|
// Register some metrics first - use the default metrics set
|
||||||
mon.RegisterDefaultMetrics()
|
mon.RegisterDefaultMetrics()
|
||||||
|
|
||||||
// Give some time for metrics to register
|
// Give some time for metrics to register
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
// Test listing active metrics
|
// Test listing active metrics
|
||||||
metrics := mon.ListActiveMetrics()
|
metrics := mon.ListActiveMetrics()
|
||||||
assert.NotEmpty(t, metrics)
|
assert.NotEmpty(t, metrics)
|
||||||
@@ -159,18 +159,18 @@ func TestListActiveMetrics(t *testing.T) {
|
|||||||
|
|
||||||
func TestMetricsEndpoint(t *testing.T) {
|
func TestMetricsEndpoint(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Register a metric
|
// Register a metric
|
||||||
mon.RegisterMetricsGauge("endpoint_gauge", map[string]string{}, 42.0)
|
mon.RegisterMetricsGauge("endpoint_gauge", map[string]string{}, 42.0)
|
||||||
|
|
||||||
// Create a test Fiber app
|
// Create a test Fiber app
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
app.Get("/metrics", mon.metricsEndpoint)
|
app.Get("/metrics", mon.metricsEndpoint)
|
||||||
|
|
||||||
// Create a test request
|
// Create a test request
|
||||||
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
req := httptest.NewRequest(http.MethodGet, "/metrics", nil)
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
|
|
||||||
// Verify the response
|
// Verify the response
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
@@ -178,10 +178,10 @@ func TestMetricsEndpoint(t *testing.T) {
|
|||||||
|
|
||||||
func TestRegisterDefaultMetricsFunc(t *testing.T) {
|
func TestRegisterDefaultMetricsFunc(t *testing.T) {
|
||||||
mon := NewMonitoring(&InitConfig{})
|
mon := NewMonitoring(&InitConfig{})
|
||||||
|
|
||||||
// Test registering default metrics
|
// Test registering default metrics
|
||||||
mon.RegisterDefaultMetrics()
|
mon.RegisterDefaultMetrics()
|
||||||
|
|
||||||
// We can't easily verify the metrics were registered in a test,
|
// We can't easily verify the metrics were registered in a test,
|
||||||
// but we can verify the function doesn't panic
|
// but we can verify the function doesn't panic
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
@@ -198,7 +198,7 @@ func TestHelperFunctions(t *testing.T) {
|
|||||||
assert.True(t, is_allowed_rune(' '))
|
assert.True(t, is_allowed_rune(' '))
|
||||||
assert.False(t, is_allowed_rune('-'))
|
assert.False(t, is_allowed_rune('-'))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test is_special_rune
|
// Test is_special_rune
|
||||||
t.Run("is_special_rune", func(t *testing.T) {
|
t.Run("is_special_rune", func(t *testing.T) {
|
||||||
assert.True(t, is_special_rune('_'))
|
assert.True(t, is_special_rune('_'))
|
||||||
@@ -211,4 +211,4 @@ func TestGetPodNameFunc(t *testing.T) {
|
|||||||
// Test getting pod name
|
// Test getting pod name
|
||||||
podName := getPodName()
|
podName := getPodName()
|
||||||
assert.NotEmpty(t, podName)
|
assert.NotEmpty(t, podName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func proxyTheRequest(c *fiber.Ctx, currentEndpoint string) error {
|
|||||||
// Setup tracing if enabled
|
// Setup tracing if enabled
|
||||||
var span trace.Span
|
var span trace.Span
|
||||||
ctx := setupTracing(c)
|
ctx := setupTracing(c)
|
||||||
|
|
||||||
if cfg.Tracing.Enable && tracer != nil {
|
if cfg.Tracing.Enable && tracer != nil {
|
||||||
span, ctx = tracer.StartSpan(ctx, "proxy_request")
|
span, ctx = tracer.StartSpan(ctx, "proxy_request")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -102,11 +102,11 @@ func proxyTheRequest(c *fiber.Ctx, currentEndpoint string) error {
|
|||||||
// setupTracing extracts and sets up tracing context from request headers
|
// setupTracing extracts and sets up tracing context from request headers
|
||||||
func setupTracing(c *fiber.Ctx) context.Context {
|
func setupTracing(c *fiber.Ctx) context.Context {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
if !cfg.Tracing.Enable || tracer == nil {
|
if !cfg.Tracing.Enable || tracer == nil {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract trace information from header
|
// Extract trace information from header
|
||||||
if traceHeader := c.Get("X-Trace-Span"); traceHeader != "" {
|
if traceHeader := c.Get("X-Trace-Span"); traceHeader != "" {
|
||||||
spanInfo, err := libpack_tracing.ParseTraceHeader(traceHeader)
|
spanInfo, err := libpack_tracing.ParseTraceHeader(traceHeader)
|
||||||
@@ -119,7 +119,7 @@ func setupTracing(c *fiber.Ctx) context.Context {
|
|||||||
ctx = trace.ContextWithSpanContext(ctx, spanCtx)
|
ctx = trace.ContextWithSpanContext(ctx, spanCtx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ func handleGzippedResponse(c *fiber.Ctx) error {
|
|||||||
if !bytes.EqualFold(c.Response().Header.Peek("Content-Encoding"), []byte("gzip")) {
|
if !bytes.EqualFold(c.Response().Header.Peek("Content-Encoding"), []byte("gzip")) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a pooled gzip reader
|
// Create a pooled gzip reader
|
||||||
reader, err := gzip.NewReader(bytes.NewReader(c.Response().Body()))
|
reader, err := gzip.NewReader(bytes.NewReader(c.Response().Body()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+28
-28
@@ -15,11 +15,11 @@ func (suite *Tests) Test_loadRatelimitConfig() {
|
|||||||
cfg = &config{}
|
cfg = &config{}
|
||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
|
|
||||||
// Create a temporary test ratelimit.json file
|
// Create a temporary test ratelimit.json file
|
||||||
tempDir := os.TempDir()
|
tempDir := os.TempDir()
|
||||||
testConfigPath := filepath.Join(tempDir, "test_ratelimit.json")
|
testConfigPath := filepath.Join(tempDir, "test_ratelimit.json")
|
||||||
|
|
||||||
testConfig := struct {
|
testConfig := struct {
|
||||||
RateLimit map[string]RateLimitConfig `json:"ratelimit"`
|
RateLimit map[string]RateLimitConfig `json:"ratelimit"`
|
||||||
}{
|
}{
|
||||||
@@ -34,28 +34,28 @@ func (suite *Tests) Test_loadRatelimitConfig() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
configData, err := json.Marshal(testConfig)
|
configData, err := json.Marshal(testConfig)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
err = os.WriteFile(testConfigPath, configData, 0644)
|
err = os.WriteFile(testConfigPath, configData, 0644)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
defer os.Remove(testConfigPath)
|
defer os.Remove(testConfigPath)
|
||||||
|
|
||||||
// Test loading config from custom path
|
// Test loading config from custom path
|
||||||
suite.Run("load from custom path", func() {
|
suite.Run("load from custom path", func() {
|
||||||
// Clear existing rate limits
|
// Clear existing rate limits
|
||||||
rateLimitMu.Lock()
|
rateLimitMu.Lock()
|
||||||
rateLimits = make(map[string]RateLimitConfig)
|
rateLimits = make(map[string]RateLimitConfig)
|
||||||
rateLimitMu.Unlock()
|
rateLimitMu.Unlock()
|
||||||
|
|
||||||
err := loadConfigFromPath(testConfigPath)
|
err := loadConfigFromPath(testConfigPath)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
// Verify rate limits were loaded
|
// Verify rate limits were loaded
|
||||||
rateLimitMu.RLock()
|
rateLimitMu.RLock()
|
||||||
defer rateLimitMu.RUnlock()
|
defer rateLimitMu.RUnlock()
|
||||||
|
|
||||||
assert.Equal(2, len(rateLimits))
|
assert.Equal(2, len(rateLimits))
|
||||||
assert.Contains(rateLimits, "admin")
|
assert.Contains(rateLimits, "admin")
|
||||||
assert.Contains(rateLimits, "user")
|
assert.Contains(rateLimits, "user")
|
||||||
@@ -64,24 +64,24 @@ func (suite *Tests) Test_loadRatelimitConfig() {
|
|||||||
assert.NotNil(rateLimits["admin"].RateCounterTicker)
|
assert.NotNil(rateLimits["admin"].RateCounterTicker)
|
||||||
assert.NotNil(rateLimits["user"].RateCounterTicker)
|
assert.NotNil(rateLimits["user"].RateCounterTicker)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test loading config from non-existent path
|
// Test loading config from non-existent path
|
||||||
suite.Run("load from non-existent path", func() {
|
suite.Run("load from non-existent path", func() {
|
||||||
err := loadConfigFromPath("/non/existent/path.json")
|
err := loadConfigFromPath("/non/existent/path.json")
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test loading config with invalid JSON
|
// Test loading config with invalid JSON
|
||||||
suite.Run("load invalid JSON", func() {
|
suite.Run("load invalid JSON", func() {
|
||||||
invalidPath := filepath.Join(tempDir, "invalid_ratelimit.json")
|
invalidPath := filepath.Join(tempDir, "invalid_ratelimit.json")
|
||||||
err := os.WriteFile(invalidPath, []byte("{invalid json}"), 0644)
|
err := os.WriteFile(invalidPath, []byte("{invalid json}"), 0644)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
defer os.Remove(invalidPath)
|
defer os.Remove(invalidPath)
|
||||||
|
|
||||||
err = loadConfigFromPath(invalidPath)
|
err = loadConfigFromPath(invalidPath)
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with a temporary ratelimit.json file in the current directory
|
// Test with a temporary ratelimit.json file in the current directory
|
||||||
suite.Run("load from current directory", func() {
|
suite.Run("load from current directory", func() {
|
||||||
// Create a temporary ratelimit.json in current directory
|
// Create a temporary ratelimit.json in current directory
|
||||||
@@ -89,23 +89,23 @@ func (suite *Tests) Test_loadRatelimitConfig() {
|
|||||||
err := os.WriteFile(currentDirPath, configData, 0644)
|
err := os.WriteFile(currentDirPath, configData, 0644)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
defer os.Remove(currentDirPath)
|
defer os.Remove(currentDirPath)
|
||||||
|
|
||||||
// Clear existing rate limits
|
// Clear existing rate limits
|
||||||
rateLimitMu.Lock()
|
rateLimitMu.Lock()
|
||||||
rateLimits = make(map[string]RateLimitConfig)
|
rateLimits = make(map[string]RateLimitConfig)
|
||||||
rateLimitMu.Unlock()
|
rateLimitMu.Unlock()
|
||||||
|
|
||||||
// This should find the file in the current directory
|
// This should find the file in the current directory
|
||||||
err = loadRatelimitConfig()
|
err = loadRatelimitConfig()
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
// Verify rate limits were loaded
|
// Verify rate limits were loaded
|
||||||
rateLimitMu.RLock()
|
rateLimitMu.RLock()
|
||||||
defer rateLimitMu.RUnlock()
|
defer rateLimitMu.RUnlock()
|
||||||
|
|
||||||
assert.Equal(2, len(rateLimits))
|
assert.Equal(2, len(rateLimits))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with all files missing
|
// Test with all files missing
|
||||||
suite.Run("all files missing", func() {
|
suite.Run("all files missing", func() {
|
||||||
// Save the original file if it exists
|
// Save the original file if it exists
|
||||||
@@ -121,12 +121,12 @@ func (suite *Tests) Test_loadRatelimitConfig() {
|
|||||||
os.WriteFile(currentDirPath, originalData, 0644)
|
os.WriteFile(currentDirPath, originalData, 0644)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Clear existing rate limits
|
// Clear existing rate limits
|
||||||
rateLimitMu.Lock()
|
rateLimitMu.Lock()
|
||||||
rateLimits = make(map[string]RateLimitConfig)
|
rateLimits = make(map[string]RateLimitConfig)
|
||||||
rateLimitMu.Unlock()
|
rateLimitMu.Unlock()
|
||||||
|
|
||||||
// This should fail as all files are missing
|
// This should fail as all files are missing
|
||||||
err = loadRatelimitConfig()
|
err = loadRatelimitConfig()
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
@@ -139,11 +139,11 @@ func (suite *Tests) Test_rateLimitedRequest() {
|
|||||||
cfg = &config{}
|
cfg = &config{}
|
||||||
parseConfig()
|
parseConfig()
|
||||||
cfg.Logger = libpack_logger.New()
|
cfg.Logger = libpack_logger.New()
|
||||||
|
|
||||||
// Create test rate limits
|
// Create test rate limits
|
||||||
rateLimitMu.Lock()
|
rateLimitMu.Lock()
|
||||||
rateLimits = make(map[string]RateLimitConfig)
|
rateLimits = make(map[string]RateLimitConfig)
|
||||||
|
|
||||||
// Admin role with high limit
|
// Admin role with high limit
|
||||||
adminCounter := goratecounter.NewRateCounter().WithConfig(goratecounter.RateCounterConfig{
|
adminCounter := goratecounter.NewRateCounter().WithConfig(goratecounter.RateCounterConfig{
|
||||||
Interval: 1 * time.Second,
|
Interval: 1 * time.Second,
|
||||||
@@ -153,7 +153,7 @@ func (suite *Tests) Test_rateLimitedRequest() {
|
|||||||
Interval: 1 * time.Second,
|
Interval: 1 * time.Second,
|
||||||
Req: 100,
|
Req: 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
// User role with low limit
|
// User role with low limit
|
||||||
userCounter := goratecounter.NewRateCounter().WithConfig(goratecounter.RateCounterConfig{
|
userCounter := goratecounter.NewRateCounter().WithConfig(goratecounter.RateCounterConfig{
|
||||||
Interval: 1 * time.Second,
|
Interval: 1 * time.Second,
|
||||||
@@ -164,31 +164,31 @@ func (suite *Tests) Test_rateLimitedRequest() {
|
|||||||
Req: 2, // Set very low for testing
|
Req: 2, // Set very low for testing
|
||||||
}
|
}
|
||||||
rateLimitMu.Unlock()
|
rateLimitMu.Unlock()
|
||||||
|
|
||||||
// Test non-existent role
|
// Test non-existent role
|
||||||
suite.Run("non-existent role", func() {
|
suite.Run("non-existent role", func() {
|
||||||
allowed := rateLimitedRequest("test-user-1", "non-existent-role")
|
allowed := rateLimitedRequest("test-user-1", "non-existent-role")
|
||||||
assert.True(allowed, "Unknown roles should return true")
|
assert.True(allowed, "Unknown roles should return true")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test admin role (high limit)
|
// Test admin role (high limit)
|
||||||
suite.Run("admin role within limit", func() {
|
suite.Run("admin role within limit", func() {
|
||||||
allowed := rateLimitedRequest("admin-user", "admin")
|
allowed := rateLimitedRequest("admin-user", "admin")
|
||||||
assert.True(allowed, "Admin should be within rate limit")
|
assert.True(allowed, "Admin should be within rate limit")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test user role (low limit)
|
// Test user role (low limit)
|
||||||
suite.Run("user role within limit", func() {
|
suite.Run("user role within limit", func() {
|
||||||
// First request should be allowed
|
// First request should be allowed
|
||||||
allowed := rateLimitedRequest("regular-user", "user")
|
allowed := rateLimitedRequest("regular-user", "user")
|
||||||
assert.True(allowed, "First request should be within rate limit")
|
assert.True(allowed, "First request should be within rate limit")
|
||||||
|
|
||||||
// Second request should be allowed
|
// Second request should be allowed
|
||||||
allowed = rateLimitedRequest("regular-user", "user")
|
allowed = rateLimitedRequest("regular-user", "user")
|
||||||
assert.True(allowed, "Second request should be within rate limit")
|
assert.True(allowed, "Second request should be within rate limit")
|
||||||
|
|
||||||
// Third request should exceed limit
|
// Third request should exceed limit
|
||||||
allowed = rateLimitedRequest("regular-user", "user")
|
allowed = rateLimitedRequest("regular-user", "user")
|
||||||
assert.False(allowed, "Third request should exceed rate limit")
|
assert.False(allowed, "Third request should exceed rate limit")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func processGraphQLRequest(c *fiber.Ctx) error {
|
|||||||
|
|
||||||
// Extract user information and check permissions
|
// Extract user information and check permissions
|
||||||
extractedUserID, extractedRoleName := extractUserInfo(c)
|
extractedUserID, extractedRoleName := extractUserInfo(c)
|
||||||
|
|
||||||
// Check if user is banned
|
// Check if user is banned
|
||||||
if checkIfUserIsBanned(c, extractedUserID) {
|
if checkIfUserIsBanned(c, extractedUserID) {
|
||||||
return c.Status(fiber.StatusForbidden).SendString("User is banned")
|
return c.Status(fiber.StatusForbidden).SendString("User is banned")
|
||||||
@@ -157,7 +157,7 @@ func extractUserInfo(c *fiber.Ctx) (string, string) {
|
|||||||
|
|
||||||
// Extract from JWT if available
|
// Extract from JWT if available
|
||||||
if authorization := c.Get("Authorization"); authorization != "" &&
|
if authorization := c.Get("Authorization"); authorization != "" &&
|
||||||
(len(cfg.Client.JWTUserClaimPath) > 0 || len(cfg.Client.JWTRoleClaimPath) > 0) {
|
(len(cfg.Client.JWTUserClaimPath) > 0 || len(cfg.Client.JWTRoleClaimPath) > 0) {
|
||||||
extractedUserID, extractedRoleName = extractClaimsFromJWTHeader(authorization)
|
extractedUserID, extractedRoleName = extractClaimsFromJWTHeader(authorization)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ func extractUserInfo(c *fiber.Ctx) (string, string) {
|
|||||||
func handleCaching(c *fiber.Ctx, parsedResult *parseGraphQLQueryResult, userID string) (bool, error) {
|
func handleCaching(c *fiber.Ctx, parsedResult *parseGraphQLQueryResult, userID string) (bool, error) {
|
||||||
// Calculate query hash for cache key
|
// Calculate query hash for cache key
|
||||||
calculatedQueryHash := libpack_cache.CalculateHash(c)
|
calculatedQueryHash := libpack_cache.CalculateHash(c)
|
||||||
|
|
||||||
// Set cache time from header or default
|
// Set cache time from header or default
|
||||||
if parsedResult.cacheTime == 0 {
|
if parsedResult.cacheTime == 0 {
|
||||||
if cacheQuery := c.Get("X-Cache-Graphql-Query"); cacheQuery != "" {
|
if cacheQuery := c.Get("X-Cache-Graphql-Query"); cacheQuery != "" {
|
||||||
@@ -214,9 +214,10 @@ func handleCaching(c *fiber.Ctx, parsedResult *parseGraphQLQueryResult, userID s
|
|||||||
if err := proxyAndCacheTheRequest(c, calculatedQueryHash, parsedResult.cacheTime, parsedResult.activeEndpoint); err != nil {
|
if err := proxyAndCacheTheRequest(c, calculatedQueryHash, parsedResult.cacheTime, parsedResult.activeEndpoint); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxyAndCacheTheRequest proxies and caches the request if needed.
|
// proxyAndCacheTheRequest proxies and caches the request if needed.
|
||||||
func proxyAndCacheTheRequest(c *fiber.Ctx, queryCacheHash string, cacheTime int, currentEndpoint string) error {
|
func proxyAndCacheTheRequest(c *fiber.Ctx, queryCacheHash string, cacheTime int, currentEndpoint string) error {
|
||||||
if err := proxyTheRequest(c, currentEndpoint); err != nil {
|
if err := proxyTheRequest(c, currentEndpoint); err != nil {
|
||||||
|
|||||||
+8
-8
@@ -68,8 +68,8 @@ func NewTracing(ctx context.Context, endpoint string) (*TracingSetup, error) {
|
|||||||
semconv.DeploymentEnvironment("production"),
|
semconv.DeploymentEnvironment("production"),
|
||||||
attribute.String("application.type", "proxy"),
|
attribute.String("application.type", "proxy"),
|
||||||
),
|
),
|
||||||
resource.WithHost(), // Add host information
|
resource.WithHost(), // Add host information
|
||||||
resource.WithOSType(), // Add OS information
|
resource.WithOSType(), // Add OS information
|
||||||
resource.WithProcessPID(), // Add process information
|
resource.WithProcessPID(), // Add process information
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -87,7 +87,7 @@ func NewTracing(ctx context.Context, endpoint string) (*TracingSetup, error) {
|
|||||||
sdktrace.WithResource(res),
|
sdktrace.WithResource(res),
|
||||||
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(0.1)), // Sample 10% of traces
|
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(0.1)), // Sample 10% of traces
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set the global tracer provider and propagator
|
// Set the global tracer provider and propagator
|
||||||
otel.SetTracerProvider(tracerProvider)
|
otel.SetTracerProvider(tracerProvider)
|
||||||
otel.SetTextMapPropagator(propagation.TraceContext{})
|
otel.SetTextMapPropagator(propagation.TraceContext{})
|
||||||
@@ -138,7 +138,7 @@ func (ts *TracingSetup) StartSpan(ctx context.Context, name string) (trace.Span,
|
|||||||
// Return a no-op span if tracing is not configured
|
// Return a no-op span if tracing is not configured
|
||||||
return trace.SpanFromContext(ctx), ctx
|
return trace.SpanFromContext(ctx), ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add common attributes to all spans
|
// Add common attributes to all spans
|
||||||
opts := []trace.SpanStartOption{
|
opts := []trace.SpanStartOption{
|
||||||
trace.WithAttributes(
|
trace.WithAttributes(
|
||||||
@@ -146,7 +146,7 @@ func (ts *TracingSetup) StartSpan(ctx context.Context, name string) (trace.Span,
|
|||||||
semconv.ServiceVersion("1.0"),
|
semconv.ServiceVersion("1.0"),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, span := ts.tracer.Start(ctx, name, opts...)
|
ctx, span := ts.tracer.Start(ctx, name, opts...)
|
||||||
return span, ctx
|
return span, ctx
|
||||||
}
|
}
|
||||||
@@ -156,18 +156,18 @@ func (ts *TracingSetup) StartSpanWithAttributes(ctx context.Context, name string
|
|||||||
if ts == nil || ts.tracer == nil {
|
if ts == nil || ts.tracer == nil {
|
||||||
return trace.SpanFromContext(ctx), ctx
|
return trace.SpanFromContext(ctx), ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert string attributes to KeyValue pairs
|
// Convert string attributes to KeyValue pairs
|
||||||
attributes := make([]attribute.KeyValue, 0, len(attrs)+2)
|
attributes := make([]attribute.KeyValue, 0, len(attrs)+2)
|
||||||
attributes = append(attributes,
|
attributes = append(attributes,
|
||||||
semconv.ServiceName("graphql-monitoring-proxy"),
|
semconv.ServiceName("graphql-monitoring-proxy"),
|
||||||
semconv.ServiceVersion("1.0"),
|
semconv.ServiceVersion("1.0"),
|
||||||
)
|
)
|
||||||
|
|
||||||
for k, v := range attrs {
|
for k, v := range attrs {
|
||||||
attributes = append(attributes, attribute.String(k, v))
|
attributes = append(attributes, attribute.String(k, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, span := ts.tracer.Start(ctx, name, trace.WithAttributes(attributes...))
|
ctx, span := ts.tracer.Start(ctx, name, trace.WithAttributes(attributes...))
|
||||||
return span, ctx
|
return span, ctx
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func TestStartSpanWithAttributes(t *testing.T) {
|
|||||||
span, newCtx := ts.StartSpanWithAttributes(ctx, "test-span", attrs)
|
span, newCtx := ts.StartSpanWithAttributes(ctx, "test-span", attrs)
|
||||||
assert.NotNil(t, span)
|
assert.NotNil(t, span)
|
||||||
assert.NotNil(t, newCtx)
|
assert.NotNil(t, newCtx)
|
||||||
|
|
||||||
// We can't easily test the attributes were set since it's a noop tracer,
|
// We can't easily test the attributes were set since it's a noop tracer,
|
||||||
// but we can verify the function doesn't panic
|
// but we can verify the function doesn't panic
|
||||||
span.End()
|
span.End()
|
||||||
@@ -36,7 +36,7 @@ func TestStartSpanWithAttributes(t *testing.T) {
|
|||||||
// Test with nil attributes
|
// Test with nil attributes
|
||||||
t.Run("with nil attributes", func(t *testing.T) {
|
t.Run("with nil attributes", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
span, newCtx := ts.StartSpanWithAttributes(ctx, "test-span", nil)
|
span, newCtx := ts.StartSpanWithAttributes(ctx, "test-span", nil)
|
||||||
assert.NotNil(t, span)
|
assert.NotNil(t, span)
|
||||||
assert.NotNil(t, newCtx)
|
assert.NotNil(t, newCtx)
|
||||||
@@ -47,7 +47,7 @@ func TestStartSpanWithAttributes(t *testing.T) {
|
|||||||
t.Run("with nil tracer", func(t *testing.T) {
|
t.Run("with nil tracer", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
nilTS := &TracingSetup{tracer: nil}
|
nilTS := &TracingSetup{tracer: nil}
|
||||||
|
|
||||||
span, newCtx := nilTS.StartSpanWithAttributes(ctx, "test-span", map[string]string{"key": "value"})
|
span, newCtx := nilTS.StartSpanWithAttributes(ctx, "test-span", map[string]string{"key": "value"})
|
||||||
assert.NotNil(t, span)
|
assert.NotNil(t, span)
|
||||||
assert.NotNil(t, newCtx)
|
assert.NotNil(t, newCtx)
|
||||||
@@ -58,19 +58,19 @@ func TestStartSpanWithAttributes(t *testing.T) {
|
|||||||
|
|
||||||
func TestNewTracingWithInvalidEndpoint(t *testing.T) {
|
func TestNewTracingWithInvalidEndpoint(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Test with invalid endpoint format
|
// Test with invalid endpoint format
|
||||||
t.Run("invalid endpoint format", func(t *testing.T) {
|
t.Run("invalid endpoint format", func(t *testing.T) {
|
||||||
_, err := NewTracing(ctx, "invalid:endpoint:format")
|
_, err := NewTracing(ctx, "invalid:endpoint:format")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with unreachable endpoint
|
// Test with unreachable endpoint
|
||||||
t.Run("unreachable endpoint", func(t *testing.T) {
|
t.Run("unreachable endpoint", func(t *testing.T) {
|
||||||
// Use a timeout to avoid long test times
|
// Use a timeout to avoid long test times
|
||||||
ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
_, err := NewTracing(ctx, "localhost:1") // Port 1 is typically unused
|
_, err := NewTracing(ctx, "localhost:1") // Port 1 is typically unused
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
@@ -80,28 +80,28 @@ func TestTracingSetupWithMockTracer(t *testing.T) {
|
|||||||
// Create a mock tracer provider
|
// Create a mock tracer provider
|
||||||
mockTracerProvider := trace.NewNoopTracerProvider()
|
mockTracerProvider := trace.NewNoopTracerProvider()
|
||||||
mockTracer := mockTracerProvider.Tracer("mock-tracer")
|
mockTracer := mockTracerProvider.Tracer("mock-tracer")
|
||||||
|
|
||||||
ts := &TracingSetup{
|
ts := &TracingSetup{
|
||||||
tracerProvider: nil, // We don't need the provider for these tests
|
tracerProvider: nil, // We don't need the provider for these tests
|
||||||
tracer: mockTracer,
|
tracer: mockTracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test StartSpan
|
// Test StartSpan
|
||||||
t.Run("start span", func(t *testing.T) {
|
t.Run("start span", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
span, newCtx := ts.StartSpan(ctx, "test-span")
|
span, newCtx := ts.StartSpan(ctx, "test-span")
|
||||||
|
|
||||||
assert.NotNil(t, span)
|
assert.NotNil(t, span)
|
||||||
assert.NotNil(t, newCtx)
|
assert.NotNil(t, newCtx)
|
||||||
|
|
||||||
// Add some attributes and events to ensure no panics
|
// Add some attributes and events to ensure no panics
|
||||||
span.SetAttributes(attribute.String("test", "value"))
|
span.SetAttributes(attribute.String("test", "value"))
|
||||||
span.AddEvent("test-event")
|
span.AddEvent("test-event")
|
||||||
|
|
||||||
// End the span
|
// End the span
|
||||||
span.End()
|
span.End()
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test StartSpanWithAttributes
|
// Test StartSpanWithAttributes
|
||||||
t.Run("start span with attributes", func(t *testing.T) {
|
t.Run("start span with attributes", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -109,12 +109,12 @@ func TestTracingSetupWithMockTracer(t *testing.T) {
|
|||||||
"service": "test-service",
|
"service": "test-service",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
}
|
}
|
||||||
|
|
||||||
span, newCtx := ts.StartSpanWithAttributes(ctx, "test-span-with-attrs", attrs)
|
span, newCtx := ts.StartSpanWithAttributes(ctx, "test-span-with-attrs", attrs)
|
||||||
|
|
||||||
assert.NotNil(t, span)
|
assert.NotNil(t, span)
|
||||||
assert.NotNil(t, newCtx)
|
assert.NotNil(t, newCtx)
|
||||||
|
|
||||||
// End the span
|
// End the span
|
||||||
span.End()
|
span.End()
|
||||||
})
|
})
|
||||||
@@ -125,10 +125,10 @@ func TestShutdownWithNilProvider(t *testing.T) {
|
|||||||
tracerProvider: nil,
|
tracerProvider: nil,
|
||||||
tracer: trace.NewNoopTracerProvider().Tracer("test"),
|
tracer: trace.NewNoopTracerProvider().Tracer("test"),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := ts.Shutdown(ctx)
|
err := ts.Shutdown(ctx)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,13 +136,13 @@ func TestExtractSpanContextWithInvalidTraceParent(t *testing.T) {
|
|||||||
ts := &TracingSetup{
|
ts := &TracingSetup{
|
||||||
tracer: trace.NewNoopTracerProvider().Tracer("test"),
|
tracer: trace.NewNoopTracerProvider().Tracer("test"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with invalid traceparent format
|
// Test with invalid traceparent format
|
||||||
t.Run("invalid traceparent format", func(t *testing.T) {
|
t.Run("invalid traceparent format", func(t *testing.T) {
|
||||||
spanInfo := &TraceSpanInfo{
|
spanInfo := &TraceSpanInfo{
|
||||||
TraceParent: "invalid-format",
|
TraceParent: "invalid-format",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ts.ExtractSpanContext(spanInfo)
|
_, err := ts.ExtractSpanContext(spanInfo)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.Error(), "invalid span context")
|
assert.Contains(t, err.Error(), "invalid span context")
|
||||||
@@ -155,16 +155,16 @@ func TestParseTraceHeaderWithEmptyHeader(t *testing.T) {
|
|||||||
_, err := ParseTraceHeader("")
|
_, err := ParseTraceHeader("")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with invalid JSON
|
// Test with invalid JSON
|
||||||
t.Run("invalid JSON", func(t *testing.T) {
|
t.Run("invalid JSON", func(t *testing.T) {
|
||||||
_, err := ParseTraceHeader("{invalid json}")
|
_, err := ParseTraceHeader("{invalid json}")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with valid JSON but missing traceparent
|
// Test with valid JSON but missing traceparent
|
||||||
t.Run("missing traceparent", func(t *testing.T) {
|
t.Run("missing traceparent", func(t *testing.T) {
|
||||||
_, err := ParseTraceHeader(`{"other": "value"}`)
|
_, err := ParseTraceHeader(`{"other": "value"}`)
|
||||||
assert.NoError(t, err) // This should parse but the traceparent will be empty
|
assert.NoError(t, err) // This should parse but the traceparent will be empty
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user