Add cache configuration to cli
Change-Id: I22b7eb9bd9a2fb9e7106ff20487e285638c5320f
diff --git a/.gitignore b/.gitignore
index c0ab5c2..a1fe5c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,4 +52,5 @@
progress.txt
README.md
/korap-mcp
+/examples
sandbox
\ No newline at end of file
diff --git a/cmd/korap-mcp/config.go b/cmd/korap-mcp/config.go
index 4cd1be9..ae0e63d 100644
--- a/cmd/korap-mcp/config.go
+++ b/cmd/korap-mcp/config.go
@@ -29,6 +29,9 @@
// KorAP API configuration
KorAP config.KorAPConfig `embed:"" prefix:"korap-"`
+ // Cache configuration
+ Cache config.CacheConfig `embed:"" prefix:"cache-"`
+
// Logging configuration
Logging config.LoggingConfig `embed:"" prefix:"log-"`
@@ -44,6 +47,7 @@
cli := CLI{
OAuth: cfg.OAuth,
KorAP: cfg.KorAP,
+ Cache: cfg.Cache,
Logging: cfg.Logging,
}
@@ -92,6 +96,7 @@
},
OAuth: c.OAuth,
KorAP: c.KorAP,
+ Cache: c.Cache,
Logging: c.Logging,
}
@@ -119,6 +124,7 @@
},
OAuth: c.OAuth,
KorAP: c.KorAP,
+ Cache: c.Cache,
Logging: c.Logging,
}
}
diff --git a/config/cache.go b/config/cache.go
new file mode 100644
index 0000000..2e6ffaa
--- /dev/null
+++ b/config/cache.go
@@ -0,0 +1,100 @@
+package config
+
+import (
+ "fmt"
+ "time"
+)
+
+// CacheConfig configures the cache behavior
+type CacheConfig struct {
+ // Enabled controls whether caching is active
+ Enabled bool `yaml:"enabled" default:"true" help:"Enable response caching"`
+
+ // DefaultTTL is the default time-to-live for cache entries
+ DefaultTTL string `yaml:"default_ttl" default:"5m" help:"Default cache TTL (e.g., '5m', '1h')"`
+
+ // SearchTTL is the TTL for search results
+ SearchTTL string `yaml:"search_ttl" default:"2m" help:"Cache TTL for search results (e.g., '2m', '30s')"`
+
+ // MetadataTTL is the TTL for metadata and corpus information
+ MetadataTTL string `yaml:"metadata_ttl" default:"15m" help:"Cache TTL for metadata and corpus info (e.g., '15m', '1h')"`
+
+ // MaxSize is the maximum number of cache entries
+ MaxSize int `yaml:"max_size" default:"1000" help:"Maximum number of cache entries"`
+}
+
+// DefaultCacheConfig returns a default cache configuration
+func DefaultCacheConfig() *CacheConfig {
+ return &CacheConfig{
+ Enabled: true,
+ DefaultTTL: "5m", // 5 minutes
+ SearchTTL: "2m", // 2 minutes - search results change less frequently
+ MetadataTTL: "15m", // 15 minutes - metadata is more stable
+ MaxSize: 1000,
+ }
+}
+
+// Validate validates cache configuration
+func (c *CacheConfig) Validate() error {
+ if !c.Enabled {
+ return nil // Skip validation if cache is disabled
+ }
+
+ if c.MaxSize <= 0 {
+ return fmt.Errorf("cache max_size must be positive, got %d", c.MaxSize)
+ }
+
+ // Validate TTL duration strings
+ if _, err := time.ParseDuration(c.DefaultTTL); err != nil {
+ return fmt.Errorf("invalid default_ttl '%s': %w", c.DefaultTTL, err)
+ }
+
+ if _, err := time.ParseDuration(c.SearchTTL); err != nil {
+ return fmt.Errorf("invalid search_ttl '%s': %w", c.SearchTTL, err)
+ }
+
+ if _, err := time.ParseDuration(c.MetadataTTL); err != nil {
+ return fmt.Errorf("invalid metadata_ttl '%s': %w", c.MetadataTTL, err)
+ }
+
+ return nil
+}
+
+// GetDefaultTTL returns the default TTL as a time.Duration
+func (c *CacheConfig) GetDefaultTTL() time.Duration {
+ if !c.Enabled {
+ return 0
+ }
+
+ duration, err := time.ParseDuration(c.DefaultTTL)
+ if err != nil {
+ return 5 * time.Minute // fallback to default
+ }
+ return duration
+}
+
+// GetSearchTTL returns the search TTL as a time.Duration
+func (c *CacheConfig) GetSearchTTL() time.Duration {
+ if !c.Enabled {
+ return 0
+ }
+
+ duration, err := time.ParseDuration(c.SearchTTL)
+ if err != nil {
+ return 2 * time.Minute // fallback to default
+ }
+ return duration
+}
+
+// GetMetadataTTL returns the metadata TTL as a time.Duration
+func (c *CacheConfig) GetMetadataTTL() time.Duration {
+ if !c.Enabled {
+ return 0
+ }
+
+ duration, err := time.ParseDuration(c.MetadataTTL)
+ if err != nil {
+ return 15 * time.Minute // fallback to default
+ }
+ return duration
+}
diff --git a/config/cache_test.go b/config/cache_test.go
new file mode 100644
index 0000000..661a9e7
--- /dev/null
+++ b/config/cache_test.go
@@ -0,0 +1,182 @@
+package config
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDefaultCacheConfig(t *testing.T) {
+ config := DefaultCacheConfig()
+
+ assert.True(t, config.Enabled)
+ assert.Equal(t, "5m", config.DefaultTTL)
+ assert.Equal(t, "2m", config.SearchTTL)
+ assert.Equal(t, "15m", config.MetadataTTL)
+ assert.Equal(t, 1000, config.MaxSize)
+}
+
+func TestCacheConfigValidate(t *testing.T) {
+ tests := []struct {
+ name string
+ config CacheConfig
+ wantError bool
+ errorMsg string
+ }{
+ {
+ name: "disabled cache",
+ config: CacheConfig{Enabled: false},
+ wantError: false,
+ },
+ {
+ name: "valid cache config",
+ config: CacheConfig{
+ Enabled: true,
+ DefaultTTL: "5m",
+ SearchTTL: "2m",
+ MetadataTTL: "15m",
+ MaxSize: 1000,
+ },
+ wantError: false,
+ },
+ {
+ name: "invalid max size",
+ config: CacheConfig{
+ Enabled: true,
+ DefaultTTL: "5m",
+ SearchTTL: "2m",
+ MetadataTTL: "15m",
+ MaxSize: 0,
+ },
+ wantError: true,
+ errorMsg: "cache max_size must be positive",
+ },
+ {
+ name: "invalid default TTL",
+ config: CacheConfig{
+ Enabled: true,
+ DefaultTTL: "invalid",
+ SearchTTL: "2m",
+ MetadataTTL: "15m",
+ MaxSize: 1000,
+ },
+ wantError: true,
+ errorMsg: "invalid default_ttl",
+ },
+ {
+ name: "invalid search TTL",
+ config: CacheConfig{
+ Enabled: true,
+ DefaultTTL: "5m",
+ SearchTTL: "bad-duration",
+ MetadataTTL: "15m",
+ MaxSize: 1000,
+ },
+ wantError: true,
+ errorMsg: "invalid search_ttl",
+ },
+ {
+ name: "invalid metadata TTL",
+ config: CacheConfig{
+ Enabled: true,
+ DefaultTTL: "5m",
+ SearchTTL: "2m",
+ MetadataTTL: "not-a-duration",
+ MaxSize: 1000,
+ },
+ wantError: true,
+ errorMsg: "invalid metadata_ttl",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ err := tt.config.Validate()
+
+ if tt.wantError {
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), tt.errorMsg)
+ } else {
+ assert.NoError(t, err)
+ }
+ })
+ }
+}
+
+func TestCacheConfigGetTTLMethods(t *testing.T) {
+ config := &CacheConfig{
+ Enabled: true,
+ DefaultTTL: "5m",
+ SearchTTL: "2m",
+ MetadataTTL: "15m",
+ MaxSize: 1000,
+ }
+
+ // Test valid TTL parsing
+ assert.Equal(t, 5*time.Minute, config.GetDefaultTTL())
+ assert.Equal(t, 2*time.Minute, config.GetSearchTTL())
+ assert.Equal(t, 15*time.Minute, config.GetMetadataTTL())
+
+ // Test disabled cache returns 0
+ disabledConfig := &CacheConfig{Enabled: false}
+ assert.Equal(t, time.Duration(0), disabledConfig.GetDefaultTTL())
+ assert.Equal(t, time.Duration(0), disabledConfig.GetSearchTTL())
+ assert.Equal(t, time.Duration(0), disabledConfig.GetMetadataTTL())
+
+ // Test invalid TTL falls back to defaults
+ invalidConfig := &CacheConfig{
+ Enabled: true,
+ DefaultTTL: "invalid",
+ SearchTTL: "bad",
+ MetadataTTL: "worse",
+ }
+ assert.Equal(t, 5*time.Minute, invalidConfig.GetDefaultTTL())
+ assert.Equal(t, 2*time.Minute, invalidConfig.GetSearchTTL())
+ assert.Equal(t, 15*time.Minute, invalidConfig.GetMetadataTTL())
+}
+
+func TestCacheConfigVariousTTLFormats(t *testing.T) {
+ tests := []struct {
+ name string
+ ttl string
+ expected time.Duration
+ }{
+ {
+ name: "seconds",
+ ttl: "30s",
+ expected: 30 * time.Second,
+ },
+ {
+ name: "minutes",
+ ttl: "5m",
+ expected: 5 * time.Minute,
+ },
+ {
+ name: "hours",
+ ttl: "1h",
+ expected: 1 * time.Hour,
+ },
+ {
+ name: "mixed format",
+ ttl: "1h30m",
+ expected: 1*time.Hour + 30*time.Minute,
+ },
+ {
+ name: "microseconds",
+ ttl: "500ms",
+ expected: 500 * time.Millisecond,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ config := &CacheConfig{
+ Enabled: true,
+ DefaultTTL: tt.ttl,
+ }
+
+ assert.Equal(t, tt.expected, config.GetDefaultTTL())
+ })
+ }
+}
diff --git a/config/config.go b/config/config.go
index 361ae2b..be1fefe 100644
--- a/config/config.go
+++ b/config/config.go
@@ -16,6 +16,9 @@
// KorAP API configuration
KorAP KorAPConfig `yaml:"korap"`
+ // Cache configuration
+ Cache CacheConfig `yaml:"cache"`
+
// Logging configuration
Logging LoggingConfig `yaml:"logging"`
}
@@ -72,6 +75,7 @@
Timeout: 30,
MaxRetries: 3,
},
+ Cache: *DefaultCacheConfig(),
Logging: LoggingConfig{
Level: "info",
Format: "text",
@@ -89,6 +93,10 @@
return fmt.Errorf("korap config validation failed: %w", err)
}
+ if err := c.Cache.Validate(); err != nil {
+ return fmt.Errorf("cache config validation failed: %w", err)
+ }
+
if err := c.Logging.Validate(); err != nil {
return fmt.Errorf("logging config validation failed: %w", err)
}
diff --git a/service/cache.go b/service/cache.go
index 43ec439..00b3abd 100644
--- a/service/cache.go
+++ b/service/cache.go
@@ -9,7 +9,7 @@
"strings"
"time"
- cfg "github.com/korap/korap-mcp/config"
+ "github.com/korap/korap-mcp/config"
"github.com/korap/korap-mcp/logger"
"github.com/maypok86/otter"
"github.com/rs/zerolog"
@@ -31,54 +31,29 @@
type Cache struct {
cache *otter.Cache[string, *CacheEntry]
logger zerolog.Logger
- config CacheConfig
+ config *config.CacheConfig
}
-// CacheConfig configures the cache behavior
-type CacheConfig struct {
- // Enabled controls whether caching is active
- Enabled bool
- // DefaultTTL is the default time-to-live for cache entries
- DefaultTTL time.Duration
- // SearchTTL is the TTL for search results
- SearchTTL time.Duration
- // MetadataTTL is the TTL for metadata and corpus information
- MetadataTTL time.Duration
- // MaxSize is the maximum number of cache entries
- MaxSize int
-}
-
-// DefaultCacheConfig returns a default cache configuration
-func DefaultCacheConfig() CacheConfig {
- return CacheConfig{
- Enabled: true,
- DefaultTTL: 5 * time.Minute,
- SearchTTL: 2 * time.Minute, // Search results change less frequently
- MetadataTTL: 15 * time.Minute, // Metadata is more stable
- MaxSize: 1000,
- }
-}
-
-// NewCache creates a new cache instance
-func NewCache(config CacheConfig) (*Cache, error) {
+// NewCache creates a new cache instance from config.CacheConfig
+func NewCache(cacheConfig *config.CacheConfig) (*Cache, error) {
// Create default logging config for cache
- logConfig := &cfg.LoggingConfig{
+ logConfig := &config.LoggingConfig{
Level: "info",
Format: "text",
}
- if !config.Enabled {
+ if !cacheConfig.Enabled {
return &Cache{
cache: nil,
logger: logger.GetLogger(logConfig),
- config: config,
+ config: cacheConfig,
}, nil
}
// Create otter cache with specified capacity
- cache, err := otter.MustBuilder[string, *CacheEntry](config.MaxSize).
+ cache, err := otter.MustBuilder[string, *CacheEntry](cacheConfig.MaxSize).
CollectStats().
- WithTTL(config.DefaultTTL).
+ WithTTL(cacheConfig.GetDefaultTTL()).
Build()
if err != nil {
return nil, fmt.Errorf("failed to create cache: %w", err)
@@ -87,7 +62,7 @@
return &Cache{
cache: &cache,
logger: logger.GetLogger(logConfig),
- config: config,
+ config: cacheConfig,
}, nil
}
@@ -188,9 +163,9 @@
"hit_ratio": stats.Ratio(),
"evictions": stats.EvictedCount(),
"max_size": c.config.MaxSize,
- "default_ttl": c.config.DefaultTTL.String(),
- "search_ttl": c.config.SearchTTL.String(),
- "metadata_ttl": c.config.MetadataTTL.String(),
+ "default_ttl": c.config.DefaultTTL,
+ "search_ttl": c.config.SearchTTL,
+ "metadata_ttl": c.config.MetadataTTL,
}
}
@@ -200,17 +175,17 @@
// Search endpoints get shorter TTL
if strings.Contains(endpoint, "search") || strings.Contains(endpoint, "query") {
- return c.config.SearchTTL
+ return c.config.GetSearchTTL()
}
// Metadata and corpus endpoints get longer TTL
if strings.Contains(endpoint, "corpus") || strings.Contains(endpoint, "metadata") ||
strings.Contains(endpoint, "statistics") || strings.Contains(endpoint, "info") {
- return c.config.MetadataTTL
+ return c.config.GetMetadataTTL()
}
// Default TTL for other endpoints
- return c.config.DefaultTTL
+ return c.config.GetDefaultTTL()
}
// Close closes the cache and cleans up resources
diff --git a/service/cache_test.go b/service/cache_test.go
index 037f0b8..9288660 100644
--- a/service/cache_test.go
+++ b/service/cache_test.go
@@ -5,36 +5,37 @@
"testing"
"time"
+ "github.com/korap/korap-mcp/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDefaultCacheConfig(t *testing.T) {
- config := DefaultCacheConfig()
+ cacheConfig := config.DefaultCacheConfig()
- assert.True(t, config.Enabled)
- assert.Equal(t, 5*time.Minute, config.DefaultTTL)
- assert.Equal(t, 2*time.Minute, config.SearchTTL)
- assert.Equal(t, 15*time.Minute, config.MetadataTTL)
- assert.Equal(t, 1000, config.MaxSize)
+ assert.True(t, cacheConfig.Enabled)
+ assert.Equal(t, "5m", cacheConfig.DefaultTTL)
+ assert.Equal(t, "2m", cacheConfig.SearchTTL)
+ assert.Equal(t, "15m", cacheConfig.MetadataTTL)
+ assert.Equal(t, 1000, cacheConfig.MaxSize)
}
func TestNewCache(t *testing.T) {
tests := []struct {
name string
- config CacheConfig
+ config *config.CacheConfig
expectError bool
expectNilCache bool
}{
{
name: "enabled cache",
- config: DefaultCacheConfig(),
+ config: config.DefaultCacheConfig(),
expectError: false,
expectNilCache: false,
},
{
name: "disabled cache",
- config: CacheConfig{
+ config: &config.CacheConfig{
Enabled: false,
},
expectError: false,
@@ -42,11 +43,11 @@
},
{
name: "custom configuration",
- config: CacheConfig{
+ config: &config.CacheConfig{
Enabled: true,
- DefaultTTL: 1 * time.Minute,
- SearchTTL: 30 * time.Second,
- MetadataTTL: 5 * time.Minute,
+ DefaultTTL: "1m",
+ SearchTTL: "30s",
+ MetadataTTL: "5m",
MaxSize: 500,
},
expectError: false,
@@ -78,7 +79,7 @@
}
func TestCacheGetSet(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
ctx := context.Background()
@@ -99,7 +100,7 @@
}
func TestCacheExpiry(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
ctx := context.Background()
@@ -125,7 +126,7 @@
}
func TestCacheDelete(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
ctx := context.Background()
@@ -147,7 +148,7 @@
}
func TestCacheClear(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
ctx := context.Background()
@@ -179,7 +180,7 @@
}
func TestCacheStats(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
ctx := context.Background()
@@ -203,8 +204,8 @@
}
func TestCacheStatsDisabled(t *testing.T) {
- config := CacheConfig{Enabled: false}
- cache, err := NewCache(config)
+ cacheConfig := &config.CacheConfig{Enabled: false}
+ cache, err := NewCache(cacheConfig)
require.NoError(t, err)
stats := cache.Stats()
@@ -213,8 +214,8 @@
}
func TestCacheDisabled(t *testing.T) {
- config := CacheConfig{Enabled: false}
- cache, err := NewCache(config)
+ cacheConfig := &config.CacheConfig{Enabled: false}
+ cache, err := NewCache(cacheConfig)
require.NoError(t, err)
ctx := context.Background()
@@ -238,7 +239,7 @@
}
func TestGenerateCacheKey(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
tests := []struct {
@@ -304,7 +305,7 @@
}
func TestCacheKeyDeterministic(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
// Test that map parameter order doesn't affect cache key generation
@@ -341,8 +342,8 @@
}
func TestGetTTLForEndpoint(t *testing.T) {
- config := DefaultCacheConfig()
- cache, err := NewCache(config)
+ cacheConfig := config.DefaultCacheConfig()
+ cache, err := NewCache(cacheConfig)
require.NoError(t, err)
tests := []struct {
@@ -353,42 +354,42 @@
{
name: "search endpoint",
endpoint: "/api/v1/search",
- expected: config.SearchTTL,
+ expected: cacheConfig.GetSearchTTL(),
},
{
name: "query endpoint",
endpoint: "/query",
- expected: config.SearchTTL,
+ expected: cacheConfig.GetSearchTTL(),
},
{
name: "corpus endpoint",
endpoint: "/corpus",
- expected: config.MetadataTTL,
+ expected: cacheConfig.GetMetadataTTL(),
},
{
name: "metadata endpoint",
endpoint: "/metadata",
- expected: config.MetadataTTL,
+ expected: cacheConfig.GetMetadataTTL(),
},
{
name: "statistics endpoint",
endpoint: "/statistics",
- expected: config.MetadataTTL,
+ expected: cacheConfig.GetMetadataTTL(),
},
{
name: "info endpoint",
endpoint: "/info",
- expected: config.MetadataTTL,
+ expected: cacheConfig.GetMetadataTTL(),
},
{
name: "other endpoint",
endpoint: "/other",
- expected: config.DefaultTTL,
+ expected: cacheConfig.GetDefaultTTL(),
},
{
name: "case insensitive",
endpoint: "/API/V1/SEARCH",
- expected: config.SearchTTL,
+ expected: cacheConfig.GetSearchTTL(),
},
}
@@ -423,7 +424,7 @@
}
func TestCacheClose(t *testing.T) {
- cache, err := NewCache(DefaultCacheConfig())
+ cache, err := NewCache(config.DefaultCacheConfig())
require.NoError(t, err)
// Add some data
@@ -435,7 +436,7 @@
assert.NoError(t, err)
// Disabled cache close should also not error
- disabledCache, err := NewCache(CacheConfig{Enabled: false})
+ disabledCache, err := NewCache(&config.CacheConfig{Enabled: false})
require.NoError(t, err)
err = disabledCache.Close()
diff --git a/service/client.go b/service/client.go
index a7c532c..3cfd127 100644
--- a/service/client.go
+++ b/service/client.go
@@ -27,7 +27,7 @@
BaseURL string
Timeout time.Duration
OAuthConfig *config.OAuthConfig
- CacheConfig *CacheConfig
+ CacheConfig *config.CacheConfig
}
// NewClient creates a new KorAP API client
@@ -63,14 +63,14 @@
// Initialize cache if configuration is provided
if opts.CacheConfig != nil {
- cache, err := NewCache(*opts.CacheConfig)
+ cache, err := NewCache(opts.CacheConfig)
if err != nil {
return nil, fmt.Errorf("failed to create cache: %w", err)
}
client.cache = cache
} else {
// Use default cache configuration
- defaultConfig := DefaultCacheConfig()
+ defaultConfig := config.DefaultCacheConfig()
cache, err := NewCache(defaultConfig)
if err != nil {
return nil, fmt.Errorf("failed to create default cache: %w", err)
diff --git a/service/client_test.go b/service/client_test.go
index 6ebb61e..1785ede 100644
--- a/service/client_test.go
+++ b/service/client_test.go
@@ -353,12 +353,12 @@
defer server.Close()
t.Run("cache enabled", func(t *testing.T) {
- cacheConfig := DefaultCacheConfig()
- cacheConfig.DefaultTTL = 1 * time.Minute
+ cacheConfig := config.DefaultCacheConfig()
+ cacheConfig.DefaultTTL = "1m"
client, err := NewClient(ClientOptions{
BaseURL: server.URL,
- CacheConfig: &cacheConfig,
+ CacheConfig: cacheConfig,
})
assert.NoError(t, err)
defer client.Close()
@@ -388,11 +388,11 @@
})
t.Run("cache disabled", func(t *testing.T) {
- cacheConfig := CacheConfig{Enabled: false}
+ cacheConfig := &config.CacheConfig{Enabled: false}
client, err := NewClient(ClientOptions{
BaseURL: server.URL,
- CacheConfig: &cacheConfig,
+ CacheConfig: cacheConfig,
})
assert.NoError(t, err)
defer client.Close()
@@ -419,17 +419,17 @@
})
t.Run("cache expiry", func(t *testing.T) {
- cacheConfig := CacheConfig{
+ cacheConfig := &config.CacheConfig{
Enabled: true,
- DefaultTTL: 50 * time.Millisecond,
- SearchTTL: 50 * time.Millisecond,
- MetadataTTL: 50 * time.Millisecond,
+ DefaultTTL: "50ms",
+ SearchTTL: "50ms",
+ MetadataTTL: "50ms",
MaxSize: 100,
}
client, err := NewClient(ClientOptions{
BaseURL: server.URL,
- CacheConfig: &cacheConfig,
+ CacheConfig: cacheConfig,
})
assert.NoError(t, err)
defer client.Close()