package cloudflare import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) func TestClientCreatesTunnelCNAME(t *testing.T) { requests := 0 server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { requests++ if request.Header.Get("Authorization") != "Bearer test-api-token" { t.Error("Cloudflare request did not use the API token header") writer.WriteHeader(http.StatusUnauthorized) return } switch request.Method + " " + request.URL.Path { case "GET /zones/zone-id/dns_records": if request.URL.Query().Get("type") != "CNAME" || request.URL.Query().Get("name") != "app.example.test" { t.Error("DNS lookup was invalid") } _ = json.NewEncoder(writer).Encode(map[string]any{"success": true, "result": []any{}}) case "POST /zones/zone-id/dns_records": var body map[string]any if err := json.NewDecoder(request.Body).Decode(&body); err != nil || body["content"] != "tunnel-id.cfargotunnel.com" || body["proxied"] != true { t.Error("DNS create request was invalid") } _ = json.NewEncoder(writer).Encode(map[string]any{"success": true, "result": map[string]string{"id": "record-id"}}) default: t.Errorf("unexpected request %s %s", request.Method, request.URL.Path) writer.WriteHeader(http.StatusMethodNotAllowed) } })) defer server.Close() client := NewClient("test-api-token") client.baseURL = server.URL client.httpClient = server.Client() if err := client.EnsureCNAME(context.Background(), "zone-id", "app.example.test", "tunnel-id"); err != nil { t.Fatal(err) } if requests != 2 { t.Fatalf("expected two Cloudflare requests, got %d", requests) } } func TestClientFailureDoesNotRevealToken(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) { writer.WriteHeader(http.StatusInternalServerError) })) defer server.Close() client := NewClient("test-api-token") client.baseURL = server.URL client.httpClient = server.Client() err := client.EnsureCNAME(context.Background(), "zone-id", "app.example.test", "tunnel-id") if err == nil || strings.Contains(err.Error(), "test-api-token") { t.Fatal("Cloudflare API failure exposed the token") } } func TestClientDeletesOnlyMatchingTunnelCNAME(t *testing.T) { deleted := false server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { if request.Header.Get("Authorization") != "Bearer test-api-token" { t.Error("Cloudflare request did not use the API token header") writer.WriteHeader(http.StatusUnauthorized) return } switch request.Method + " " + request.URL.Path { case "GET /zones/zone-id/dns_records": _ = json.NewEncoder(writer).Encode(map[string]any{"success": true, "result": []map[string]any{{"id": "record-id", "name": "app.example.test", "content": "tunnel-id.cfargotunnel.com", "proxied": true}}}) case "DELETE /zones/zone-id/dns_records/record-id": deleted = true _ = json.NewEncoder(writer).Encode(map[string]any{"success": true, "result": map[string]string{"id": "record-id"}}) default: t.Errorf("unexpected request %s %s", request.Method, request.URL.Path) writer.WriteHeader(http.StatusMethodNotAllowed) } })) defer server.Close() client := NewClient("test-api-token") client.baseURL = server.URL client.httpClient = server.Client() if err := client.DeleteCNAME(context.Background(), "zone-id", "app.example.test", "tunnel-id"); err != nil || !deleted { t.Fatal("matching managed CNAME was not deleted") } }