package edgeos import ( "bytes" "context" "fmt" "io" "net/http" "sync" "testing" ) type mockTransport struct { RoundTripFunc func(req *http.Request) (*http.Response, error) } func (m *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) { if m.RoundTripFunc != nil { return m.RoundTripFunc(req) } // Default mock response return &http.Response{ StatusCode: 200, Body: io.NopCloser(bytes.NewBufferString("{}")), Header: make(http.Header), }, nil } func TestClient_ThreadSafety(t *testing.T) { ctx := context.Background() client := MustNew(ctx, []Config{}) var wg sync.WaitGroup start := make(chan struct{}) // Writer: Adds and deletes hosts wg.Add(1) go func() { defer wg.Done() <-start for i := 0; i < 100; i++ { host := fmt.Sprintf("host-%d", i) cfg := &Config{ Host: host, Transport: &mockTransport{}, } if err := client.Add(cfg); err != nil { // verify we don't error on valid add t.Logf("Add error: %v", err) } // We invoke Del immediately. if err := client.Del(host); err != nil { t.Logf("Del error: %v", err) } } }() // Reader: Iterates hosts wg.Add(1) go func() { defer wg.Done() <-start for i := 0; i < 10; i++ { // GetAllInterfaces iterates keys. // With mock transport, this will succeed (returning empty structs) // checking for race conditions. _, _ = client.GetAllInterfaces(ctx) } }() close(start) wg.Wait() } func TestClient_AddDel(t *testing.T) { ctx := context.Background() client := MustNew(ctx, []Config{}) cfg := &Config{ Host: "test-host", Transport: &mockTransport{}, } if err := client.Add(cfg); err != nil { t.Fatalf("Add failed: %v", err) } if err := client.Add(cfg); err == nil { t.Fatal("Expected error adding duplicate host, got nil") } // Verify we can retrieve it // Mock transport returns 200 OK with empty body, so GetInterfaces should return empty slice (or error decoding if empty body is not valid JSON array? actually "{}" is valid object, but GetInterfaces expects array for /interfaces?) // Let's check api.go: GetInterfaces calls /interfaces. // We can customize the mock if we want to test success return. // For this test, we just care that it doesn't return "device not found". _, err := client.GetInterfaces(ctx, "test-host") if err != nil && err.Error() == "device not found: test-host" { t.Fatal("Device should exist") } if err := client.Del("test-host"); err != nil { t.Fatalf("Del failed: %v", err) } if err := client.Del("test-host"); err == nil { t.Fatal("Expected error deleting non-existent host, got nil") } }