diff --git a/Makefile b/Makefile index 0af6203..bb8978d 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,13 @@ lint: ## Run golangci-lint linter lint-fix: ## Run golangci-lint linter and perform fixes $(GOLANGCI_LINT) run --fix +FUZZTIME ?= 30s + +.PHONY: fuzz +fuzz: ## Run fuzz tests with a configurable duration (default 30s per target) + $(GO) test ./api/v1alpha1/ -run=^$$ -fuzz=FuzzHttpBinRoundTrip -fuzztime=$(FUZZTIME) -count=1 + $(GO) test ./api/v1alpha1/ -run=^$$ -fuzz=FuzzHttpBinDeploymentRoundTrip -fuzztime=$(FUZZTIME) -count=1 + ##@ Build .PHONY: build diff --git a/api/v1alpha1/roundtrip_fuzz_test.go b/api/v1alpha1/roundtrip_fuzz_test.go new file mode 100644 index 0000000..2bf6471 --- /dev/null +++ b/api/v1alpha1/roundtrip_fuzz_test.go @@ -0,0 +1,43 @@ +package v1alpha1 + +import ( + "encoding/json" + "testing" + + "k8s.io/apimachinery/pkg/api/equality" +) + +func FuzzHttpBinRoundTrip(f *testing.F) { + f.Add([]byte(`{"apiVersion":"httpbin.platform-mesh.io/v1alpha1","kind":"HttpBin","metadata":{"name":"test-httpbin","namespace":"default"},"spec":{"region":"eu-west-1"}}`)) + f.Add([]byte(`{"spec":{"region":"us-east-1"},"status":{"url":"https://httpbin.example.com","ready":true}}`)) + f.Add([]byte(`{}`)) + f.Fuzz(func(t *testing.T, data []byte) { + fuzzRoundTrip(t, data, &HttpBin{}, &HttpBin{}) + }) +} + +func FuzzHttpBinDeploymentRoundTrip(f *testing.F) { + f.Add([]byte(`{"apiVersion":"httpbin.platform-mesh.io/v1alpha1","kind":"HttpBinDeployment","metadata":{"name":"test-deployment","namespace":"default"},"spec":{"service":{"name":"httpbin-svc","type":"ClusterIP","port":80},"deployment":{"name":"httpbin","replicas":3}}}`)) + f.Add([]byte(`{"spec":{"service":{"type":"LoadBalancer","port":8080,"annotations":{"service.beta.kubernetes.io/aws-load-balancer-type":"nlb"}},"deployment":{"replicas":1,"labels":{"app":"httpbin"},"annotations":{"prometheus.io/scrape":"true"}}},"status":{"readyReplicas":1,"url":"https://httpbin.example.com","isDeploymentReady":true}}`)) + f.Add([]byte(`{}`)) + f.Fuzz(func(t *testing.T, data []byte) { + fuzzRoundTrip(t, data, &HttpBinDeployment{}, &HttpBinDeployment{}) + }) +} + +func fuzzRoundTrip[T any](t *testing.T, data []byte, obj *T, obj2 *T) { + t.Helper() + if err := json.Unmarshal(data, obj); err != nil { + return + } + roundtripped, err := json.Marshal(obj) + if err != nil { + t.Fatalf("failed to marshal: %v", err) + } + if err := json.Unmarshal(roundtripped, obj2); err != nil { + t.Fatalf("failed to unmarshal roundtripped data: %v", err) + } + if !equality.Semantic.DeepEqual(obj, obj2) { + t.Errorf("roundtrip mismatch for %T", obj) + } +} diff --git a/go.sum b/go.sum index 7dea803..2bbb3ba 100644 --- a/go.sum +++ b/go.sum @@ -836,20 +836,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= -k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= k8s.io/api v0.34.6 h1:0ReeOHQfV9SwQ8CMOHkPbM/GscIT3gN2qh463TOEEk4= k8s.io/api v0.34.6/go.mod h1:u6eOg5ckbO2DUKiyVp7mUMVIA+qZZdW2oyKDhs8nXec= k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= k8s.io/apimachinery v0.34.6 h1:Y/ZNX0Mf1E+CT8clgFzLIkOhkbRLTSHqv6+eJnMJaoQ= k8s.io/apimachinery v0.34.6/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= k8s.io/client-go v0.34.6 h1:8aF4tJiZolSdliT5nhJnBx49Om2ET3Tn3/JKKpJk4gI= k8s.io/client-go v0.34.6/go.mod h1:ZntANq4HsaiOD0rIhLHTdZT/aLkv4NVyI/glqocESTQ= k8s.io/code-generator v0.34.1 h1:WpphT26E+j7tEgIUfFr5WfbJrktCGzB3JoJH9149xYc=