Repository: VictoriaMetrics/operator

Issue:
PrometheusRule conversion omits keep_firing_for from rule definitions
When a PrometheusRule contains a keep_firing_for key, the resulting VMRule object created by the conversion process is missing the keep_firing_for in the rule body. No error is generated.

Making a VMRule with keep_firing_for included works fine though.

Discussion:
@AndrewChubatiuk: conversion of `keep_firing_for` PrometheusRule parameter will be available in the next release@AndrewChubatiuk: fix for this issue was released in 0.62.0

Solution patch:
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 952bc2d9..329b487c 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -13,6 +13,7 @@ aliases:
 
 ## tip
 
+* FEATURE: [converter](https://docs.victoriametrics.com/operator/integrations/prometheus/#objects-conversion): support `spec.limit`, `spec.labels`, `spec.query_offset` and `spec.group[*].keep_firing_for` PrometheusRule properties conversion to VMRule. Related issue [#1485](https://github.com/VictoriaMetrics/operator/issues/1485).
 * BUGFIX: [config-reloader](https://github.com/VictoriaMetrics/operator/tree/master/cmd/config-reloader): fixed config reloader command line arguments override. Related issue [#1378](https://github.com/VictoriaMetrics/operator/issues/1478).
 
 ## [v0.61.2](https://github.com/VictoriaMetrics/operator/releases/tag/v0.61.2)
diff --git a/go.mod b/go.mod
index 2ece568a..3b927e61 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/VictoriaMetrics/operator/api v0.51.3
 	github.com/caarlos0/env/v11 v11.3.1
 	github.com/fsnotify/fsnotify v1.8.0
-	github.com/go-logr/logr v1.4.2
+	github.com/go-logr/logr v1.4.3
 	github.com/go-test/deep v1.1.1
 	github.com/google/go-cmp v0.7.0
 	github.com/google/uuid v1.6.0
@@ -18,25 +18,26 @@ require (
 	github.com/onsi/ginkgo/v2 v2.23.0
 	github.com/onsi/gomega v1.36.2
 	github.com/pires/go-proxyproto v0.8.0
-	github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.82.1
-	github.com/prometheus/client_golang v1.21.1
+	github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.84.0
+	github.com/prometheus/client_golang v1.22.0
 	github.com/stretchr/testify v1.10.0
 	go.uber.org/zap v1.27.0
-	golang.org/x/net v0.39.0
-	golang.org/x/sync v0.13.0
+	golang.org/x/net v0.41.0
+	golang.org/x/sync v0.16.0
 	gopkg.in/yaml.v2 v2.4.0
-	k8s.io/api v0.32.4
-	k8s.io/apiextensions-apiserver v0.32.4
-	k8s.io/apimachinery v0.32.4
-	k8s.io/client-go v0.32.4
+	k8s.io/api v0.33.2
+	k8s.io/apiextensions-apiserver v0.33.2
+	k8s.io/apimachinery v0.33.2
+	k8s.io/client-go v0.33.2
 	k8s.io/klog/v2 v2.130.1
-	k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
-	sigs.k8s.io/controller-runtime v0.20.4
+	k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
+	sigs.k8s.io/controller-runtime v0.21.0
 )
 
 require (
 	github.com/aws/aws-sdk-go v1.55.6 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/blang/semver/v4 v4.0.0 // indirect
 	github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@@ -50,10 +51,8 @@ require (
 	github.com/go-openapi/swag v0.23.0 // indirect
 	github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
-	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/google/btree v1.1.3 // indirect
 	github.com/google/gnostic-models v0.6.9 // indirect
-	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
@@ -82,21 +81,23 @@ require (
 	github.com/valyala/quicktemplate v1.8.0 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
+	go.yaml.in/yaml/v2 v2.4.2 // indirect
 	golang.org/x/oauth2 v0.28.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
-	golang.org/x/term v0.31.0 // indirect
-	golang.org/x/text v0.24.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/term v0.32.0 // indirect
+	golang.org/x/text v0.27.0 // indirect
 	golang.org/x/time v0.11.0 // indirect
-	golang.org/x/tools v0.31.0 // indirect
+	golang.org/x/tools v0.34.0 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
 	google.golang.org/protobuf v1.36.6 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
+	k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
 	sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
+	sigs.k8s.io/randfill v1.0.0 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
-	sigs.k8s.io/yaml v1.4.0 // indirect
+	sigs.k8s.io/yaml v1.5.0 // indirect
 )
 
 replace github.com/VictoriaMetrics/operator/api => ./api
diff --git a/go.sum b/go.sum
index 4f111df9..d5d6dbdc 100644
--- a/go.sum
+++ b/go.sum
@@ -55,6 +55,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
+github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
 github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
 github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
 github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
@@ -95,8 +97,8 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
-github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
+github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
 github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
 github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
@@ -138,8 +140,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
 github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -245,16 +245,16 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.82.1 h1:7zaP53Udfw1flmENke9vKkW0+QyVpFgQn2qP3QqIQBM=
-github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.82.1/go.mod h1:hY5yoQsoIalncoxYqXXCDL5y7f+GGYYlW9Bi2IdU5KY=
+github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.84.0 h1:V/HLst0rSw4BZp8nIqhaTnnW4/EGxEoYbgjcDqzPJ5U=
+github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.84.0/go.mod h1:MruMqbSS9aYrKhBImrO9X9g52hwz3I0B+tcoeAwkmuM=
 github.com/prometheus/alertmanager v0.28.0 h1:sLN+6HhZet8hrbmGHLAHWsTXgZSVCvq9Ix3U3wvivqc=
 github.com/prometheus/alertmanager v0.28.0/go.mod h1:/okSnb2LlodbMlRoOWQEKtqI/coOo2NKZDm2Hu9QHLQ=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
-github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
+github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
+github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -276,8 +276,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
 github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
 github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
@@ -285,6 +285,8 @@ github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
 github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -322,6 +324,10 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
 go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
+go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
+go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
+go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -389,8 +395,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
-golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
+golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
+golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -409,8 +415,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
-golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
+golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -447,19 +453,19 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
-golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
+golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
+golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
-golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
+golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -507,8 +513,8 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
 golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
-golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
+golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
+golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -620,25 +626,25 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-k8s.io/api v0.32.4 h1:kw8Y/G8E7EpNy7gjB8gJZl3KJkNz8HM2YHrZPtAZsF4=
-k8s.io/api v0.32.4/go.mod h1:5MYFvLvweRhyKylM3Es/6uh/5hGp0dg82vP34KifX4g=
-k8s.io/apiextensions-apiserver v0.32.4 h1:IA+CoR63UDOijR/vEpow6wQnX4V6iVpzazJBskHrpHE=
-k8s.io/apiextensions-apiserver v0.32.4/go.mod h1:Y06XO/b92H8ymOdG1HlA1submf7gIhbEDc3RjriqZOs=
-k8s.io/apimachinery v0.32.4 h1:8EEksaxA7nd7xWJkkwLDN4SvWS5ot9g6Z/VZb3ju25I=
-k8s.io/apimachinery v0.32.4/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
-k8s.io/client-go v0.32.4 h1:zaGJS7xoYOYumoWIFXlcVrsiYioRPrXGO7dBfVC5R6M=
-k8s.io/client-go v0.32.4/go.mod h1:k0jftcyYnEtwlFW92xC7MTtFv5BNcZBr+zn9jPlT9Ic=
+k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
+k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
+k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
+k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
+k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
+k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
+k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
+k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
-k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
-k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
-k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
+k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
+k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU=
-sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY=
+sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
+sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
 sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
@@ -646,5 +652,6 @@ sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
 sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
 sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
 sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
-sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
 sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
+sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
+sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
diff --git a/internal/controller/operator/converter/apis.go b/internal/controller/operator/converter/apis.go
index 794180b8..c8571d4e 100644
--- a/internal/controller/operator/converter/apis.go
+++ b/internal/controller/operator/converter/apis.go
@@ -36,12 +36,22 @@ func ConvertPromRule(prom *promv1.PrometheusRule, conf *config.BaseOperatorConf)
 			if promRuleItem.For != nil {
 				trule.For = string(*promRuleItem.For)
 			}
+			if promRuleItem.KeepFiringFor != nil {
+				trule.KeepFiringFor = string(*promRuleItem.KeepFiringFor)
+			}
 			ruleItems = append(ruleItems, trule)
 		}
 
 		tgroup := vmv1beta1.RuleGroup{
-			Name:  promGroup.Name,
-			Rules: ruleItems,
+			Name:   promGroup.Name,
+			Rules:  ruleItems,
+			Labels: promGroup.Labels,
+		}
+		if promGroup.QueryOffset != nil {
+			tgroup.EvalOffset = string(*promGroup.QueryOffset)
+		}
+		if promGroup.Limit != nil {
+			tgroup.Limit = *promGroup.Limit
 		}
 		if promGroup.Interval != nil {
 			tgroup.Interval = string(*promGroup.Interval)
@@ -472,8 +482,8 @@ func ConvertProbe(probe *promv1.Probe, conf *config.BaseOperatorConf) *vmv1beta1
 			},
 		},
 	}
-	if probe.Spec.ProberSpec.ProxyURL != "" {
-		cp.Spec.ProxyURL = &probe.Spec.ProberSpec.ProxyURL
+	if probe.Spec.ProberSpec.ProxyURL != nil {
+		cp.Spec.ProxyURL = probe.Spec.ProberSpec.ProxyURL
 	}
 	if probe.Spec.SampleLimit != nil {
 		cp.Spec.SampleLimit = *probe.Spec.SampleLimit



Test patch:
diff --git a/internal/controller/operator/converter/apis_test.go b/internal/controller/operator/converter/apis_test.go
index 00d800de..74bcf9dc 100644
--- a/internal/controller/operator/converter/apis_test.go
+++ b/internal/controller/operator/converter/apis_test.go
@@ -7,6 +7,7 @@ import (
 	promv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/utils/ptr"
 
 	vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1"
@@ -14,509 +15,512 @@ import (
 )
 
 func TestConvertTlsConfig(t *testing.T) {
-	type args struct {
-		tlsConf *promv1.TLSConfig
-	}
-	tests := []struct {
-		name string
-		args args
+	type opts struct {
+		ptc  *promv1.TLSConfig
 		want *vmv1beta1.TLSConfig
-	}{
-		{
-			name: "replace prom secret path",
-			args: args{
-				tlsConf: &promv1.TLSConfig{
-					CAFile:   "/etc/prom_add/ca",
-					CertFile: "/etc/prometheus/secrets/cert.crt",
-					KeyFile:  "/etc/prometheus/configmaps/key.pem",
-				},
-			},
-			want: &vmv1beta1.TLSConfig{
-				CAFile:   "/etc/prom_add/ca",
-				CertFile: "/etc/vm/secrets/cert.crt",
-				KeyFile:  "/etc/vm/configs/key.pem",
-			},
+	}
+	f := func(opts opts) {
+		t.Helper()
+		got := ConvertTLSConfig(opts.ptc)
+		if got.KeyFile != opts.want.KeyFile || got.CertFile != opts.want.CertFile || got.CAFile != opts.want.CAFile {
+			t.Errorf("ConvertTlsConfig() = \n%v, \nwant \n%v", got, opts.want)
+		}
+	}
+
+	// replace prom secret path
+	o := opts{
+		ptc: &promv1.TLSConfig{
+			CAFile:   "/etc/prom_add/ca",
+			CertFile: "/etc/prometheus/secrets/cert.crt",
+			KeyFile:  "/etc/prometheus/configmaps/key.pem",
 		},
-		{
-			name: "with server name and insecure",
-			args: args{
-				tlsConf: &promv1.TLSConfig{
-					CAFile:        "/etc/prom_add/ca",
-					CertFile:      "/etc/prometheus/secrets/cert.crt",
-					KeyFile:       "/etc/prometheus/configmaps/key.pem",
-					SafeTLSConfig: promv1.SafeTLSConfig{ServerName: ptr.To("some-hostname"), InsecureSkipVerify: ptr.To(true)},
-				},
-			},
-			want: &vmv1beta1.TLSConfig{
-				CAFile:             "/etc/prom_add/ca",
-				CertFile:           "/etc/vm/secrets/cert.crt",
-				KeyFile:            "/etc/vm/configs/key.pem",
-				ServerName:         "some-hostname",
-				InsecureSkipVerify: true,
-			},
+		want: &vmv1beta1.TLSConfig{
+			CAFile:   "/etc/prom_add/ca",
+			CertFile: "/etc/vm/secrets/cert.crt",
+			KeyFile:  "/etc/vm/configs/key.pem",
 		},
 	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got := ConvertTLSConfig(tt.args.tlsConf)
-			if got.KeyFile != tt.want.KeyFile || got.CertFile != tt.want.CertFile || got.CAFile != tt.want.CAFile {
-				t.Errorf("ConvertTlsConfig() = \n%v, \nwant \n%v", got, tt.want)
-			}
-		})
+	f(o)
+
+	// with server name and insecure
+	o = opts{
+		ptc: &promv1.TLSConfig{
+			CAFile:        "/etc/prom_add/ca",
+			CertFile:      "/etc/prometheus/secrets/cert.crt",
+			KeyFile:       "/etc/prometheus/configmaps/key.pem",
+			SafeTLSConfig: promv1.SafeTLSConfig{ServerName: ptr.To("some-hostname"), InsecureSkipVerify: ptr.To(true)},
+		},
+		want: &vmv1beta1.TLSConfig{
+			CAFile:             "/etc/prom_add/ca",
+			CertFile:           "/etc/vm/secrets/cert.crt",
+			KeyFile:            "/etc/vm/configs/key.pem",
+			ServerName:         "some-hostname",
+			InsecureSkipVerify: true,
+		},
 	}
+	f(o)
 }
 
 func TestConvertRelabelConfig(t *testing.T) {
-	type args struct {
-		promRelabelConfig []promv1.RelabelConfig
-	}
-	tests := []struct {
-		name string
-		args args
+	type opts struct {
+		prc  []promv1.RelabelConfig
 		want []*vmv1beta1.RelabelConfig
-	}{
-		{
-			name: "test empty cfg",
-			args: args{},
-			want: nil,
-		},
-		{
-			name: "1 relabel cfg rule",
-			args: args{
-				promRelabelConfig: []promv1.RelabelConfig{
-					{
-						Action:       "drop",
-						SourceLabels: []promv1.LabelName{"__address__"},
-					},
-				},
-			},
-			want: []*vmv1beta1.RelabelConfig{
-				{
-					Action:       "drop",
-					SourceLabels: []string{"__address__"},
-				},
-			},
-		},
-		{
-			name: "unsupported config",
-			args: args{
-				promRelabelConfig: []promv1.RelabelConfig{
-					{
-						Action: "drop",
-					},
-					{
-						Action:       "keep",
-						SourceLabels: []promv1.LabelName{"__address__"},
-					},
-				},
+	}
+
+	f := func(opts opts) {
+		t.Helper()
+		got := ConvertRelabelConfig(opts.prc)
+		if len(got) != len(opts.want) {
+			t.Fatalf("len of relabelConfigs mismatch, want: %d, got %d", len(opts.want), len(got))
+		}
+		for i, wantRelabelConfig := range opts.want {
+			if !reflect.DeepEqual(*wantRelabelConfig, *got[i]) {
+				t.Fatalf("ConvertRelabelConfig() = %v, want %v", *got[i], *wantRelabelConfig)
+			}
+		}
+	}
+
+	// test empty cfg
+	o := opts{}
+	f(o)
+
+	// 1 relabel cfg rule
+	o = opts{
+		prc: []promv1.RelabelConfig{{
+			Action:       "drop",
+			SourceLabels: []promv1.LabelName{"__address__"},
+		}},
+		want: []*vmv1beta1.RelabelConfig{{
+			Action:       "drop",
+			SourceLabels: []string{"__address__"},
+		}},
+	}
+	f(o)
+
+	// unsupported config
+	o = opts{
+		prc: []promv1.RelabelConfig{
+			{
+				Action: "drop",
 			},
-			want: []*vmv1beta1.RelabelConfig{
-				{
-					Action:       "keep",
-					SourceLabels: []string{"__address__"},
-				},
+			{
+				Action:       "keep",
+				SourceLabels: []promv1.LabelName{"__address__"},
 			},
 		},
+		want: []*vmv1beta1.RelabelConfig{{
+			Action:       "keep",
+			SourceLabels: []string{"__address__"},
+		}},
 	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got := ConvertRelabelConfig(tt.args.promRelabelConfig)
-			if len(got) != len(tt.want) {
-				t.Fatalf("len of relabelConfigs mismatch, want: %d, got %d", len(tt.want), len(got))
-			}
-			for i, wantRelabelConfig := range tt.want {
-				if !reflect.DeepEqual(*wantRelabelConfig, *got[i]) {
-					t.Fatalf("ConvertRelabelConfig() = %v, want %v", *got[i], *wantRelabelConfig)
-				}
-			}
-		})
-	}
+	f(o)
 }
 
 func TestConvertEndpoint(t *testing.T) {
-	type args struct {
-		promEndpoint []promv1.Endpoint
-	}
-	tests := []struct {
-		name string
-		args args
+	type opts struct {
+		pe   []promv1.Endpoint
 		want []vmv1beta1.Endpoint
-	}{
-		{
-			name: "convert endpoint with relabel config",
-			args: args{
-				promEndpoint: []promv1.Endpoint{
-					{
-						Port: "9100",
-						Path: "/metrics",
-						RelabelConfigs: []promv1.RelabelConfig{
-							{
-								Action:       "drop",
-								SourceLabels: []promv1.LabelName{"__meta__instance"},
-							},
-							{
-								Action: "keep",
-							},
-						},
-					},
+	}
+	f := func(opts opts) {
+		t.Helper()
+		if got := convertEndpoint(opts.pe); !reflect.DeepEqual(got, opts.want) {
+			t.Errorf("ConvertEndpoint() \ngot:  \n%v\n, \nwant: \n%v", got, opts.want)
+		}
+	}
+
+	// convert endpoint with relabel config
+	o := opts{
+		pe: []promv1.Endpoint{{
+			Port: "9100",
+			Path: "/metrics",
+			RelabelConfigs: []promv1.RelabelConfig{
+				{
+					Action:       "drop",
+					SourceLabels: []promv1.LabelName{"__meta__instance"},
 				},
-			},
-			want: []vmv1beta1.Endpoint{
 				{
-					EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{
-						Path: "/metrics",
-					},
-					Port: "9100",
-					EndpointRelabelings: vmv1beta1.EndpointRelabelings{
-						RelabelConfigs: []*vmv1beta1.RelabelConfig{
-							{
-								Action:       "drop",
-								SourceLabels: []string{"__meta__instance"},
-							},
-						},
-					},
+					Action: "keep",
 				},
 			},
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := convertEndpoint(tt.args.promEndpoint); !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("ConvertEndpoint() \ngot:  \n%v\n, \nwant: \n%v", got, tt.want)
-			}
-		})
+		}},
+		want: []vmv1beta1.Endpoint{{
+			EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{
+				Path: "/metrics",
+			},
+			Port: "9100",
+			EndpointRelabelings: vmv1beta1.EndpointRelabelings{
+				RelabelConfigs: []*vmv1beta1.RelabelConfig{{
+					Action:       "drop",
+					SourceLabels: []string{"__meta__instance"},
+				}},
+			},
+		}},
 	}
+	f(o)
 }
 
 func TestConvertServiceMonitor(t *testing.T) {
-	type args struct {
-		serviceMon *promv1.ServiceMonitor
-	}
-	tests := []struct {
-		name string
-		args args
+	type opts struct {
+		sm   *promv1.ServiceMonitor
 		want vmv1beta1.VMServiceScrape
-	}{
-		{
-			name: "with metricsRelabelConfig",
-			args: args{
-				serviceMon: &promv1.ServiceMonitor{
-					Spec: promv1.ServiceMonitorSpec{
-						Endpoints: []promv1.Endpoint{
-							{
-								MetricRelabelConfigs: []promv1.RelabelConfig{
-									{
-										Action:       "drop",
-										SourceLabels: []promv1.LabelName{"__meta__instance"},
-									},
-								},
-							},
-						},
-					},
-				},
+	}
+	f := func(opts opts) {
+		t.Helper()
+		got := ConvertServiceMonitor(opts.sm, &config.BaseOperatorConf{
+			FilterPrometheusConverterLabelPrefixes:      []string{"app.kubernetes", "helm.sh"},
+			FilterPrometheusConverterAnnotationPrefixes: []string{"another-annotation-filter", "app.kubernetes"},
+		})
+		if !reflect.DeepEqual(*got, opts.want) {
+			t.Errorf("ConvertServiceMonitor() got = \n%v, \nwant \n%v", *got, opts.want)
+		}
+	}
+
+	// with metricsRelabelConfig
+	o := opts{
+		sm: &promv1.ServiceMonitor{
+			Spec: promv1.ServiceMonitorSpec{
+				Endpoints: []promv1.Endpoint{{
+					MetricRelabelConfigs: []promv1.RelabelConfig{{
+						Action:       "drop",
+						SourceLabels: []promv1.LabelName{"__meta__instance"},
+					}},
+				}},
 			},
-			want: vmv1beta1.VMServiceScrape{
-				Spec: vmv1beta1.VMServiceScrapeSpec{
-					Endpoints: []vmv1beta1.Endpoint{
-						{
-							EndpointRelabelings: vmv1beta1.EndpointRelabelings{
-								MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{
-									{
-										Action:       "drop",
-										SourceLabels: []string{"__meta__instance"},
-									},
-								},
-							},
-						},
-					},
+		},
+		want: vmv1beta1.VMServiceScrape{
+			Spec: vmv1beta1.VMServiceScrapeSpec{
+				Endpoints: []vmv1beta1.Endpoint{{
+					EndpointRelabelings: vmv1beta1.EndpointRelabelings{
+						MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{{
+							Action:       "drop",
+							SourceLabels: []string{"__meta__instance"},
+						}},
+					}},
 				},
 			},
 		},
-		{
-			name: "with label and annotations filter",
-			args: args{
-				serviceMon: &promv1.ServiceMonitor{
-					ObjectMeta: metav1.ObjectMeta{
-						Labels:      map[string]string{"helm.sh/release": "prod", "keep-label": "value"},
-						Annotations: map[string]string{"app.kubernetes.io/": "release"},
-					},
-					Spec: promv1.ServiceMonitorSpec{
-						Endpoints: []promv1.Endpoint{
-							{
-								MetricRelabelConfigs: []promv1.RelabelConfig{
-									{
-										Action:       "drop",
-										SourceLabels: []promv1.LabelName{"__meta__instance"},
-									},
-								},
-							},
-						},
-					},
-				},
+	}
+	f(o)
+
+	// with label and annotations filter
+	o = opts{
+		sm: &promv1.ServiceMonitor{
+			ObjectMeta: metav1.ObjectMeta{
+				Labels:      map[string]string{"helm.sh/release": "prod", "keep-label": "value"},
+				Annotations: map[string]string{"app.kubernetes.io/": "release"},
 			},
-			want: vmv1beta1.VMServiceScrape{
-				ObjectMeta: metav1.ObjectMeta{
-					Labels: map[string]string{"keep-label": "value"},
-				},
-				Spec: vmv1beta1.VMServiceScrapeSpec{
-					Endpoints: []vmv1beta1.Endpoint{
-						{
-							EndpointRelabelings: vmv1beta1.EndpointRelabelings{
-								MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{
-									{
-										Action:       "drop",
-										SourceLabels: []string{"__meta__instance"},
-									},
-								},
-							},
-						},
+			Spec: promv1.ServiceMonitorSpec{
+				Endpoints: []promv1.Endpoint{{
+					MetricRelabelConfigs: []promv1.RelabelConfig{{
+						Action:       "drop",
+						SourceLabels: []promv1.LabelName{"__meta__instance"},
+					}},
+				}},
+			},
+		},
+		want: vmv1beta1.VMServiceScrape{
+			ObjectMeta: metav1.ObjectMeta{
+				Labels: map[string]string{"keep-label": "value"},
+			},
+			Spec: vmv1beta1.VMServiceScrapeSpec{
+				Endpoints: []vmv1beta1.Endpoint{{
+					EndpointRelabelings: vmv1beta1.EndpointRelabelings{
+						MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{{
+							Action:       "drop",
+							SourceLabels: []string{"__meta__instance"},
+						}},
 					},
-				},
+				}},
 			},
 		},
 	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got := ConvertServiceMonitor(tt.args.serviceMon, &config.BaseOperatorConf{
-				FilterPrometheusConverterLabelPrefixes:      []string{"app.kubernetes", "helm.sh"},
-				FilterPrometheusConverterAnnotationPrefixes: []string{"another-annotation-filter", "app.kubernetes"},
-			})
-			if !reflect.DeepEqual(*got, tt.want) {
-				t.Errorf("ConvertServiceMonitor() got = \n%v, \nwant \n%v", got, tt.want)
-			}
-		})
-	}
+	f(o)
 }
 
 func TestConvertPodEndpoints(t *testing.T) {
-	type args struct {
-		promPodEnpoints []promv1.PodMetricsEndpoint
-	}
-	tests := []struct {
-		name string
-		args args
+	type opts struct {
+		pe   []promv1.PodMetricsEndpoint
 		want []vmv1beta1.PodMetricsEndpoint
-	}{
-		{
-			name: "with partial tls config",
-			args: args{promPodEnpoints: []promv1.PodMetricsEndpoint{
-				{
-					BearerTokenSecret: corev1.SecretKeySelector{},
-					TLSConfig: &promv1.SafeTLSConfig{
-						CA: promv1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{
-							Key: "ca",
-						}},
+	}
+	f := func(opts opts) {
+		t.Helper()
+		if got := convertPodEndpoints(opts.pe); !reflect.DeepEqual(got, opts.want) {
+			t.Errorf("ConvertPodEndpoints() = %v, want %v", got, opts.want)
+		}
+	}
+
+	// with partial tls config
+	o := opts{
+		pe: []promv1.PodMetricsEndpoint{{
+			BearerTokenSecret: corev1.SecretKeySelector{},
+			TLSConfig: &promv1.SafeTLSConfig{
+				CA: promv1.SecretOrConfigMap{
+					ConfigMap: &corev1.ConfigMapKeySelector{
+						Key: "ca",
 					},
 				},
-			}},
-			want: []vmv1beta1.PodMetricsEndpoint{{
-				EndpointAuth: vmv1beta1.EndpointAuth{
-					TLSConfig: &vmv1beta1.TLSConfig{
-						CA: vmv1beta1.SecretOrConfigMap{
-							ConfigMap: &corev1.ConfigMapKeySelector{
-								Key: "ca",
-							},
+			},
+		}},
+		want: []vmv1beta1.PodMetricsEndpoint{{
+			EndpointAuth: vmv1beta1.EndpointAuth{
+				TLSConfig: &vmv1beta1.TLSConfig{
+					CA: vmv1beta1.SecretOrConfigMap{
+						ConfigMap: &corev1.ConfigMapKeySelector{
+							Key: "ca",
 						},
 					},
 				},
-			}},
-		},
+			},
+		}},
+	}
+	f(o)
 
-		{
-			name: "with tls config",
-			args: args{promPodEnpoints: []promv1.PodMetricsEndpoint{
-				{
-					BearerTokenSecret: corev1.SecretKeySelector{},
-					TLSConfig: &promv1.SafeTLSConfig{
-						InsecureSkipVerify: ptr.To(true),
-						ServerName:         ptr.To("some-srv"),
-						CA: promv1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{
-							Key: "ca",
-						}},
+	// with tls config
+	o = opts{
+		pe: []promv1.PodMetricsEndpoint{{
+			BearerTokenSecret: corev1.SecretKeySelector{},
+			TLSConfig: &promv1.SafeTLSConfig{
+				InsecureSkipVerify: ptr.To(true),
+				ServerName:         ptr.To("some-srv"),
+				CA: promv1.SecretOrConfigMap{
+					ConfigMap: &corev1.ConfigMapKeySelector{
+						Key: "ca",
 					},
 				},
-			}},
-			want: []vmv1beta1.PodMetricsEndpoint{{
-				EndpointAuth: vmv1beta1.EndpointAuth{
-					TLSConfig: &vmv1beta1.TLSConfig{
-						InsecureSkipVerify: true,
-						ServerName:         "some-srv",
-						CA: vmv1beta1.SecretOrConfigMap{
-							ConfigMap: &corev1.ConfigMapKeySelector{
-								Key: "ca",
-							},
+			},
+		}},
+		want: []vmv1beta1.PodMetricsEndpoint{{
+			EndpointAuth: vmv1beta1.EndpointAuth{
+				TLSConfig: &vmv1beta1.TLSConfig{
+					InsecureSkipVerify: true,
+					ServerName:         "some-srv",
+					CA: vmv1beta1.SecretOrConfigMap{
+						ConfigMap: &corev1.ConfigMapKeySelector{
+							Key: "ca",
 						},
 					},
 				},
-			}},
-		},
-		{
-			name: "with basic auth and bearer",
-			args: args{promPodEnpoints: []promv1.PodMetricsEndpoint{
-				{
-					BearerTokenSecret: corev1.SecretKeySelector{Key: "bearer"},
-					BasicAuth: &promv1.BasicAuth{
-						Username: corev1.SecretKeySelector{Key: "username"},
-						Password: corev1.SecretKeySelector{Key: "password"},
-					},
+			},
+		}},
+	}
+	f(o)
+
+	// with basic auth and bearer
+	o = opts{
+		pe: []promv1.PodMetricsEndpoint{{
+			BearerTokenSecret: corev1.SecretKeySelector{Key: "bearer"},
+			BasicAuth: &promv1.BasicAuth{
+				Username: corev1.SecretKeySelector{Key: "username"},
+				Password: corev1.SecretKeySelector{Key: "password"},
+			},
+		}},
+		want: []vmv1beta1.PodMetricsEndpoint{{
+			EndpointAuth: vmv1beta1.EndpointAuth{
+				BearerTokenSecret: &corev1.SecretKeySelector{
+					Key: "bearer",
 				},
-			}},
-			want: []vmv1beta1.PodMetricsEndpoint{{
-				EndpointAuth: vmv1beta1.EndpointAuth{
-					BearerTokenSecret: &corev1.SecretKeySelector{
-						Key: "bearer",
-					},
-					BasicAuth: &vmv1beta1.BasicAuth{
-						Username: corev1.SecretKeySelector{
-							Key: "username",
-						},
-						Password: corev1.SecretKeySelector{Key: "password"},
+				BasicAuth: &vmv1beta1.BasicAuth{
+					Username: corev1.SecretKeySelector{
+						Key: "username",
 					},
+					Password: corev1.SecretKeySelector{Key: "password"},
 				},
-			}},
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if got := convertPodEndpoints(tt.args.promPodEnpoints); !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("ConvertPodEndpoints() = %v, want %v", got, tt.want)
-			}
-		})
+			},
+		}},
 	}
+	f(o)
 }
 
 func TestConvertProbe(t *testing.T) {
-	type args struct {
-		probe *promv1.Probe
-	}
-	tests := []struct {
-		name string
-		args args
+	type opts struct {
+		pp   *promv1.Probe
 		want vmv1beta1.VMProbe
-	}{
-		{
-			name: "with static config",
-			args: args{
-				probe: &promv1.Probe{
-					Spec: promv1.ProbeSpec{
-						ProberSpec: promv1.ProberSpec{
-							ProxyURL: "http://proxy.com",
-						},
-						Targets: promv1.ProbeTargets{
-							StaticConfig: &promv1.ProbeTargetStaticConfig{
-								Targets: []string{"target-1", "target-2"},
-								Labels: map[string]string{
-									"l1": "v1",
-									"l2": "v2",
-								},
-								RelabelConfigs: []promv1.RelabelConfig{
-									{
-										Action:       "drop",
-										SourceLabels: []promv1.LabelName{"__address__"},
-									},
-								},
-							},
+	}
+	f := func(opts opts) {
+		t.Helper()
+		got := ConvertProbe(opts.pp, &config.BaseOperatorConf{
+			FilterPrometheusConverterLabelPrefixes:      []string{"helm.sh"},
+			FilterPrometheusConverterAnnotationPrefixes: []string{"app.kubernetes"},
+		})
+
+		if !reflect.DeepEqual(*got, opts.want) {
+			t.Errorf("ConvertProbe() got = \n%v, \nwant \n%v", *got, opts.want)
+		}
+	}
+
+	// with static config
+	o := opts{
+		pp: &promv1.Probe{
+			Spec: promv1.ProbeSpec{
+				ProberSpec: promv1.ProberSpec{
+					ProxyConfig: promv1.ProxyConfig{
+						ProxyURL: ptr.To("http://proxy.com"),
+					},
+				},
+				Targets: promv1.ProbeTargets{
+					StaticConfig: &promv1.ProbeTargetStaticConfig{
+						Targets: []string{"target-1", "target-2"},
+						Labels: map[string]string{
+							"l1": "v1",
+							"l2": "v2",
 						},
+						RelabelConfigs: []promv1.RelabelConfig{{
+							Action:       "drop",
+							SourceLabels: []promv1.LabelName{"__address__"},
+						}},
 					},
 				},
 			},
-			want: vmv1beta1.VMProbe{
-				Spec: vmv1beta1.VMProbeSpec{
-					EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{
-						ProxyURL: ptr.To("http://proxy.com"),
-					},
-					Targets: vmv1beta1.VMProbeTargets{
-						StaticConfig: &vmv1beta1.VMProbeTargetStaticConfig{
-							Targets: []string{"target-1", "target-2"},
-							Labels: map[string]string{
-								"l1": "v1",
-								"l2": "v2",
-							},
-							RelabelConfigs: []*vmv1beta1.RelabelConfig{
-								{
-									Action:       "drop",
-									SourceLabels: []string{"__address__"},
-								},
-							},
+		},
+		want: vmv1beta1.VMProbe{
+			Spec: vmv1beta1.VMProbeSpec{
+				EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{
+					ProxyURL: ptr.To("http://proxy.com"),
+				},
+				Targets: vmv1beta1.VMProbeTargets{
+					StaticConfig: &vmv1beta1.VMProbeTargetStaticConfig{
+						Targets: []string{"target-1", "target-2"},
+						Labels: map[string]string{
+							"l1": "v1",
+							"l2": "v2",
 						},
+						RelabelConfigs: []*vmv1beta1.RelabelConfig{{
+							Action:       "drop",
+							SourceLabels: []string{"__address__"},
+						}},
 					},
 				},
 			},
 		},
-		{
-			name: "with ingress config",
-			args: args{
-				probe: &promv1.Probe{
-					Spec: promv1.ProbeSpec{
-						Targets: promv1.ProbeTargets{
-							Ingress: &promv1.ProbeTargetIngress{
-								Selector: metav1.LabelSelector{
-									MatchLabels: map[string]string{
-										"app": "test",
-									},
-									MatchExpressions: []metav1.LabelSelectorRequirement{
-										{
-											Key:      "key",
-											Operator: "op",
-											Values:   []string{"v1", "v2"},
-										},
-									},
-								},
-								NamespaceSelector: promv1.NamespaceSelector{
-									MatchNames: []string{"test-ns"},
-								},
-								RelabelConfigs: []promv1.RelabelConfig{
-									{
-										Action:       "keep",
-										SourceLabels: []promv1.LabelName{"__address__"},
-									},
-								},
+	}
+	f(o)
+
+	// with ingress config
+	o = opts{
+		pp: &promv1.Probe{
+			Spec: promv1.ProbeSpec{
+				Targets: promv1.ProbeTargets{
+					Ingress: &promv1.ProbeTargetIngress{
+						Selector: metav1.LabelSelector{
+							MatchLabels: map[string]string{
+								"app": "test",
 							},
+							MatchExpressions: []metav1.LabelSelectorRequirement{{
+								Key:      "key",
+								Operator: "op",
+								Values:   []string{"v1", "v2"},
+							}},
+						},
+						NamespaceSelector: promv1.NamespaceSelector{
+							MatchNames: []string{"test-ns"},
 						},
+						RelabelConfigs: []promv1.RelabelConfig{{
+							Action:       "keep",
+							SourceLabels: []promv1.LabelName{"__address__"},
+						}},
 					},
 				},
 			},
-			want: vmv1beta1.VMProbe{
-				Spec: vmv1beta1.VMProbeSpec{
-					Targets: vmv1beta1.VMProbeTargets{
-						Ingress: &vmv1beta1.ProbeTargetIngress{
-							Selector: metav1.LabelSelector{
-								MatchLabels: map[string]string{
-									"app": "test",
-								},
-								MatchExpressions: []metav1.LabelSelectorRequirement{
-									{
-										Key:      "key",
-										Operator: "op",
-										Values:   []string{"v1", "v2"},
-									},
-								},
-							},
-							NamespaceSelector: vmv1beta1.NamespaceSelector{
-								MatchNames: []string{"test-ns"},
-							},
-							RelabelConfigs: []*vmv1beta1.RelabelConfig{
-								{
-									Action:       "keep",
-									SourceLabels: []string{"__address__"},
-								},
+		},
+		want: vmv1beta1.VMProbe{
+			Spec: vmv1beta1.VMProbeSpec{
+				Targets: vmv1beta1.VMProbeTargets{
+					Ingress: &vmv1beta1.ProbeTargetIngress{
+						Selector: metav1.LabelSelector{
+							MatchLabels: map[string]string{
+								"app": "test",
 							},
+							MatchExpressions: []metav1.LabelSelectorRequirement{{
+								Key:      "key",
+								Operator: "op",
+								Values:   []string{"v1", "v2"},
+							}},
+						},
+						NamespaceSelector: vmv1beta1.NamespaceSelector{
+							MatchNames: []string{"test-ns"},
 						},
+						RelabelConfigs: []*vmv1beta1.RelabelConfig{{
+							Action:       "keep",
+							SourceLabels: []string{"__address__"},
+						}},
 					},
 				},
 			},
 		},
 	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got := ConvertProbe(tt.args.probe, &config.BaseOperatorConf{
-				FilterPrometheusConverterLabelPrefixes:      []string{"helm.sh"},
-				FilterPrometheusConverterAnnotationPrefixes: []string{"app.kubernetes"},
-			})
+	f(o)
+}
 
-			if !reflect.DeepEqual(*got, tt.want) {
-				t.Errorf("ConvertProbe() got = \n%v, \nwant \n%v", got, tt.want)
-			}
+func TestConvertPromRule(t *testing.T) {
+	type opts struct {
+		pr   *promv1.PrometheusRule
+		want vmv1beta1.VMRule
+	}
+	f := func(opts opts) {
+		t.Helper()
+		got := ConvertPromRule(opts.pr, &config.BaseOperatorConf{
+			FilterPrometheusConverterLabelPrefixes:      []string{"helm.sh"},
+			FilterPrometheusConverterAnnotationPrefixes: []string{"app.kubernetes"},
 		})
+
+		if !reflect.DeepEqual(*got, opts.want) {
+			t.Errorf("ConvertPromRule() got = \n%v, \nwant \n%v", *got, opts.want)
+		}
+	}
+
+	// with keep firing for
+	o := opts{
+		pr: &promv1.PrometheusRule{
+			Spec: promv1.PrometheusRuleSpec{
+				Groups: []promv1.RuleGroup{{
+					Name: "group-1",
+					Labels: map[string]string{
+						"group-name-1": "group-value-1",
+					},
+					Interval:    promv1.DurationPointer("1m"),
+					QueryOffset: promv1.DurationPointer("10m"),
+					Rules: []promv1.Rule{{
+						Alert:         "target_failed",
+						Expr:          intstr.FromString("valid_target > 0"),
+						For:           promv1.DurationPointer("11m"),
+						KeepFiringFor: ptr.To(promv1.NonEmptyDuration("9m")),
+						Labels: map[string]string{
+							"rule-label-name": "rule-label-value",
+						},
+						Annotations: map[string]string{
+							"rule-annotation-name": "rule-annotation-value",
+						},
+					}},
+					PartialResponseStrategy: "warn",
+					Limit:                   ptr.To(10),
+				}},
+			},
+		},
+		want: vmv1beta1.VMRule{
+			Spec: vmv1beta1.VMRuleSpec{
+				Groups: []vmv1beta1.RuleGroup{{
+					Name: "group-1",
+					Labels: map[string]string{
+						"group-name-1": "group-value-1",
+					},
+					Interval:   "1m",
+					EvalOffset: "10m",
+					Rules: []vmv1beta1.Rule{{
+						Alert:         "target_failed",
+						Expr:          "valid_target > 0",
+						For:           "11m",
+						KeepFiringFor: "9m",
+						Labels: map[string]string{
+							"rule-label-name": "rule-label-value",
+						},
+						Annotations: map[string]string{
+							"rule-annotation-name": "rule-annotation-value",
+						},
+					}},
+					Limit: 10,
+				}},
+			},
+		},
 	}
+	f(o)
 }
diff --git a/internal/controller/operator/converter/v1alpha1/apis_test.go b/internal/controller/operator/converter/v1alpha1/apis_test.go
index cbd66ec8..36d8f0d0 100644
--- a/internal/controller/operator/converter/v1alpha1/apis_test.go
+++ b/internal/controller/operator/converter/v1alpha1/apis_test.go
@@ -16,19 +16,24 @@ import (
 )
 
 func TestConvertAlertmanagerConfig(t *testing.T) {
-	f := func(name string, promCfg *promv1alpha1.AlertmanagerConfig, validate func(convertedAMCfg *vmv1beta1.VMAlertmanagerConfig) error) {
-		t.Run(name, func(t *testing.T) {
-			converted, err := ConvertAlertmanagerConfig(promCfg, &config.BaseOperatorConf{})
-			if err != nil {
-				t.Fatalf("unexpected error: %s", err)
-			}
-			if err := validate(converted); err != nil {
-				t.Fatalf("not valid converted alertmanager config: %s", err)
-			}
-		})
+	type opts struct {
+		promCfg  *promv1alpha1.AlertmanagerConfig
+		validate func(convertedAMCfg *vmv1beta1.VMAlertmanagerConfig) error
 	}
-	f("simple convert",
-		&promv1alpha1.AlertmanagerConfig{
+	f := func(opts opts) {
+		t.Helper()
+		converted, err := ConvertAlertmanagerConfig(opts.promCfg, &config.BaseOperatorConf{})
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+		}
+		if err := opts.validate(converted); err != nil {
+			t.Fatalf("not valid converted alertmanager config: %s", err)
+		}
+	}
+
+	// simple convert
+	o := opts{
+		promCfg: &promv1alpha1.AlertmanagerConfig{
 			ObjectMeta: metav1.ObjectMeta{Name: "test-1"},
 			Spec: promv1alpha1.AlertmanagerConfigSpec{
 				Route: &promv1alpha1.Route{Receiver: "webhook", GroupInterval: "1min"},
@@ -40,7 +45,7 @@ func TestConvertAlertmanagerConfig(t *testing.T) {
 				},
 			},
 		},
-		func(convertedAMCfg *vmv1beta1.VMAlertmanagerConfig) error {
+		validate: func(convertedAMCfg *vmv1beta1.VMAlertmanagerConfig) error {
 			if convertedAMCfg.Name != "test-1" {
 				return fmt.Errorf("name not match, want: %s got: %s", "test-1", convertedAMCfg.Name)
 			}
@@ -54,10 +59,13 @@ func TestConvertAlertmanagerConfig(t *testing.T) {
 				return fmt.Errorf("expected url with secret key")
 			}
 			return nil
-		})
+		},
+	}
+	f(o)
 
-	f("msteamsv2",
-		&promv1alpha1.AlertmanagerConfig{
+	// msteamsv2
+	o = opts{
+		promCfg: &promv1alpha1.AlertmanagerConfig{
 			Spec: promv1alpha1.AlertmanagerConfigSpec{
 				Receivers: []promv1alpha1.Receiver{
 					{
@@ -75,7 +83,7 @@ func TestConvertAlertmanagerConfig(t *testing.T) {
 				},
 			},
 		},
-		func(convertedAMCfg *vmv1beta1.VMAlertmanagerConfig) error {
+		validate: func(convertedAMCfg *vmv1beta1.VMAlertmanagerConfig) error {
 			if len(convertedAMCfg.Spec.Receivers) != 1 {
 				return fmt.Errorf("expected single receiver, got: %d", len(convertedAMCfg.Spec.Receivers))
 			}
@@ -91,322 +99,283 @@ func TestConvertAlertmanagerConfig(t *testing.T) {
 			}
 			return nil
 		},
-	)
+	}
+	f(o)
 }
 
 func TestConvertScrapeConfig(t *testing.T) {
-	type args struct {
+	type opts struct {
 		scrapeConfig *promv1alpha1.ScrapeConfig
 		ownerRef     bool
+		want         vmv1beta1.VMScrapeConfig
 	}
-	tests := []struct {
-		name string
-		args args
-		want vmv1beta1.VMScrapeConfig
-	}{
-		{
-			name: "with static config",
-			args: args{
-				scrapeConfig: &promv1alpha1.ScrapeConfig{
-					Spec: promv1alpha1.ScrapeConfigSpec{
-						StaticConfigs: []promv1alpha1.StaticConfig{
-							{
-								Targets: []promv1alpha1.Target{"target-1", "target-2"},
-							},
-						},
-						HonorTimestamps:   ptr.To(true),
-						EnableCompression: ptr.To(true),
-						BasicAuth: &promv1.BasicAuth{
-							Username: corev1.SecretKeySelector{Key: "username"},
-							Password: corev1.SecretKeySelector{Key: "password"},
-						},
-						MetricsPath: ptr.To("/test"),
-						ProxyConfig: promv1.ProxyConfig{
-							ProxyURL: ptr.To("http://proxy.com"),
-						},
-						RelabelConfigs: []promv1.RelabelConfig{
-							{
-								Action:      "LabelMap",
-								Regex:       "__meta_kubernetes_pod_label_(.+)",
-								Replacement: ptr.To("foo_$1"),
-							},
-						},
-						MetricRelabelConfigs: []promv1.RelabelConfig{
-							{
-								SourceLabels: []promv1.LabelName{"__meta_kubernetes_pod_name", "__meta_kubernetes_pod_container_port_number"},
-								Separator:    ptr.To(":"),
-								TargetLabel:  "host_port",
-							},
-						},
-					},
+	f := func(opts opts) {
+		t.Helper()
+		got := ConvertScrapeConfig(opts.scrapeConfig, &config.BaseOperatorConf{EnabledPrometheusConverterOwnerReferences: opts.ownerRef})
+		if !cmp.Equal(*got, opts.want) {
+			diff := cmp.Diff(*got, opts.want)
+			t.Fatal("not expected output with diff: ", diff)
+		}
+	}
+
+	// with static config
+	o := opts{
+		scrapeConfig: &promv1alpha1.ScrapeConfig{
+			Spec: promv1alpha1.ScrapeConfigSpec{
+				StaticConfigs: []promv1alpha1.StaticConfig{{
+					Targets: []promv1alpha1.Target{"target-1", "target-2"},
+				}},
+				HonorTimestamps:   ptr.To(true),
+				EnableCompression: ptr.To(true),
+				BasicAuth: &promv1.BasicAuth{
+					Username: corev1.SecretKeySelector{Key: "username"},
+					Password: corev1.SecretKeySelector{Key: "password"},
 				},
-			},
-			want: vmv1beta1.VMScrapeConfig{
-				Spec: vmv1beta1.VMScrapeConfigSpec{
-					EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{
-						ProxyURL:        ptr.To("http://proxy.com"),
-						HonorTimestamps: ptr.To(true),
-						VMScrapeParams:  &vmv1beta1.VMScrapeParams{DisableCompression: ptr.To(false)},
-						Path:            "/test",
-					},
-					StaticConfigs: []vmv1beta1.StaticConfig{
-						{
-							Targets: []string{"target-1", "target-2"},
-						},
-					},
-					EndpointAuth: vmv1beta1.EndpointAuth{
-						BasicAuth: &vmv1beta1.BasicAuth{
-							Username: corev1.SecretKeySelector{Key: "username"},
-							Password: corev1.SecretKeySelector{Key: "password"},
-						},
-					},
-					EndpointRelabelings: vmv1beta1.EndpointRelabelings{
-						RelabelConfigs: []*vmv1beta1.RelabelConfig{
-							{
-								Action:      "LabelMap",
-								Regex:       vmv1beta1.StringOrArray{"__meta_kubernetes_pod_label_(.+)"},
-								Replacement: ptr.To("foo_$1"),
-							},
-						},
-						MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{
-							{
-								SourceLabels: []string{"__meta_kubernetes_pod_name", "__meta_kubernetes_pod_container_port_number"},
-								Separator:    ptr.To(":"),
-								TargetLabel:  "host_port",
-							},
-						},
-					},
+				MetricsPath: ptr.To("/test"),
+				ProxyConfig: promv1.ProxyConfig{
+					ProxyURL: ptr.To("http://proxy.com"),
 				},
+				RelabelConfigs: []promv1.RelabelConfig{{
+					Action:      "LabelMap",
+					Regex:       "__meta_kubernetes_pod_label_(.+)",
+					Replacement: ptr.To("foo_$1"),
+				}},
+				MetricRelabelConfigs: []promv1.RelabelConfig{{
+					SourceLabels: []promv1.LabelName{"__meta_kubernetes_pod_name", "__meta_kubernetes_pod_container_port_number"},
+					Separator:    ptr.To(":"),
+					TargetLabel:  "host_port",
+				}},
 			},
 		},
-		{
-			name: "with httpsd config",
-			args: args{
-				scrapeConfig: &promv1alpha1.ScrapeConfig{
-					Spec: promv1alpha1.ScrapeConfigSpec{
-						HTTPSDConfigs: []promv1alpha1.HTTPSDConfig{
-							{
-								URL: "http://test1.com",
-								Authorization: &promv1.SafeAuthorization{
-									Type: "Bearer",
-									Credentials: &corev1.SecretKeySelector{
-										Key: "token",
-									},
-								},
-							},
-							{
-								URL: "http://test2.com",
-								TLSConfig: &promv1.SafeTLSConfig{
-									CA:                 promv1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{Key: "ca.crt"}},
-									Cert:               promv1.SecretOrConfigMap{Secret: &corev1.SecretKeySelector{Key: "cert.pem"}},
-									KeySecret:          &corev1.SecretKeySelector{Key: "key"},
-									ServerName:         ptr.To("test"),
-									InsecureSkipVerify: ptr.To(true),
-								},
-							},
-						},
-					},
+		want: vmv1beta1.VMScrapeConfig{
+			Spec: vmv1beta1.VMScrapeConfigSpec{
+				EndpointScrapeParams: vmv1beta1.EndpointScrapeParams{
+					ProxyURL:        ptr.To("http://proxy.com"),
+					HonorTimestamps: ptr.To(true),
+					VMScrapeParams:  &vmv1beta1.VMScrapeParams{DisableCompression: ptr.To(false)},
+					Path:            "/test",
 				},
-			},
-			want: vmv1beta1.VMScrapeConfig{
-				Spec: vmv1beta1.VMScrapeConfigSpec{
-					HTTPSDConfigs: []vmv1beta1.HTTPSDConfig{
-						{
-							URL: "http://test1.com",
-							Authorization: &vmv1beta1.Authorization{
-								Type: "Bearer",
-								Credentials: &corev1.SecretKeySelector{
-									Key: "token",
-								},
-							},
-						},
-						{
-							URL: "http://test2.com",
-							TLSConfig: &vmv1beta1.TLSConfig{
-								CA:                 vmv1beta1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{Key: "ca.crt"}},
-								Cert:               vmv1beta1.SecretOrConfigMap{Secret: &corev1.SecretKeySelector{Key: "cert.pem"}},
-								KeySecret:          &corev1.SecretKeySelector{Key: "key"},
-								ServerName:         "test",
-								InsecureSkipVerify: true,
-							},
-						},
+				StaticConfigs: []vmv1beta1.StaticConfig{{
+					Targets: []string{"target-1", "target-2"},
+				}},
+				EndpointAuth: vmv1beta1.EndpointAuth{
+					BasicAuth: &vmv1beta1.BasicAuth{
+						Username: corev1.SecretKeySelector{Key: "username"},
+						Password: corev1.SecretKeySelector{Key: "password"},
 					},
 				},
+				EndpointRelabelings: vmv1beta1.EndpointRelabelings{
+					RelabelConfigs: []*vmv1beta1.RelabelConfig{{
+						Action:      "LabelMap",
+						Regex:       vmv1beta1.StringOrArray{"__meta_kubernetes_pod_label_(.+)"},
+						Replacement: ptr.To("foo_$1"),
+					}},
+					MetricRelabelConfigs: []*vmv1beta1.RelabelConfig{{
+						SourceLabels: []string{"__meta_kubernetes_pod_name", "__meta_kubernetes_pod_container_port_number"},
+						Separator:    ptr.To(":"),
+						TargetLabel:  "host_port",
+					}},
+				},
 			},
 		},
-		{
-			name: "with k8s sd config",
-			args: args{
-				scrapeConfig: &promv1alpha1.ScrapeConfig{
-					Spec: promv1alpha1.ScrapeConfigSpec{
-						KubernetesSDConfigs: []promv1alpha1.KubernetesSDConfig{
-							{
-								APIServer: ptr.To("http://1.2.3.4"),
-								Role:      promv1alpha1.KubernetesRole("pod"),
-								Selectors: []promv1alpha1.K8SSelectorConfig{
-									{
-										Label: ptr.To("app=test"),
-									},
-								},
+	}
+	f(o)
+
+	// with httpsd config
+	o = opts{
+		scrapeConfig: &promv1alpha1.ScrapeConfig{
+			Spec: promv1alpha1.ScrapeConfigSpec{
+				HTTPSDConfigs: []promv1alpha1.HTTPSDConfig{
+					{
+						URL: "http://test1.com",
+						Authorization: &promv1.SafeAuthorization{
+							Type: "Bearer",
+							Credentials: &corev1.SecretKeySelector{
+								Key: "token",
 							},
 						},
 					},
-				},
-			},
-			want: vmv1beta1.VMScrapeConfig{
-				Spec: vmv1beta1.VMScrapeConfigSpec{
-					KubernetesSDConfigs: []vmv1beta1.KubernetesSDConfig{
-						{
-							APIServer: ptr.To("http://1.2.3.4"),
-							Role:      "pod",
-							Selectors: []vmv1beta1.K8SSelectorConfig{
-								{
-									Label: "app=test",
-								},
-							},
+					{
+						URL: "http://test2.com",
+						TLSConfig: &promv1.SafeTLSConfig{
+							CA:                 promv1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{Key: "ca.crt"}},
+							Cert:               promv1.SecretOrConfigMap{Secret: &corev1.SecretKeySelector{Key: "cert.pem"}},
+							KeySecret:          &corev1.SecretKeySelector{Key: "key"},
+							ServerName:         ptr.To("test"),
+							InsecureSkipVerify: ptr.To(true),
 						},
 					},
 				},
 			},
 		},
-		{
-			name: "with consul sd config",
-			args: args{
-				scrapeConfig: &promv1alpha1.ScrapeConfig{
-					Spec: promv1alpha1.ScrapeConfigSpec{
-						ConsulSDConfigs: []promv1alpha1.ConsulSDConfig{
-							{
-								Server:     "http://1.2.3.4",
-								TokenRef:   &corev1.SecretKeySelector{Key: "token"},
-								Datacenter: ptr.To("prod"),
-								Namespace:  ptr.To("test"),
+		want: vmv1beta1.VMScrapeConfig{
+			Spec: vmv1beta1.VMScrapeConfigSpec{
+				HTTPSDConfigs: []vmv1beta1.HTTPSDConfig{
+					{
+						URL: "http://test1.com",
+						Authorization: &vmv1beta1.Authorization{
+							Type: "Bearer",
+							Credentials: &corev1.SecretKeySelector{
+								Key: "token",
 							},
 						},
 					},
-				},
-			},
-			want: vmv1beta1.VMScrapeConfig{
-				Spec: vmv1beta1.VMScrapeConfigSpec{
-					ConsulSDConfigs: []vmv1beta1.ConsulSDConfig{
-						{
-							Server:     "http://1.2.3.4",
-							TokenRef:   &corev1.SecretKeySelector{Key: "token"},
-							Datacenter: ptr.To("prod"),
-							Namespace:  ptr.To("test"),
+					{
+						URL: "http://test2.com",
+						TLSConfig: &vmv1beta1.TLSConfig{
+							CA:                 vmv1beta1.SecretOrConfigMap{ConfigMap: &corev1.ConfigMapKeySelector{Key: "ca.crt"}},
+							Cert:               vmv1beta1.SecretOrConfigMap{Secret: &corev1.SecretKeySelector{Key: "cert.pem"}},
+							KeySecret:          &corev1.SecretKeySelector{Key: "key"},
+							ServerName:         "test",
+							InsecureSkipVerify: true,
 						},
 					},
 				},
 			},
 		},
-		{
-			name: "with ec2 sd config",
-			args: args{
-				scrapeConfig: &promv1alpha1.ScrapeConfig{
-					Spec: promv1alpha1.ScrapeConfigSpec{
-						EC2SDConfigs: []promv1alpha1.EC2SDConfig{
-							{
-								Region:    ptr.To("us-west-1"),
-								AccessKey: &corev1.SecretKeySelector{Key: "accesskey"},
-								SecretKey: &corev1.SecretKeySelector{Key: "secret"},
-								Filters: []promv1alpha1.Filter{
-									{
-										Name:   "f1",
-										Values: []string{"1"},
-									},
-								},
-								Port: ptr.To[int32](80),
-							},
-						},
+	}
+	f(o)
+
+	// with k8s sd config
+	o = opts{
+		scrapeConfig: &promv1alpha1.ScrapeConfig{
+			Spec: promv1alpha1.ScrapeConfigSpec{
+				KubernetesSDConfigs: []promv1alpha1.KubernetesSDConfig{
+					{
+						APIServer: ptr.To("http://1.2.3.4"),
+						Role:      promv1alpha1.KubernetesRole("pod"),
+						Selectors: []promv1alpha1.K8SSelectorConfig{{
+							Label: ptr.To("app=test"),
+						}},
 					},
 				},
 			},
-			want: vmv1beta1.VMScrapeConfig{
-				Spec: vmv1beta1.VMScrapeConfigSpec{
-					EC2SDConfigs: []vmv1beta1.EC2SDConfig{
-						{
-							Region:    ptr.To("us-west-1"),
-							AccessKey: &corev1.SecretKeySelector{Key: "accesskey"},
-							SecretKey: &corev1.SecretKeySelector{Key: "secret"},
-							Filters: []*vmv1beta1.EC2Filter{
-								{
-									Name:   "f1",
-									Values: []string{"1"},
-								},
-							},
-							Port: ptr.To(80),
-						},
+		},
+		want: vmv1beta1.VMScrapeConfig{
+			Spec: vmv1beta1.VMScrapeConfigSpec{
+				KubernetesSDConfigs: []vmv1beta1.KubernetesSDConfig{
+					{
+						APIServer: ptr.To("http://1.2.3.4"),
+						Role:      "pod",
+						Selectors: []vmv1beta1.K8SSelectorConfig{{
+							Label: "app=test",
+						}},
 					},
 				},
 			},
 		},
-		{
-			name: "with owner",
-			args: args{
-				scrapeConfig: &promv1alpha1.ScrapeConfig{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "test",
-						Namespace: "test-ns",
-						UID:       "42",
-					},
-					Spec: promv1alpha1.ScrapeConfigSpec{},
-				},
-				ownerRef: true,
+	}
+	f(o)
+
+	// with consul sd config
+	o = opts{
+		scrapeConfig: &promv1alpha1.ScrapeConfig{
+			Spec: promv1alpha1.ScrapeConfigSpec{
+				ConsulSDConfigs: []promv1alpha1.ConsulSDConfig{{
+					Server:     "http://1.2.3.4",
+					TokenRef:   &corev1.SecretKeySelector{Key: "token"},
+					Datacenter: ptr.To("prod"),
+					Namespace:  ptr.To("test"),
+				}},
 			},
-			want: vmv1beta1.VMScrapeConfig{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-ns",
-					OwnerReferences: []metav1.OwnerReference{
-						{
-							APIVersion:         "monitoring.coreos.com/v1alpha1",
-							Kind:               "ScrapeConfig",
-							Name:               "test",
-							UID:                "42",
-							Controller:         ptr.To(true),
-							BlockOwnerDeletion: ptr.To(true),
-						},
-					},
-				},
-				Spec: vmv1beta1.VMScrapeConfigSpec{},
+		},
+		want: vmv1beta1.VMScrapeConfig{
+			Spec: vmv1beta1.VMScrapeConfigSpec{
+				ConsulSDConfigs: []vmv1beta1.ConsulSDConfig{{
+					Server:     "http://1.2.3.4",
+					TokenRef:   &corev1.SecretKeySelector{Key: "token"},
+					Datacenter: ptr.To("prod"),
+					Namespace:  ptr.To("test"),
+				}},
 			},
 		},
-		{
-			name: "with gce sd config",
-			args: args{
-				scrapeConfig: &promv1alpha1.ScrapeConfig{
-					Spec: promv1alpha1.ScrapeConfigSpec{
-						GCESDConfigs: []promv1alpha1.GCESDConfig{
-							{
-								Project:      "eu-project",
-								Zone:         "zone-1",
-								TagSeparator: ptr.To(""),
-								Port:         ptr.To[int32](80),
-							},
-						},
-					},
-				},
+	}
+	f(o)
+
+	// with ec2 sd config
+	o = opts{
+		scrapeConfig: &promv1alpha1.ScrapeConfig{
+			Spec: promv1alpha1.ScrapeConfigSpec{
+				EC2SDConfigs: []promv1alpha1.EC2SDConfig{{
+					Region:    ptr.To("us-west-1"),
+					AccessKey: &corev1.SecretKeySelector{Key: "accesskey"},
+					SecretKey: &corev1.SecretKeySelector{Key: "secret"},
+					Filters: []promv1alpha1.Filter{{
+						Name:   "f1",
+						Values: []string{"1"},
+					}},
+					Port: ptr.To[int32](80),
+				}},
 			},
-			want: vmv1beta1.VMScrapeConfig{
-				Spec: vmv1beta1.VMScrapeConfigSpec{
-					GCESDConfigs: []vmv1beta1.GCESDConfig{
-						{
-							Project:      "eu-project",
-							Zone:         vmv1beta1.StringOrArray{"zone-1"},
-							TagSeparator: ptr.To(""),
-							Port:         ptr.To(80),
-						},
-					},
-				},
+		},
+		want: vmv1beta1.VMScrapeConfig{
+			Spec: vmv1beta1.VMScrapeConfigSpec{
+				EC2SDConfigs: []vmv1beta1.EC2SDConfig{{
+					Region:    ptr.To("us-west-1"),
+					AccessKey: &corev1.SecretKeySelector{Key: "accesskey"},
+					SecretKey: &corev1.SecretKeySelector{Key: "secret"},
+					Filters: []*vmv1beta1.EC2Filter{{
+						Name:   "f1",
+						Values: []string{"1"},
+					}},
+					Port: ptr.To(80),
+				}},
 			},
 		},
 	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got := ConvertScrapeConfig(tt.args.scrapeConfig, &config.BaseOperatorConf{EnabledPrometheusConverterOwnerReferences: tt.args.ownerRef})
-			if !cmp.Equal(*got, tt.want) {
-				diff := cmp.Diff(*got, tt.want)
-				t.Fatal("not expected output with diff: ", diff)
-			}
-		})
+	f(o)
+
+	// with owner
+	o = opts{
+		scrapeConfig: &promv1alpha1.ScrapeConfig{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "test",
+				Namespace: "test-ns",
+				UID:       "42",
+			},
+			Spec: promv1alpha1.ScrapeConfigSpec{},
+		},
+		ownerRef: true,
+		want: vmv1beta1.VMScrapeConfig{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "test",
+				Namespace: "test-ns",
+				OwnerReferences: []metav1.OwnerReference{{
+					APIVersion:         "monitoring.coreos.com/v1alpha1",
+					Kind:               "ScrapeConfig",
+					Name:               "test",
+					UID:                "42",
+					Controller:         ptr.To(true),
+					BlockOwnerDeletion: ptr.To(true),
+				}},
+			},
+			Spec: vmv1beta1.VMScrapeConfigSpec{},
+		},
+	}
+	f(o)
+
+	// with gce sd config
+	o = opts{
+		scrapeConfig: &promv1alpha1.ScrapeConfig{
+			Spec: promv1alpha1.ScrapeConfigSpec{
+				GCESDConfigs: []promv1alpha1.GCESDConfig{{
+					Project:      "eu-project",
+					Zone:         "zone-1",
+					TagSeparator: ptr.To(""),
+					Port:         ptr.To[int32](80),
+				}},
+			},
+		},
+		want: vmv1beta1.VMScrapeConfig{
+			Spec: vmv1beta1.VMScrapeConfigSpec{
+				GCESDConfigs: []vmv1beta1.GCESDConfig{{
+					Project:      "eu-project",
+					Zone:         vmv1beta1.StringOrArray{"zone-1"},
+					TagSeparator: ptr.To(""),
+					Port:         ptr.To(80),
+				}},
+			},
+		},
 	}
+	f(o)
 }