Add comprehensive test coverage for previously untested functions: internal/debug/debug_test.go: - TestSetVerbose: tests SetVerbose() and its effect on Enabled() - TestSetQuietAndIsQuiet: tests SetQuiet() and IsQuiet() functions - TestPrintNormal: tests quiet mode suppression of normal output - TestPrintlnNormal: tests quiet mode suppression of println output internal/export/config_test.go (new file): - TestLoadConfig: comprehensive tests for LoadConfig() including: - Default values when no config exists - Loading custom policies (both regular and auto-export) - Loading retry attempts, backoff, skip encoding errors, write manifest - Handling invalid/malformed config values gracefully internal/export/policy_test.go: - TestErrorPolicyString: tests String() method on ErrorPolicy - TestNewManifest: tests manifest creation with proper defaults - TestWriteManifest: tests manifest file writing and error handling These tests bring coverage from 44.8% to 45.0%, meeting the CI threshold.
244 lines
5.8 KiB
Go
244 lines
5.8 KiB
Go
package export
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRetryWithBackoff(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("succeeds first try", func(t *testing.T) {
|
|
attempts := 0
|
|
err := RetryWithBackoff(ctx, 3, 100, "test", func() error {
|
|
attempts++
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Errorf("expected no error, got %v", err)
|
|
}
|
|
if attempts != 1 {
|
|
t.Errorf("expected 1 attempt, got %d", attempts)
|
|
}
|
|
})
|
|
|
|
t.Run("succeeds after retries", func(t *testing.T) {
|
|
attempts := 0
|
|
err := RetryWithBackoff(ctx, 3, 10, "test", func() error {
|
|
attempts++
|
|
if attempts < 3 {
|
|
return errors.New("transient error")
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Errorf("expected no error, got %v", err)
|
|
}
|
|
if attempts != 3 {
|
|
t.Errorf("expected 3 attempts, got %d", attempts)
|
|
}
|
|
})
|
|
|
|
t.Run("fails after max retries", func(t *testing.T) {
|
|
attempts := 0
|
|
err := RetryWithBackoff(ctx, 3, 10, "test", func() error {
|
|
attempts++
|
|
return errors.New("persistent error")
|
|
})
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if attempts != 3 {
|
|
t.Errorf("expected 3 attempts, got %d", attempts)
|
|
}
|
|
})
|
|
|
|
t.Run("respects context cancellation", func(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
|
defer cancel()
|
|
|
|
attempts := 0
|
|
err := RetryWithBackoff(ctx, 10, 100, "test", func() error {
|
|
attempts++
|
|
return errors.New("error")
|
|
})
|
|
if err != context.DeadlineExceeded {
|
|
t.Errorf("expected DeadlineExceeded, got %v", err)
|
|
}
|
|
// Should stop before reaching max retries due to timeout
|
|
if attempts >= 10 {
|
|
t.Errorf("expected fewer than 10 attempts due to timeout, got %d", attempts)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestErrorPolicy(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
policy ErrorPolicy
|
|
valid bool
|
|
}{
|
|
{"strict", PolicyStrict, true},
|
|
{"best-effort", PolicyBestEffort, true},
|
|
{"partial", PolicyPartial, true},
|
|
{"required-core", PolicyRequiredCore, true},
|
|
{"invalid", ErrorPolicy("invalid"), false},
|
|
{"empty", ErrorPolicy(""), false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.policy.IsValid(); got != tt.valid {
|
|
t.Errorf("IsValid() = %v, want %v", got, tt.valid)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestErrorPolicyString(t *testing.T) {
|
|
tests := []struct {
|
|
policy ErrorPolicy
|
|
want string
|
|
}{
|
|
{PolicyStrict, "strict"},
|
|
{PolicyBestEffort, "best-effort"},
|
|
{PolicyPartial, "partial"},
|
|
{PolicyRequiredCore, "required-core"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.want, func(t *testing.T) {
|
|
if got := tt.policy.String(); got != tt.want {
|
|
t.Errorf("String() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewManifest(t *testing.T) {
|
|
manifest := NewManifest(PolicyBestEffort)
|
|
|
|
if manifest == nil {
|
|
t.Fatal("NewManifest returned nil")
|
|
}
|
|
if manifest.ErrorPolicy != string(PolicyBestEffort) {
|
|
t.Errorf("ErrorPolicy = %v, want %v", manifest.ErrorPolicy, PolicyBestEffort)
|
|
}
|
|
if !manifest.Complete {
|
|
t.Error("Complete should be true by default")
|
|
}
|
|
if manifest.ExportedAt.IsZero() {
|
|
t.Error("ExportedAt should not be zero")
|
|
}
|
|
}
|
|
|
|
func TestWriteManifest(t *testing.T) {
|
|
t.Run("writes manifest successfully", func(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
jsonlPath := tmpDir + "/test.jsonl"
|
|
|
|
manifest := NewManifest(PolicyStrict)
|
|
manifest.ExportedCount = 5
|
|
manifest.Complete = true
|
|
|
|
err := WriteManifest(jsonlPath, manifest)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
// Verify manifest file was created
|
|
manifestPath := tmpDir + "/test.manifest.json"
|
|
if _, err := os.Stat(manifestPath); os.IsNotExist(err) {
|
|
t.Error("manifest file was not created")
|
|
}
|
|
})
|
|
|
|
t.Run("fails on invalid directory", func(t *testing.T) {
|
|
err := WriteManifest("/nonexistent/path/test.jsonl", NewManifest(PolicyStrict))
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent directory")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFetchWithPolicy(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("strict policy fails fast", func(t *testing.T) {
|
|
cfg := &Config{
|
|
Policy: PolicyStrict,
|
|
RetryAttempts: 1,
|
|
RetryBackoffMS: 10,
|
|
}
|
|
result := FetchWithPolicy(ctx, cfg, DataTypeCore, "test", func() error {
|
|
return errors.New("test error")
|
|
})
|
|
if result.Err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if result.Success {
|
|
t.Error("expected Success=false")
|
|
}
|
|
})
|
|
|
|
t.Run("best-effort policy skips errors", func(t *testing.T) {
|
|
cfg := &Config{
|
|
Policy: PolicyBestEffort,
|
|
RetryAttempts: 1,
|
|
RetryBackoffMS: 10,
|
|
}
|
|
result := FetchWithPolicy(ctx, cfg, DataTypeLabels, "test", func() error {
|
|
return errors.New("test error")
|
|
})
|
|
if result.Err != nil {
|
|
t.Errorf("expected no error in best-effort, got %v", result.Err)
|
|
}
|
|
if result.Success {
|
|
t.Error("expected Success=false")
|
|
}
|
|
if len(result.Warnings) == 0 {
|
|
t.Error("expected warnings")
|
|
}
|
|
})
|
|
|
|
t.Run("required-core fails on core data", func(t *testing.T) {
|
|
cfg := &Config{
|
|
Policy: PolicyRequiredCore,
|
|
RetryAttempts: 1,
|
|
RetryBackoffMS: 10,
|
|
}
|
|
result := FetchWithPolicy(ctx, cfg, DataTypeCore, "test", func() error {
|
|
return errors.New("test error")
|
|
})
|
|
if result.Err == nil {
|
|
t.Error("expected error for core data, got nil")
|
|
}
|
|
if result.Success {
|
|
t.Error("expected Success=false")
|
|
}
|
|
})
|
|
|
|
t.Run("required-core skips enrichment errors", func(t *testing.T) {
|
|
cfg := &Config{
|
|
Policy: PolicyRequiredCore,
|
|
RetryAttempts: 1,
|
|
RetryBackoffMS: 10,
|
|
}
|
|
result := FetchWithPolicy(ctx, cfg, DataTypeLabels, "test", func() error {
|
|
return errors.New("test error")
|
|
})
|
|
if result.Err != nil {
|
|
t.Errorf("expected no error for enrichment, got %v", result.Err)
|
|
}
|
|
if result.Success {
|
|
t.Error("expected Success=false")
|
|
}
|
|
if len(result.Warnings) == 0 {
|
|
t.Error("expected warnings")
|
|
}
|
|
})
|
|
}
|