Repository: apache/camel-k
Pull request #4159 (2023-03-24 01:01:26)

chore(deps): bump github.com/onsi/gomega from 1.27.4 to 1.27.5
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.27.4 to 1.27.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/onsi/gomega/releases">github.com/onsi/gomega's releases</a>.</em></p>
<blockquote>
<h2>v1.27.5</h2>
<h2>1.27.5</h2>
<h3>Maintenance</h3>
<ul>
<li>Bump github.com/onsi/ginkgo/v2 from 2.9.1 to 2.9.2 (<a href="https://redirect.github.com/onsi/gomega/issues/653">#653</a>) [a215021]</li>
<li>Bump github.com/go-task/slim-sprig (<a href="https://redirect.github.com/onsi/gomega/issues/652">#652</a>) [a26fed8]</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/onsi/gomega/blob/master/CHANGELOG.md">github.com/onsi/gomega's changelog</a>.</em></p>
<blockquote>
<h2>1.27.5</h2>
<h3>Maintenance</h3>
<ul>
<li>Bump github.com/onsi/ginkgo/v2 from 2.9.1 to 2.9.2 (<a href="https://redirect.github.com/onsi/gomega/issues/653">#653</a>) [a215021]</li>
<li>Bump github.com/go-task/slim-sprig (<a href="https://redirect.github.com/onsi/gomega/issues/652">#652</a>) [a26fed8]</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/onsi/gomega/commit/5129b5cf7d54245b130b241a4ace8a0d12442ab1"><code>5129b5c</code></a> v1.27.5</li>
<li><a href="https://github.com/onsi/gomega/commit/a215021955460515ff0c6673353fdbe38ebdc48d"><code>a215021</code></a> Bump github.com/onsi/ginkgo/v2 from 2.9.1 to 2.9.2 (<a href="https://redirect.github.com/onsi/gomega/issues/653">#653</a>)</li>
<li><a href="https://github.com/onsi/gomega/commit/a26fed89eba179ec91bb43d4a913ddadac3cd434"><code>a26fed8</code></a> Bump github.com/go-task/slim-sprig (<a href="https://redirect.github.com/onsi/gomega/issues/652">#652</a>)</li>
<li>See full diff in <a href="https://github.com/onsi/gomega/compare/v1.27.4...v1.27.5">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/onsi/gomega&package-manager=go_modules&previous-version=1.27.4&new-version=1.27.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/docs/modules/ROOT/pages/contributing/local-development.adoc b/docs/modules/ROOT/pages/contributing/local-development.adoc
index 82d61e8a7..ff6197b55 100644
--- a/docs/modules/ROOT/pages/contributing/local-development.adoc
+++ b/docs/modules/ROOT/pages/contributing/local-development.adoc
@@ -4,85 +4,40 @@
 If you plan on contributing to Camel K, you will end up needing to run and troubleshoot your operator code locally. Here is a guideline that will help you configure your local operator running.
 
 [[local-operator]]
-== Running operator locally
+== Running a development operator
 
-As soon as you build your operator locally you will ask yourself how to test it. The idea is that you execute it locally and instruct it to **watch** a namespace on a Kubernetes cluster (it may be remote or any local environment). Let's use a namespace called ``operator-test``.
+As soon as you build your operator locally you will ask yourself how to test it. In the past, we used to have the possibility to run the operator on the same development machine and connect to Kubernetes cluster. However, that approach was quite cumbersome, so now we propose a way to locally install and run your development Camel K operator as it was a "normal" installation.
 
-* You can start with setting the environment variable ``WATCH_NAMESPACE`` with the namespace you'd like your operator to watch. You also need to specify the name of the operator, as you may have different operators running on the cluster.
-----
-export WATCH_NAMESPACE=operator-test
-export OPERATOR_ID="camel-k-dev"
-----
+Once you have done your development, you will need to build and push Camel K Operator container image to the container registry your Kubernetes is later going to use. If you're on a local machine, you are probably using Minikube or Kind. In such case you can make your Docker daemon to use the cluster container registry. In Minikube it would be like the following:
 
-* The next step is to install an ``IntegrationPlatform`` on the cluster namespace. You probably need to tweak the registry parameters in order to be able to authenticate against an image repository (see below paragraph for local repository instructions). It's important to specify the target operator that will take care of this IntegrationPlatform (`-x` or `--operator-id` option).
+[source]
 ----
-./kamel install --skip-operator-setup -n operator-test --registry my-registry:5000 -x camel-k-dev
+eval $(minikube -p minikube docker-env)
 ----
 
-* Finally, assuming you've built your application correctly we can run the operator:
------
-./kamel operator
------
-
-* Test the local operator by creating a test `Integration`.
------
-./kamel run xyz.abc -n operator-test -x camel-k-dev
------
-
-IMPORTANT: make sure no other Camel K Operators are watching this namespace, neither you have a global Camel K Operator  installed on your cluster. As you may have more than one Camel K operator installed on the cluster, it's important you specify the `-x` (or `--operator-id`) option.
+For other cluster types you may check the specific documentation. As soon as you're connected to the Docker daemon you can build images via:
 
-[[local-minikube]]
-== Local operator and local cluster
-
-If you want to run a local operator togheter with ``Minikube`` you will need an additional step in order to let the local operator push images in the local registry. We need to expose the local registry as described in https://minikube.sigs.k8s.io/docs/handbook/registry/#docker-on-windows[this procedure]:
-
-* Enable the addon registry (this should be already in place):
+[source]
 ----
-minikube addons enable registry
+make images
 ----
 
-* Get the ``Pod`` name that is in charge to run the registry and proxy the registry 5000 port to be used locally.
-----
-kubectl get pods -n kube-system
-NAME                               READY   STATUS    RESTARTS   AGE
-...
-registry-fttbv                     1/1     Running   40         89d
-...
+This command will build and publish your actual Camel K development version to the container registry. At this stage installing the Camel K development version will be as easy as a typical installation:
 
-kubectl port-forward --namespace kube-system registry-fttbv 5000:5000
+[source]
 ----
-
-* Update the ``IntegrationPlatform`` to instruct it to use the ``localhost`` registry:
-----
-./kamel install --skip-operator-setup -n operator-test --registry localhost:5000 --force -x camel-k-dev
+./kamel install
 ----
 
-A similar procedure may work if you use other local environments. The idea is to expose the docker registry and be able to use it from your local operator.
-
-IMPORTANT: using build strategy as `Pod` won't probably work as it will expect the registry to be available at a URL not possible to reach from a local machine.
+You can provide any customization required such as `--log-level`, `--operator-id`, etcetera. Mind that you need to use `./kamel` in order to use the development binary you've just built, as tipically, `kamel` is the production CLI you have installed in your binary path.
 
 === Local Camel K runtime
 
-Camel K integrations are based on https://github.com/apache/camel-k-runtime[Camel K runtime], generally paired with the operator release. If you need to specify a different runtime, or you have a local Camel K runtime that you want to test, then you will need to specify it in the `Integration Platform`:
-----
-./kamel install --skip-operator-setup -n operator-test --registry localhost:5000 --force --runtime-version $version -x camel-k-dev
-----
+Camel K integrations are based on https://github.com/apache/camel-k-runtime[Camel K runtime], generally paired with the operator release. If you need to specify a different runtime, or you have a local Camel K Runtime that you want to test you need to build a Camel K version bundled with the local Camel K Runtime bits
 
-The `$version` variable must be replaced with the version you are building. For example, `1.3.1-SNAPSHOT`. With these instructions, the operator will pick up and use the snapshot version you have released locally. In order to use the local maven repository, you will also need to edit your IntegrationPlatform as follow:
 ----
-$ k edit ip -n operator-test
-
-...
-  spec:
-    build:
-      maven:
-        cliOptions:
-        - -V
-        localRepository: /home/user/.m2/repository
-        settings: {}
-...
+make images CAMEL_K_RUNTIME_DIR=<path/to/local/ck-runtime/project>
 ----
-pointing the `localRepository` where your local maven is storing the artifacts (it will look for the camel-k-runtime dependencies there).
 
+Once this is done you need to re-install via `./kamel install`.
 
-Alternatively, if no local registry is available, you can use another type of registry as explained in xref:installation/registry/registry.adoc[the Registry section].
diff --git a/go.mod b/go.mod
index 8fab3d6dc..f60f4b301 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
 	github.com/mattn/go-shellwords v1.0.3
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/mitchellh/mapstructure v1.5.0
-	github.com/onsi/gomega v1.27.4
+	github.com/onsi/gomega v1.27.5
 	github.com/openshift/api v3.9.1-0.20190927182313-d4a64ec2cbd8+incompatible
 	github.com/operator-framework/api v0.13.0
 	github.com/otiai10/copy v1.9.0
diff --git a/go.sum b/go.sum
index 1c80b8f15..728bd070d 100644
--- a/go.sum
+++ b/go.sum
@@ -494,8 +494,8 @@ github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
 github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
 github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
 github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
@@ -943,7 +943,7 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
 github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
+github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
 github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -953,8 +953,8 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs
 github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
 github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
 github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
-github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
-github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
+github.com/onsi/gomega v1.27.5 h1:T/X6I0RNFw/kTqgfkZPcQ5KU6vCnWNBGdtrIx2dpGeQ=
+github.com/onsi/gomega v1.27.5/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
 github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
diff --git a/pkg/controller/integration/kits.go b/pkg/controller/integration/kits.go
index 2cf22089b..8c8cebd1e 100644
--- a/pkg/controller/integration/kits.go
+++ b/pkg/controller/integration/kits.go
@@ -131,6 +131,12 @@ func integrationMatches(integration *v1.Integration, kit *v1.IntegrationKit) (bo
 		ilog.Debug("Integration and integration-kit dependencies do not match", "integration", integration.Name, "integration-kit", kit.Name, "namespace", integration.Namespace)
 		return false, nil
 	}
+	// If IntegrationKit has any source, we must verify that it corresponds with the one in the Integration.
+	// This is important in case of Native builds as we need to rebuild when language requires a source during build.
+	if (kit.Spec.Sources != nil && len(kit.Spec.Sources) > 0) && !hasMatchingSources(integration, kit) {
+		ilog.Debug("Integration and integration-kit sources do not match", "integration", integration.Name, "integration-kit", kit.Name, "namespace", integration.Namespace)
+		return false, nil
+	}
 
 	ilog.Debug("Matched Integration and integration-kit", "integration", integration.Name, "integration-kit", kit.Name, "namespace", integration.Namespace)
 	return true, nil
@@ -250,3 +256,22 @@ func matchesTrait(it map[string]interface{}, kt map[string]interface{}) bool {
 	// perform exact match on the two trait maps
 	return reflect.DeepEqual(it, kt)
 }
+
+func hasMatchingSources(it *v1.Integration, kit *v1.IntegrationKit) bool {
+	if len(it.Sources()) != len(kit.Spec.Sources) {
+		return false
+	}
+	for _, itSource := range it.Sources() {
+		found := false
+		for _, ikSource := range kit.Spec.Sources {
+			if itSource.Content == ikSource.Content {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return false
+		}
+	}
+	return true
+}
diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index ae517e797..c23b0583f 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -167,6 +167,18 @@ var assets = func() http.FileSystem {
 			name:    "manager",
 			modTime: time.Time{},
 		},
+		"/manager/bundle": &vfsgen۰DirInfo{
+			name:    "bundle",
+			modTime: time.Time{},
+		},
+		"/manager/bundle/manifests": &vfsgen۰DirInfo{
+			name:    "manifests",
+			modTime: time.Time{},
+		},
+		"/manager/bundle/metadata": &vfsgen۰DirInfo{
+			name:    "metadata",
+			modTime: time.Time{},
+		},
 		"/manager/operator-deployment.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "operator-deployment.yaml",
 			modTime:          time.Time{},
@@ -671,6 +683,7 @@ var assets = func() http.FileSystem {
 		fs["/crd/bases/camel.apache.org_kamelets.yaml"].(os.FileInfo),
 	}
 	fs["/manager"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
+		fs["/manager/bundle"].(os.FileInfo),
 		fs["/manager/operator-deployment.yaml"].(os.FileInfo),
 		fs["/manager/operator-pvc.yaml"].(os.FileInfo),
 		fs["/manager/operator-service-account.yaml"].(os.FileInfo),
@@ -684,6 +697,10 @@ var assets = func() http.FileSystem {
 		fs["/manager/patch-toleration.yaml"].(os.FileInfo),
 		fs["/manager/patch-watch-namespace-global.yaml"].(os.FileInfo),
 	}
+	fs["/manager/bundle"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
+		fs["/manager/bundle/manifests"].(os.FileInfo),
+		fs["/manager/bundle/metadata"].(os.FileInfo),
+	}
 	fs["/prometheus"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
 		fs["/prometheus/operator-pod-monitor.yaml"].(os.FileInfo),
 		fs["/prometheus/operator-prometheus-rule.yaml"].(os.FileInfo),
diff --git a/pkg/util/defaults/defaults.go b/pkg/util/defaults/defaults.go
index fad3aed54..c20ed0e4f 100644
--- a/pkg/util/defaults/defaults.go
+++ b/pkg/util/defaults/defaults.go
@@ -26,7 +26,7 @@ const (
 	Version = "2.0.0-SNAPSHOT"
 
 	// DefaultRuntimeVersion --
-	DefaultRuntimeVersion = "1.18.0-SNAPSHOT"
+	DefaultRuntimeVersion = "3.20.1-SNAPSHOT"
 
 	// BuildahVersion --
 	BuildahVersion = "1.23.3"


Test patch:
diff --git a/e2e/common/config/config_test.go b/e2e/common/config/config_test.go
index 07b239632..f3362b343 100644
--- a/e2e/common/config/config_test.go
+++ b/e2e/common/config/config_test.go
@@ -283,7 +283,7 @@ func TestRunConfigExamples(t *testing.T) {
 		Eventually(IntegrationConditionStatus(ns, "build-property-route-updated", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
 		Eventually(IntegrationLogs(ns, "build-property-route-updated"), TestTimeoutShort).Should(ContainSubstring("my-super-application-updated"))
 		// Verify the integration kits are different
-		Expect(IntegrationKit(ns, "build-property-route")).ShouldNot(Equal(IntegrationKit(ns, "build-property-route-updated")))
+		Eventually(IntegrationKit(ns, "build-property-route-updated")).ShouldNot(Equal(IntegrationKit(ns, "build-property-route")()))
 		Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
 	})
 
diff --git a/e2e/native/files/Java2.java b/e2e/native/files/Java2.java
new file mode 100644
index 000000000..73b29ab99
--- /dev/null
+++ b/e2e/native/files/Java2.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ import org.apache.camel.builder.RouteBuilder;
+
+ public class Java extends RouteBuilder {
+   @Override
+   public void configure() throws Exception {
+     from("timer:tick")
+       .setHeader("m").constant("string!")
+       .setBody().simple("Magic2${header.m}")
+       .log("Java ${body}");
+   }
+ }
diff --git a/e2e/native/files/yaml2.yaml b/e2e/native/files/yaml2.yaml
new file mode 100644
index 000000000..d717e5da6
--- /dev/null
+++ b/e2e/native/files/yaml2.yaml
@@ -0,0 +1,28 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+
+- from:
+    uri: "timer:yaml"
+    parameters:
+      period: "5000"
+    steps:
+      - set-header:
+          name: "m"
+          constant: "string!"
+      - set-body:
+          simple: "Magic${header.m}2"
+      - to: "log:info"
diff --git a/e2e/native/native_test.go b/e2e/native/native_test.go
index 0060b0d93..d7c7c2ba5 100644
--- a/e2e/native/native_test.go
+++ b/e2e/native/native_test.go
@@ -75,24 +75,10 @@ func TestNativeIntegrations(t *testing.T) {
 			Expect(Kamel("delete", name, "-n", ns).Execute()).To(Succeed())
 		})
 
-		t.Run("warm up before native build testing", func(t *testing.T) {
-			// The following native build test is under tight time constraints, so here it runs
-			// a warm up testing to make sure necessary jars are already downloaded.
-			name := "warm-up-yaml"
-			Expect(KamelRunWithID(operatorID, ns, "files/yaml.yaml", "--name", name).Execute()).To(Succeed())
-
-			Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning))
-			Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).
-				Should(Equal(corev1.ConditionTrue))
-			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
-
-			// Clean up
-			Expect(Kamel("delete", name, "-n", ns).Execute()).To(Succeed())
-			Expect(DeleteKits(ns)).To(Succeed())
-		})
-
 		t.Run("automatic rollout deployment from fast-jar to native kit", func(t *testing.T) {
-			name := "jvm-to-native"
+			// Let's make sure we start from a clean state
+			Expect(DeleteKits(ns)).To(Succeed())
+			name := "yaml-native"
 			Expect(KamelRunWithID(operatorID, ns, "files/yaml.yaml", "--name", name,
 				"-t", "quarkus.package-type=fast-jar",
 				"-t", "quarkus.package-type=native",
@@ -143,8 +129,25 @@ func TestNativeIntegrations(t *testing.T) {
 
 			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
 
+			t.Run("yaml native should not rebuild", func(t *testing.T) {
+				name := "yaml-native-2"
+				Expect(KamelRunWithID(operatorID, ns, "files/yaml2.yaml", "--name", name,
+					"-t", "quarkus.package-type=native",
+				).Execute()).To(Succeed())
+
+				// This one should run quickly as it suppose to reuse an IntegrationKit
+				Eventually(IntegrationPodPhase(ns, name), TestTimeoutShort).Should(Equal(corev1.PodRunning))
+				Eventually(IntegrationPod(ns, name), TestTimeoutShort).
+					Should(WithTransform(getContainerCommand(), MatchRegexp(".*camel-k-integration-\\d+\\.\\d+\\.\\d+[-A-Za-z]*-runner.*")))
+				Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).
+					Should(Equal(corev1.ConditionTrue))
+				Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Magicstring!2"))
+				Eventually(IntegrationKit(ns, "yaml-native-2")).Should(Equal(IntegrationKit(ns, "yaml-native")()))
+			})
+
 			// Clean up
 			Expect(Kamel("delete", name, "-n", ns).Execute()).To(Succeed())
 		})
+
 	})
 }
diff --git a/e2e/native/native_with_sources_test.go b/e2e/native/native_with_sources_test.go
index ab3348fca..b5128ab95 100644
--- a/e2e/native/native_with_sources_test.go
+++ b/e2e/native/native_with_sources_test.go
@@ -54,9 +54,39 @@ func TestNativeHighMemoryIntegrations(t *testing.T) {
 				Should(WithTransform(getContainerCommand(), MatchRegexp(".*camel-k-integration-\\d+\\.\\d+\\.\\d+[-A-Za-z]*-runner.*")))
 			Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).
 				Should(Equal(corev1.ConditionTrue))
-
 			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Java Magicstring!"))
 
+			t.Run("java native same should not rebuild", func(t *testing.T) {
+				name := "java-native-clone"
+				Expect(KamelRunWithID(operatorID, ns, "files/Java.java", "--name", name,
+					"-t", "quarkus.package-type=native",
+				).Execute()).To(Succeed())
+
+				// This one should run quickly as it suppose to reuse an IntegrationKit
+				Eventually(IntegrationPodPhase(ns, name), TestTimeoutShort).Should(Equal(corev1.PodRunning))
+				Eventually(IntegrationPod(ns, name), TestTimeoutShort).
+					Should(WithTransform(getContainerCommand(), MatchRegexp(".*camel-k-integration-\\d+\\.\\d+\\.\\d+[-A-Za-z]*-runner.*")))
+				Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).
+					Should(Equal(corev1.ConditionTrue))
+				Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Java Magicstring!"))
+				Eventually(IntegrationKit(ns, "java-native-clone")).Should(Equal(IntegrationKit(ns, "java-native")()))
+			})
+
+			t.Run("java native should rebuild", func(t *testing.T) {
+				name := "java-native-2"
+				Expect(KamelRunWithID(operatorID, ns, "files/Java2.java", "--name", name,
+					"-t", "quarkus.package-type=native",
+				).Execute()).To(Succeed())
+
+				Eventually(IntegrationPodPhase(ns, name), TestTimeoutVeryLong).Should(Equal(corev1.PodRunning))
+				Eventually(IntegrationPod(ns, name), TestTimeoutShort).
+					Should(WithTransform(getContainerCommand(), MatchRegexp(".*camel-k-integration-\\d+\\.\\d+\\.\\d+[-A-Za-z]*-runner.*")))
+				Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).
+					Should(Equal(corev1.ConditionTrue))
+				Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Java Magic2string!"))
+				Eventually(IntegrationKit(ns, "java-native-2")).ShouldNot(Equal(IntegrationKit(ns, "java-native")()))
+			})
+
 			// Clean up
 			Expect(Kamel("delete", name, "-n", ns).Execute()).To(Succeed())
 		})
diff --git a/pkg/controller/integration/kits_test.go b/pkg/controller/integration/kits_test.go
index 94709f977..4e316bace 100644
--- a/pkg/controller/integration/kits_test.go
+++ b/pkg/controller/integration/kits_test.go
@@ -338,3 +338,100 @@ func TestHasMatchingTraits_KitSameTraitShouldBePicked(t *testing.T) {
 	assert.Nil(t, err)
 	assert.True(t, ok)
 }
+
+func TestHasMatchingSources(t *testing.T) {
+	integration := &v1.Integration{
+		Spec: v1.IntegrationSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	kit := &v1.IntegrationKit{
+		Spec: v1.IntegrationKitSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	hms := hasMatchingSources(integration, kit)
+	assert.True(t, hms)
+
+	kit2 := &v1.IntegrationKit{
+		Spec: v1.IntegrationKitSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content 2", v1.LanguageJavaShell),
+				v1.NewSourceSpec("test", "some content", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	hms2 := hasMatchingSources(integration, kit2)
+	assert.False(t, hms2)
+}
+
+func TestHasMatchingMultipleSources(t *testing.T) {
+	integration := &v1.Integration{
+		Spec: v1.IntegrationSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content", v1.LanguageJavaShell),
+				v1.NewSourceSpec("test", "some content 2", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	kit := &v1.IntegrationKit{
+		Spec: v1.IntegrationKitSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content 2", v1.LanguageJavaShell),
+				v1.NewSourceSpec("test", "some content", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	hms := hasMatchingSources(integration, kit)
+	assert.True(t, hms)
+
+	integration2 := &v1.Integration{
+		Spec: v1.IntegrationSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	hms2 := hasMatchingSources(integration2, kit)
+	assert.False(t, hms2)
+}
+
+func TestHasNotMatchingSources(t *testing.T) {
+	integration := &v1.Integration{
+		Spec: v1.IntegrationSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	kit := &v1.IntegrationKit{
+		Spec: v1.IntegrationKitSpec{
+			Sources: []v1.SourceSpec{
+				v1.NewSourceSpec("test", "some content 2", v1.LanguageJavaShell),
+			},
+		},
+	}
+
+	hsm := hasMatchingSources(integration, kit)
+	assert.False(t, hsm)
+
+	kit2 := &v1.IntegrationKit{
+		Spec: v1.IntegrationKitSpec{
+			Sources: []v1.SourceSpec{},
+		},
+	}
+
+	hsm2 := hasMatchingSources(integration, kit2)
+	assert.False(t, hsm2)
+}
diff --git a/pkg/util/camel/camel_util_test.go b/pkg/util/camel/camel_util_test.go
index 945631ba0..d696dab95 100644
--- a/pkg/util/camel/camel_util_test.go
+++ b/pkg/util/camel/camel_util_test.go
@@ -18,8 +18,10 @@ limitations under the License.
 package camel
 
 import (
+	"sort"
 	"testing"
 
+	"github.com/Masterminds/semver"
 	"github.com/stretchr/testify/assert"
 
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -64,3 +66,54 @@ func TestFindRangeMatch(t *testing.T) {
 	assert.Equal(t, "1.0.2", c.Runtime.Version)
 	assert.Equal(t, v1.RuntimeProviderQuarkus, c.Runtime.Provider)
 }
+
+func TestMissingMatch(t *testing.T) {
+	catalogs := []v1.CamelCatalog{
+		{Spec: v1.CamelCatalogSpec{Runtime: v1.RuntimeSpec{Version: "1.0.0", Provider: v1.RuntimeProviderQuarkus}}},
+	}
+
+	c, err := findBestMatch(catalogs, v1.RuntimeSpec{Version: "1.0.1", Provider: v1.RuntimeProviderQuarkus})
+	assert.Nil(t, err)
+	assert.Nil(t, c)
+}
+
+func TestNewCatalogVersionCollection(t *testing.T) {
+	catalogs := []v1.CamelCatalog{
+		{Spec: v1.CamelCatalogSpec{Runtime: v1.RuntimeSpec{Version: "1.0.0", Provider: v1.RuntimeProviderQuarkus}}},
+	}
+
+	versions := make([]CatalogVersion, 0, len(catalogs))
+	rv, _ := semver.NewVersion(catalogs[0].Spec.Runtime.Version)
+	versions = append(versions, CatalogVersion{
+		RuntimeVersion: rv,
+		Catalog:        &catalogs[0],
+	})
+	expected := CatalogVersionCollection(versions)
+	sort.Sort(sort.Reverse(expected))
+
+	c := newCatalogVersionCollection(catalogs)
+
+	assert.Equal(t, expected, c)
+
+}
+func TestIncorrectConstraint(t *testing.T) {
+	rc := newSemVerConstraint("1.A.0")
+	assert.Nil(t, rc)
+
+	catalogs := []v1.CamelCatalog{
+		{Spec: v1.CamelCatalogSpec{Runtime: v1.RuntimeSpec{Version: "1.A.0", Provider: v1.RuntimeProviderQuarkus}}},
+	}
+	c, err := findBestMatch(catalogs, v1.RuntimeSpec{Version: "1.0.0", Provider: v1.RuntimeProviderQuarkus})
+	assert.Nil(t, err)
+	assert.Nil(t, c)
+}
+
+func TestGetDependency(t *testing.T) {
+	artifact := v1.CamelArtifact{}
+	artifact.ArtifactID = "camel-quarkus-"
+	provider := v1.RuntimeProviderQuarkus
+	assert.Equal(t, "camel:", getDependency(artifact, provider))
+	provider = v1.RuntimeProvider("notquarkus")
+	artifact.ArtifactID = "camel-"
+	assert.Equal(t, "camel:", getDependency(artifact, provider))
+}
diff --git a/pkg/util/docker/docker_base_test.go b/pkg/util/docker/docker_base_test.go
new file mode 100644
index 000000000..23aa58db5
--- /dev/null
+++ b/pkg/util/docker/docker_base_test.go
@@ -0,0 +1,95 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package docker
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestBuildImageArgs(t *testing.T) {
+
+	args := BuildImageArgs("dockerfileDirectory", "imageName", "sourceDirectory")
+	assert.Equal(t, "build", args[0])
+	assert.Equal(t, "-f", args[1])
+	assert.Equal(t, "dockerfileDirectory/Dockerfile", args[2])
+	assert.Equal(t, "-t", args[3])
+	assert.Equal(t, "imageName", args[4])
+	assert.Equal(t, "sourceDirectory", args[5])
+}
+
+func TestRunImageArgs(t *testing.T) {
+
+	args, err := RunImageArgs("imagePath")
+	assert.Nil(t, err)
+	assert.Equal(t, "run", args[0])
+	assert.Equal(t, "--network="+NetworkName, args[1])
+	assert.Equal(t, "-t", args[2])
+	assert.Equal(t, "imagePath:latest", args[3])
+}
+
+func TestDockerfilePathArg(t *testing.T) {
+	args := DockerfilePathArg("path/docker")
+	assert.Equal(t, "-f", args[0])
+	assert.Equal(t, "path/docker", args[1])
+}
+
+func TestImageArg(t *testing.T) {
+	args := ImageArg("imageName", "tag")
+	assert.Equal(t, "-t", args[0])
+	assert.Equal(t, "imageName:tag", args[1])
+}
+
+func TestLatestImageArg(t *testing.T) {
+	args := LatestImageArg("imageName")
+	assert.Equal(t, "-t", args[0])
+	assert.Equal(t, "imageName:latest", args[1])
+}
+
+func TestFullImageArg(t *testing.T) {
+	args := FullImageArg("dir/imageName:tag")
+	assert.Equal(t, "-t", args[0])
+	assert.Equal(t, "dir/imageName:tag", args[1])
+
+	args = FullImageArg("imageName:tag")
+	assert.Equal(t, "-t", args[0])
+	assert.Equal(t, "imageName:tag", args[1])
+
+	args = FullImageArg("imageName")
+	assert.Equal(t, "-t", args[0])
+	assert.Equal(t, "imageName:latest", args[1])
+}
+
+func TestGetImage(t *testing.T) {
+	image := GetImage("imageName", "tag")
+	assert.Equal(t, "imageName:tag", image)
+	assert.Equal(t, GetImage("imageName", "latest"), GetLatestImage("imageName"))
+}
+
+func TestGetFullDockerImage(t *testing.T) {
+	image := GetFullDockerImage("dir/dir/imageName", "tag")
+	assert.Equal(t, "dir/dir/imageName:tag", image)
+	image = GetFullDockerImage("imageName", "tag")
+	assert.Equal(t, "imageName:tag", image)
+}
+
+func TestJoinPath(t *testing.T) {
+	path := JoinPath("path1", "dir/path2")
+	assert.Equal(t, "path1/dir/path2", path)
+}
diff --git a/pkg/util/docker/docker_test.go b/pkg/util/docker/docker_test.go
new file mode 100644
index 000000000..7d15caa36
--- /dev/null
+++ b/pkg/util/docker/docker_test.go
@@ -0,0 +1,144 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package docker
+
+import (
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/apache/camel-k/v2/pkg/util"
+	"github.com/apache/camel-k/v2/pkg/util/defaults"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCreateBaseImageDockerFile(t *testing.T) {
+
+	dockerfileExists, _ := util.FileExists("/tmp/Dockerfile")
+	if dockerfileExists {
+		os.Remove("/tmp/Dockerfile")
+	}
+
+	dockerFile := []string{}
+	dockerFile = append(dockerFile, FROM(defaults.BaseImage()))
+	dockerFile = append(dockerFile, RUNMavenInstall())
+	expected := strings.Join(dockerFile, "\n")
+
+	BaseWorkingDirectory = "/tmp/"
+
+	err := CreateBaseImageDockerFile()
+	assert.Nil(t, err)
+	baseDockerFilePath := filepath.Join(BaseWorkingDirectory, "Dockerfile")
+
+	c, err := util.ReadFile(baseDockerFilePath)
+
+	assert.Nil(t, err)
+	assert.Equal(t, expected, string(c))
+
+	os.Remove("/tmp/Dockerfile")
+}
+
+func TestCreateIntegrationImageDockerFile(t *testing.T) {
+	dockerfileExists, _ := util.FileExists("/tmp/Dockerfile")
+	if dockerfileExists {
+		os.Remove("/tmp/Dockerfile")
+	}
+	IntegrationWorkingDirectory = "/tmp/"
+	var cmd exec.Cmd
+	cmd.Path = "test"
+	cmd.Env = []string{"key=value"}
+	cmd.Args = []string{"-t"}
+	dockerFile1 := []string{}
+	dockerFile1 = append(dockerFile1, FROM(GetFullDockerImage(GetBaseImagePath(), latestTag)))
+	dockerFile1 = append(dockerFile1, RUNMakeDir(GetContainerWorkspaceDir()))
+	dockerFile1 = append(dockerFile1, COPY(util.DefaultRoutesDirectoryName, GetContainerRoutesDir()))
+	dockerFile1 = append(dockerFile1, COPY(util.DefaultPropertiesDirectoryName, GetContainerPropertiesDir()))
+	dockerFile1 = append(dockerFile1, COPY(util.DefaultDependenciesDirectoryName, GetContainerDependenciesDir()))
+
+	dockerFile2 := dockerFile1
+	dockerFile2 = append(dockerFile2, RUNMakeDir(util.ContainerQuarkusDirectoryName))
+	dockerFile2 = append(dockerFile2, RUNMakeDir(util.ContainerLibDirectoryName))
+	dockerFile2 = append(dockerFile2, RUNMakeDir(util.ContainerAppDirectoryName))
+	dockerFile2 = append(dockerFile2, COPY(util.CustomQuarkusDirectoryName, util.ContainerQuarkusDirectoryName))
+	dockerFile2 = append(dockerFile2, COPY(util.CustomLibDirectoryName, util.ContainerLibDirectoryName))
+	dockerFile2 = append(dockerFile2, COPY(util.CustomAppDirectoryName, util.ContainerAppDirectoryName))
+
+	for _, keyValue := range cmd.Env {
+		values := strings.Split(keyValue, "=")
+		dockerFile1 = append(dockerFile1, ENV(values[0], strings.Join(values[1:], "=")))
+		dockerFile2 = append(dockerFile2, ENV(values[0], strings.Join(values[1:], "=")))
+	}
+	dockerFile1 = append(dockerFile1, CMDShellWrap(strings.Join(cmd.Args, " ")))
+	dockerFile2 = append(dockerFile2, CMDShellWrap(strings.Join(cmd.Args, " ")))
+
+	expected := strings.Join(dockerFile1, "\n")
+
+	err := CreateIntegrationImageDockerFile(&cmd, false)
+	assert.Nil(t, err)
+
+	c, err := util.ReadFile("/tmp/Dockerfile")
+	assert.Nil(t, err)
+	assert.Equal(t, expected, string(c))
+
+	os.Remove("/tmp/Dockerfile")
+
+	expected = strings.Join(dockerFile2, "\n")
+
+	err = CreateIntegrationImageDockerFile(&cmd, true)
+	assert.Nil(t, err)
+
+	c, err = util.ReadFile("/tmp/Dockerfile")
+	assert.Nil(t, err)
+	assert.Equal(t, expected, string(c))
+
+	os.Remove("/tmp/Dockerfile")
+
+}
+
+func TestContainerizeFilePaths(t *testing.T) {
+	expected := []string{"home/quarkus-app"}
+
+	dependencyPaths := []string{"test1/quarkus-app"}
+	newDir := "home"
+	result := ContainerizeFilePaths(dependencyPaths, newDir)
+
+	assert.Equal(t, expected, result)
+}
+
+func TestContainerizeDependencyPaths(t *testing.T) {
+	expected := []string{"home/quarkus-app", "home/not-quarkus-app"}
+
+	dependencyPaths := []string{"test1/quarkus-app", "not-quarkus-app"}
+	newDir := "home"
+	result := ContainerizeDependencyPaths(dependencyPaths, newDir)
+
+	assert.Equal(t, expected, result)
+}
+
+func TestExtractRegistryName(t *testing.T) {
+	expected := "localhost:5000"
+
+	result, err := ExtractRegistryName("localhost:5000/imageName")
+	assert.Nil(t, err)
+	assert.Equal(t, expected, result)
+
+	_, err = ExtractRegistryName("imageName")
+	assert.NotNil(t, err)
+}
diff --git a/pkg/util/gzip/compress_test.go b/pkg/util/gzip/compress_test.go
index 97cc19580..2ea281b4c 100644
--- a/pkg/util/gzip/compress_test.go
+++ b/pkg/util/gzip/compress_test.go
@@ -18,12 +18,24 @@ limitations under the License.
 package gzip
 
 import (
+	"bytes"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
 func TestCompression(t *testing.T) {
+	source := "this is a script"
+	var compressed bytes.Buffer
+	err := Compress(&compressed, []byte(source))
+	assert.Nil(t, err)
+	var uncompressed bytes.Buffer
+	err = Uncompress(&uncompressed, compressed.Bytes())
+	assert.Nil(t, err)
+	assert.Equal(t, source, uncompressed.String())
+}
+
+func TestCompression64(t *testing.T) {
 	source := "this is a script"
 	compressed, err := CompressBase64([]byte(source))
 	assert.Nil(t, err)
diff --git a/pkg/util/jvm/keystore_test.go b/pkg/util/jvm/keystore_test.go
new file mode 100644
index 000000000..3859d79bc
--- /dev/null
+++ b/pkg/util/jvm/keystore_test.go
@@ -0,0 +1,43 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package jvm
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGenerateKeystore(t *testing.T) {
+
+	// No Data
+	var data [][]byte
+	ctx := context.Background()
+	err := GenerateKeystore(ctx, "", "name", NewKeystorePassword(), data)
+	assert.Nil(t, err)
+
+	// Correct input
+	data = [][]byte{{0}, {1}}
+	err = GenerateKeystore(ctx, "", "name", NewKeystorePassword(), data)
+	assert.NotNil(t, err)
+
+	// Incorrect input format
+	err = GenerateKeystore(ctx, "", "name", "", data)
+	assert.NotNil(t, err)
+}