diff --git a/qa/integration/src/test/java/org/eclipse/kapua/integration/service/jobEngine/RunJobEngineServiceI9nTest.java b/qa/integration/src/test/java/org/eclipse/kapua/integration/service/jobEngine/RunJobEngineServiceI9nTest.java
index 408d12e1cee..fa4758d8275 100644
--- a/qa/integration/src/test/java/org/eclipse/kapua/integration/service/jobEngine/RunJobEngineServiceI9nTest.java
+++ b/qa/integration/src/test/java/org/eclipse/kapua/integration/service/jobEngine/RunJobEngineServiceI9nTest.java
@@ -25,6 +25,7 @@
"classpath:features/jobEngine/JobEngineServiceProcessorCommandI9n.feature",
"classpath:features/jobEngine/JobEngineServiceProcessorConfigurationI9n.feature",
"classpath:features/jobEngine/JobEngineServiceProcessorKeystoreI9n.feature",
+ "classpath:features/jobEngine/JobEngineServiceProcessorPackagesI9n.feature",
},
glue = {
"org.eclipse.kapua.service.job.steps",
diff --git a/qa/integration/src/test/resources/features/jobEngine/JobEngineServiceProcessorPackagesI9n.feature b/qa/integration/src/test/resources/features/jobEngine/JobEngineServiceProcessorPackagesI9n.feature
new file mode 100644
index 00000000000..5e1cb019314
--- /dev/null
+++ b/qa/integration/src/test/resources/features/jobEngine/JobEngineServiceProcessorPackagesI9n.feature
@@ -0,0 +1,137 @@
+###############################################################################
+# Copyright (c) 2024, 2024 Eurotech and/or its affiliates and others
+#
+# This program and the accompanying materials are made
+# available under the terms of the Eclipse Public License 2.0
+# which is available at https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# Eurotech - initial API and implementation
+###############################################################################
+@env_docker
+@it
+@jobEngine
+@jobEngineTargetProcessors
+
+Feature: Job Engine Service - Packages Step Processors
+ Tests for Device Management Packages Processor
+
+ @setup
+ Scenario: Setup test resources
+ Given Init Security Context
+ And Start Docker environment with resources
+ | db |
+ | events-broker |
+ | job-engine |
+ | message-broker |
+ | broker-auth-service |
+ | consumer-lifecycle |
+
+ Scenario: Package Install - XML
+
+ Given I login as user with name "kapua-sys" and password "kapua-password"
+ And I start the Kura Mock
+ And Device birth message is sent
+ And Device "rpione3" is connected within 10s
+ And I create a job with the name "TestJob"
+ And I add device targets to job
+ | rpione3 |
+ And I search for step definition with the name
+ | Package Download / Install |
+ And I add job step to job with name "Test Step - Package Download and Install - XML" and with selected job step definition and properties
+ | name | type | value |
+ | packageDownloadRequest | org.eclipse.kapua.service.device.management.packages.model.download.DevicePackageDownloadRequest | http://download.eclipse.org/kura/releases/3.2.0/org.eclipse.kura.demo.heater_1.0.300.dpheater1.0.300true |
+ | timeout | java.lang.Long | 5000 |
+ When I start a job
+ And I wait job to finish its execution up to 5s
+ Then I confirm that job has 1 job execution
+ And I confirm that job target in job has step index 0 and status "AWAITING_COMPLETION"
+ Then I wait job target to finish processing and notify completion up to 10s
+ And I wait for another job start up to 10s
+ And I wait job to finish its execution up to 5s
+ And I confirm that job has 2 job execution
+ And I confirm that job target in job has step index 0 and status "PROCESS_OK"
+
+ Scenario: Package Install - JSON
+
+ Given I login as user with name "kapua-sys" and password "kapua-password"
+ And I start the Kura Mock
+ And Device birth message is sent
+ And Device "rpione3" is connected within 10s
+ And I create a job with the name "TestJob"
+ And I add device targets to job
+ | rpione3 |
+ And I search for step definition with the name
+ | Package Download / Install |
+ And I add job step to job with name "Test Step - Package Download and Install - JSON" and with selected job step definition and properties
+ | name | type | value |
+ | packageDownloadRequest | org.eclipse.kapua.service.device.management.packages.model.download.DevicePackageDownloadRequest | { "uri": "http://download.eclipse.org/kura/releases/3.2.0/org.eclipse.kura.demo.heater_1.0.300.dp", "name": "heater", "version": "1.0.300", "install": true } |
+ | timeout | java.lang.Long | 5000 |
+ When I start a job
+ And I wait job to finish its execution up to 5s
+ Then I confirm that job has 1 job execution
+ And I confirm that job target in job has step index 0 and status "AWAITING_COMPLETION"
+ Then I wait job target to finish processing and notify completion up to 10s
+ And I wait for another job start up to 10s
+ And I wait job to finish its execution up to 5s
+ And I confirm that job has 2 job execution
+ And I confirm that job target in job has step index 0 and status "PROCESS_OK"
+
+ Scenario: Package Uninstall - XML
+
+ Given I login as user with name "kapua-sys" and password "kapua-password"
+ And I start the Kura Mock
+ And Device birth message is sent
+ And Device "rpione3" is connected within 10s
+ And I create a job with the name "TestJob"
+ And I add device targets to job
+ | rpione3 |
+ And I search for step definition with the name
+ | Package Uninstall |
+ And I add job step to job with name "Test Step - Package Uninstall - XML" and with selected job step definition and properties
+ | name | type | value |
+ | packageUninstallRequest | org.eclipse.kapua.service.device.management.packages.model.uninstall.DevicePackageUninstallRequest | heater1.0.300false30000 |
+ | timeout | java.lang.Long | 5000 |
+ When I start a job
+ And I wait job to finish its execution up to 5s
+ Then I confirm that job has 1 job execution
+ And I confirm that job target in job has step index 0 and status "AWAITING_COMPLETION"
+ Then I wait job target to finish processing and notify completion up to 10s
+ And I wait for another job start up to 10s
+ And I wait job to finish its execution up to 5s
+ And I confirm that job has 2 job execution
+ And I confirm that job target in job has step index 0 and status "PROCESS_OK"
+
+ Scenario: Package Uninstall - JSON
+
+ Given I login as user with name "kapua-sys" and password "kapua-password"
+ And I start the Kura Mock
+ And Device birth message is sent
+ And Device "rpione3" is connected within 10s
+ And I create a job with the name "TestJob"
+ And I add device targets to job
+ | rpione3 |
+ And I search for step definition with the name
+ | Package Uninstall |
+ And I add job step to job with name "Test Step - Package Uninstall - JSON" and with selected job step definition and properties
+ | name | type | value |
+ | packageUninstallRequest | org.eclipse.kapua.service.device.management.packages.model.uninstall.DevicePackageUninstallRequest | { "name": "org.eclipse.kura.demo.heater", "version": "1.0.500", "reboot": false, "rebootDelay": 30000 } |
+ | timeout | java.lang.Long | 5000 |
+ When I start a job
+ And I wait job to finish its execution up to 5s
+ Then I confirm that job has 1 job execution
+ And I confirm that job target in job has step index 0 and status "AWAITING_COMPLETION"
+ Then I wait job target to finish processing and notify completion up to 10s
+ And I wait for another job start up to 10s
+ And I wait job to finish its execution up to 5s
+ And I confirm that job has 2 job execution
+ And I confirm that job target in job has step index 0 and status "PROCESS_OK"
+
+ @teardown
+ Scenario: Tear down test resources
+ Given I logout
+ And KuraMock is disconnected
+ And Stop Docker environment
+ And Clean Locator Instance
\ No newline at end of file
diff --git a/service/device/registry/test-steps/src/main/java/org/eclipse/kapua/service/device/registry/steps/KuraDevice.java b/service/device/registry/test-steps/src/main/java/org/eclipse/kapua/service/device/registry/steps/KuraDevice.java
index 9c30988b186..65076a8f0d3 100644
--- a/service/device/registry/test-steps/src/main/java/org/eclipse/kapua/service/device/registry/steps/KuraDevice.java
+++ b/service/device/registry/test-steps/src/main/java/org/eclipse/kapua/service/device/registry/steps/KuraDevice.java
@@ -453,79 +453,106 @@ else if (topic.equals(deployGetPackages)) {
mqttClient.publish(responseTopic, responsePayload, 0, false);
} else if (topic.equals(deployExecDownload)) {
callbackParam = extractCallback(requestPayload);
- KuraPayload kuraPayloadInitial = new KuraPayload();
- kuraPayloadInitial.readFromByteArray(requestPayload);
+ KuraPayload kuraRequestPayload = new KuraPayload();
+ kuraRequestPayload.readFromByteArray(requestPayload);
+
+ // Reply
responseTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_REPLY + callbackParam.getRequestId();
- KuraPayload customKuraPayload1 = new KuraPayload();
- customKuraPayload1.setTimestamp(new Date());
- customKuraPayload1.getMetrics().put("response.code", 200);
- responsePayload = customKuraPayload1.toByteArray();
- mqttClient.publish(responseTopic, responsePayload, 0, false);
- Thread.sleep(100);
-
- responseTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_NOTIFY + clientId + "/download";
- KuraPayload customKuraPayload2 = new KuraPayload();
- customKuraPayload2.setTimestamp(new Date());
- customKuraPayload2.getMetrics().put(JOB_ID, kuraPayloadInitial.getMetrics().get(JOB_ID));
- customKuraPayload2.getMetrics().put(CLIENT_ID, clientId);
- customKuraPayload2.getMetrics().put("dp.download.progress", 50);
- customKuraPayload2.getMetrics().put("dp.download.size", 20409);
- customKuraPayload2.getMetrics().put("dp.download.status", "IN_PROGRESS");
- customKuraPayload2.getMetrics().put("dp.download.index", 0);
- responsePayload = customKuraPayload2.toByteArray();
- mqttClient.publish(responseTopic, responsePayload, 0, false);
- Thread.sleep(100);
-
- responseTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_NOTIFY + clientId + "/download";
- KuraPayload customKuraPayload3 = new KuraPayload();
- customKuraPayload3.setTimestamp(new Date());
- customKuraPayload3.getMetrics().put(JOB_ID, kuraPayloadInitial.getMetrics().get(JOB_ID));
- customKuraPayload3.getMetrics().put(CLIENT_ID, clientId);
- customKuraPayload3.getMetrics().put("dp.download.progress", 100);
- customKuraPayload3.getMetrics().put("dp.download.size", 20409);
- customKuraPayload3.getMetrics().put("dp.download.status", COMPLETED);
- customKuraPayload3.getMetrics().put("dp.download.index", 0);
- responsePayload = customKuraPayload3.toByteArray();
- mqttClient.publish(responseTopic, responsePayload, 0, false);
- Thread.sleep(100);
-
- responseTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_NOTIFY + clientId + "/install";
- KuraPayload customKuraPayload4 = new KuraPayload();
- customKuraPayload4.setTimestamp(new Date());
- customKuraPayload4.getMetrics().put("dp.name", "Example Publisher-1.0.300.dp");
- customKuraPayload4.getMetrics().put(JOB_ID, kuraPayloadInitial.getMetrics().get(JOB_ID));
- customKuraPayload4.getMetrics().put("dp.install.progress", 100);
- customKuraPayload4.getMetrics().put("dp.install.status", COMPLETED);
- customKuraPayload4.getMetrics().put(CLIENT_ID, clientId);
- responsePayload = customKuraPayload4.toByteArray();
+
+ KuraPayload replyKuraResponsePayload = new KuraPayload();
+ replyKuraResponsePayload.setTimestamp(new Date());
+ replyKuraResponsePayload.getMetrics().put("response.code", 200);
+ responsePayload = replyKuraResponsePayload.toByteArray();
+
mqttClient.publish(responseTopic, responsePayload, 0, false);
+ Thread.sleep(1000);
+
+ // Download Notification 25%
+ String downloadNotifyTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_NOTIFY + clientId + "/download";
+
+ KuraPayload downloadNotifyPayload = new KuraPayload();
+ downloadNotifyPayload.setTimestamp(new Date());
+ downloadNotifyPayload.getMetrics().put(CLIENT_ID, clientId);
+ downloadNotifyPayload.getMetrics().put(JOB_ID, kuraRequestPayload.getMetrics().get(JOB_ID));
+ downloadNotifyPayload.getMetrics().put("dp.download.progress", 25);
+ downloadNotifyPayload.getMetrics().put("dp.download.size", 20409);
+ downloadNotifyPayload.getMetrics().put("dp.download.status", "IN_PROGRESS");
+ downloadNotifyPayload.getMetrics().put("dp.download.index", 0);
+ responsePayload = downloadNotifyPayload.toByteArray();
+
+ mqttClient.publish(downloadNotifyTopic, responsePayload, 0, false);
+ Thread.sleep(1000);
+
+ // Download Notification 50%
+ downloadNotifyPayload.setTimestamp(new Date());
+ downloadNotifyPayload.getMetrics().put("dp.download.progress", 50);
+ responsePayload = downloadNotifyPayload.toByteArray();
+
+ mqttClient.publish(downloadNotifyTopic, responsePayload, 0, false);
+ Thread.sleep(1000);
+
+ // Download Notification 75%
+ downloadNotifyPayload.setTimestamp(new Date());
+ downloadNotifyPayload.getMetrics().put("dp.download.progress", 75);
+ responsePayload = downloadNotifyPayload.toByteArray();
+
+ mqttClient.publish(downloadNotifyTopic, responsePayload, 0, false);
+ Thread.sleep(1000);
+
+ // Download Notification 100%
+ downloadNotifyPayload.setTimestamp(new Date());
+ downloadNotifyPayload.getMetrics().put("dp.download.progress", 100);
+ downloadNotifyPayload.getMetrics().put("dp.download.status", COMPLETED);
+ responsePayload = downloadNotifyPayload.toByteArray();
+
+ mqttClient.publish(downloadNotifyTopic, responsePayload, 0, false);
+ Thread.sleep(1000);
+
+ // Install Notification 100%
+ String installNotifyTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_NOTIFY + clientId + "/install";
+
+ KuraPayload installNotifyPayload = new KuraPayload();
+ installNotifyPayload.setTimestamp(new Date());
+ installNotifyPayload.getMetrics().put(CLIENT_ID, clientId);
+ installNotifyPayload.getMetrics().put(JOB_ID, kuraRequestPayload.getMetrics().get(JOB_ID));
+ installNotifyPayload.getMetrics().put("dp.name", "heater-1.0.300.dp");
+ installNotifyPayload.getMetrics().put("dp.install.progress", 100);
+ installNotifyPayload.getMetrics().put("dp.install.status", COMPLETED);
+ responsePayload = installNotifyPayload.toByteArray();
+
+ mqttClient.publish(installNotifyTopic, responsePayload, 0, false);
packageListChanged = true;
} else if (topic.equals(deployExecUninstall)) {
callbackParam = extractCallback(requestPayload);
- KuraPayload kuraPayloadInitial = new KuraPayload();
- kuraPayloadInitial.readFromByteArray(requestPayload);
+ KuraPayload kuraRequestPayload = new KuraPayload();
+ kuraRequestPayload.readFromByteArray(requestPayload);
+
+ // Reply topic
responseTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_REPLY + callbackParam.getRequestId();
- KuraPayload customKuraPayload = new KuraPayload();
- customKuraPayload.setTimestamp(new Date());
- customKuraPayload.getMetrics().put("response.code", 200);
- responsePayload = customKuraPayload.toByteArray();
+ KuraPayload replyResponsePayload = new KuraPayload();
+ replyResponsePayload.setTimestamp(new Date());
+ replyResponsePayload.getMetrics().put("response.code", 200);
+ responsePayload = replyResponsePayload.toByteArray();
+
mqttClient.publish(responseTopic, responsePayload, 0, false);
- Thread.sleep(5000);
+ Thread.sleep(3000);
+ // Uninstall notification 100%
responseTopic = $EDC + CLIENT_ACCOUNT + "/" + callbackParam.getClientId() + DEPLOY_V2_NOTIFY + clientId + "/uninstall";
- KuraPayload customKuraPayload2 = new KuraPayload();
-
- customKuraPayload2.setTimestamp(new Date());
- customKuraPayload2.getMetrics().put(JOB_ID, kuraPayloadInitial.getMetrics().get(JOB_ID));
- customKuraPayload2.getMetrics().put("dp.name", "org.eclipse.kura.example.beacon");
- customKuraPayload2.getMetrics().put("dp.uninstall.progress", 100);
- customKuraPayload2.getMetrics().put("dp.uninstall.status", COMPLETED);
- customKuraPayload2.getMetrics().put(CLIENT_ID, clientId);
- responsePayload = customKuraPayload2.toByteArray();
+
+ KuraPayload uninstallNotifyPayload = new KuraPayload();
+ uninstallNotifyPayload.setTimestamp(new Date());
+ uninstallNotifyPayload.getMetrics().put(CLIENT_ID, clientId);
+ uninstallNotifyPayload.getMetrics().put(JOB_ID, kuraRequestPayload.getMetrics().get(JOB_ID));
+ uninstallNotifyPayload.getMetrics().put("dp.name", "org.eclipse.kura.demo.heater");
+ uninstallNotifyPayload.getMetrics().put("dp.uninstall.progress", 100);
+ uninstallNotifyPayload.getMetrics().put("dp.uninstall.status", COMPLETED);
+ responsePayload = uninstallNotifyPayload.toByteArray();
+
mqttClient.publish(responseTopic, responsePayload, 0, false);
packageListChangedAfterUninstall = true;
diff --git a/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobEngineSteps.java b/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobEngineSteps.java
index 17d735bfce0..267b6aed576 100644
--- a/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobEngineSteps.java
+++ b/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobEngineSteps.java
@@ -70,6 +70,32 @@ public void startJob() throws Exception {
// Wait Job Running
+ /**
+ * Waits the {@link Job} in context to start.
+ *
+ * @param waitSeconds The max time to wait
+ * @throws Exception
+ * @since 2.1.0
+ */
+ @And("I wait for another job start up to {int}s")
+ public void waitJobInContextToStart(int waitSeconds) throws Exception {
+ Job job = (Job) stepData.get(JOB);
+
+ long now = System.currentTimeMillis();
+ while ((System.currentTimeMillis() - now) < (waitSeconds * 1000L)) {
+ if (jobEngineService.isRunning(job.getScopeId(), job.getId())) {
+ return;
+ }
+
+ // Check frequently!
+ TimeUnit.MILLISECONDS.sleep(25);
+ }
+
+ Assert.fail("Job " + job.getName() + " did not start an execution within " + waitSeconds + "s");
+ }
+
+ // Wait Job Finish Run
+
/**
* Waits the last {@link Job} in context to finish it execution up the given wait time
*
@@ -117,7 +143,7 @@ private void waitJobUpTo(Job job, int waitSeconds) throws Exception {
TimeUnit.MILLISECONDS.sleep(100);
}
- Assert.fail("Job " + job.getName() + "did not completed its execution within " + waitSeconds + "s");
+ Assert.fail("Job " + job.getName() + " did not completed its execution within " + waitSeconds + "s");
}
// Check Job Running
diff --git a/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobTargetServiceSteps.java b/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobTargetServiceSteps.java
index ea7e630c583..9921b83de09 100644
--- a/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobTargetServiceSteps.java
+++ b/service/job/test-steps/src/main/java/org/eclipse/kapua/service/job/steps/JobTargetServiceSteps.java
@@ -27,6 +27,7 @@
import org.eclipse.kapua.model.id.KapuaId;
import org.eclipse.kapua.model.query.predicate.AttributePredicate;
import org.eclipse.kapua.qa.common.StepData;
+import org.eclipse.kapua.service.device.management.registry.operation.notification.ManagementOperationNotification;
import org.eclipse.kapua.service.device.registry.Device;
import org.eclipse.kapua.service.device.registry.DeviceAttributes;
import org.eclipse.kapua.service.device.registry.DeviceFactory;
@@ -49,11 +50,14 @@
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Singleton
public class JobTargetServiceSteps extends JobServiceTestBase {
+ private final static Logger LOG = LoggerFactory.getLogger(JobTargetServiceSteps.class);
+
private static final String DEVICE = "Device";
private DeviceFactory deviceFactory;
@@ -61,7 +65,6 @@ public class JobTargetServiceSteps extends JobServiceTestBase {
private JobTargetService jobTargetService;
private JobTargetFactory jobTargetFactory;
- final Logger logger = LoggerFactory.getLogger(this.getClass());
@Inject
public JobTargetServiceSteps(StepData stepData) {
@@ -214,7 +217,7 @@ public void findLastJobTarget() throws Exception {
public void checkStepIndexAndStatus(int stepIndex, String status) throws KapuaException {
JobTarget jobTarget = (JobTarget) stepData.get(JOB_TARGET);
JobTarget target = jobTargetService.find(jobTarget.getScopeId(), jobTarget.getId());
- logger.error("step: {}, status: {}", target.getStepIndex(), target.getStatus().name());
+ LOG.error("step: {}, status: {}", target.getStepIndex(), target.getStatus().name());
Assert.assertEquals(stepIndex, target.getStepIndex());
Assert.assertEquals(status, target.getStatus().toString());
}
@@ -448,6 +451,35 @@ private void checkJobTargetForJobHas(JobTarget jobTarget, int expectedStepIndex,
stepData.put(JOB_TARGET, updatedJobTarget);
}
+ /**
+ * Waits the {@link JobTarget} in context to finish its processing and to have {@link JobTarget#getStatus()} set to {@link JobTargetStatus#NOTIFIED_COMPLETION}
+ *
+ * It also takes as a valid {@link JobTarget#getStatus()} {@link JobTargetStatus#PROCESS_OK} because the {@link ManagementOperationNotification} can be processed fast and
+ * {@link JobTarget} can switch from {@link JobTargetStatus#NOTIFIED_COMPLETION} to {@link JobTargetStatus#PROCESS_OK} while waiting for the next check.
+ *
+ * @param waitSeconds The max time to wait
+ * @throws Exception
+ * @since 2.1.0
+ */
+ @Then("I wait job target to finish processing and notify completion up to {int}s")
+ public void waitJobTargetInContextToNotifyCompletion(int waitSeconds) throws Exception {
+ JobTarget jobTarget = (JobTarget) stepData.get(JOB_TARGET);
+
+ long now = System.currentTimeMillis();
+ while ((System.currentTimeMillis() - now) < (waitSeconds * 1000L)) {
+ JobTarget updatedJobTarget = jobTargetService.find(jobTarget.getScopeId(), jobTarget.getId());
+ if (JobTargetStatus.NOTIFIED_COMPLETION.equals(updatedJobTarget.getStatus()) ||
+ // Processing of notification is fast so we accept also PROCESS_OK as a valid status
+ JobTargetStatus.PROCESS_OK.equals(updatedJobTarget.getStatus())) {
+ return;
+ }
+
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+
+ Assert.fail("Job Target" + jobTarget.getId() + " did not notified completion of processing within " + waitSeconds + "s");
+ }
+
//
// Private methods
//