Skip to content

Commit 84bd69f

Browse files
rina23qclaude
andcommitted
test: cover the service commands from Cumulocity
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Rina Fujino <rina.fujino.23@gmail.com>
1 parent c88ae4f commit 84bd69f

8 files changed

Lines changed: 266 additions & 64 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/sh
2+
# Test service plugin for the "container-test" service type.
3+
#
4+
# It runs nothing: it records the arguments `tedge service` passed it, so the test can check
5+
# what the runner and the workflow resolved, and it returns the exit code the test expects for
6+
# each action.
7+
#
8+
# Exit codes:
9+
# 0 the action succeeded
10+
# 2 the action is not supported by this plugin
11+
set -u
12+
13+
ACTION="${1:-}"
14+
NAME="${2:-}"
15+
16+
echo "$ACTION $NAME" >>/tmp/container-test-plugin.log
17+
18+
case "$ACTION" in
19+
restart | freeze)
20+
echo "container-test plugin: $ACTION $NAME"
21+
;;
22+
*)
23+
echo "container-test plugin: unsupported action '$ACTION'" >&2
24+
exit 2
25+
;;
26+
esac
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[Unit]
2+
Description=A service the service command tests can start, stop and restart
3+
4+
[Service]
5+
Type=exec
6+
ExecStart=/bin/sleep infinity
7+
Restart=no
8+
9+
[Install]
10+
WantedBy=multi-user.target
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
*** Settings ***
2+
Resource ../../../resources/common.resource
3+
Library Cumulocity
4+
Library ThinEdgeIO
5+
6+
Suite Setup Custom Setup
7+
Test Teardown Get Logs
8+
9+
Test Tags theme:c8y theme:services theme:operation
10+
11+
12+
*** Variables ***
13+
${DEVICE_SN} ${EMPTY}
14+
${SERVICE_NAME} dummy-service
15+
${SERVICE_XID} ${EMPTY}
16+
${AGENT_XID} ${EMPTY}
17+
${MAPPER_XID} ${EMPTY}
18+
19+
20+
*** Test Cases ***
21+
Declares and clears an action of a service
22+
Execute Command tedge mqtt pub -q 1 --retain te/device/main/service/${SERVICE_NAME}/cmd/pause '{}'
23+
Supported Service Commands Should Be ${SERVICE_XID} PAUSE RESTART
24+
Cumulocity.Should Contain Supported Operations c8y_ServiceCommand
25+
26+
Execute Command tedge mqtt pub -q 1 --retain te/device/main/service/${SERVICE_NAME}/cmd/pause ''
27+
Supported Service Commands Should Be ${SERVICE_XID} RESTART
28+
29+
Declares the action of thin-edge's own services
30+
Supported Service Commands Should Be ${AGENT_XID} RESTART
31+
Cumulocity.Should Contain Supported Operations c8y_ServiceCommand
32+
33+
Supported Service Commands Should Be ${MAPPER_XID} RESTART
34+
Cumulocity.Should Contain Supported Operations c8y_ServiceCommand
35+
36+
Restarts a service managed by the init system
37+
${before}= Get Service PID ${SERVICE_NAME}
38+
${operation}= Create Service Command Operation
39+
... ${SERVICE_XID}
40+
... {"command":"RESTART","serviceName":"${SERVICE_NAME}","serviceType":"service"}
41+
Cumulocity.Operation Should Be SUCCESSFUL ${operation} timeout=120
42+
43+
${after}= Get Service PID ${SERVICE_NAME}
44+
Should Not Be Equal ${before} ${after} The service was not restarted
45+
46+
Rejects an action the service has not declared
47+
${operation}= Create Service Command Operation
48+
... ${SERVICE_XID}
49+
... {"command":"COLLECT_MEASUREMENTS","serviceName":"${SERVICE_NAME}","serviceType":"service"}
50+
Cumulocity.Operation Should Be FAILED
51+
... ${operation}
52+
... failure_reason=.*has not declared the 'collect_measurements' action.*
53+
... timeout=60
54+
55+
Restarts tedge-agent itself
56+
${before}= Get Service PID tedge-agent
57+
58+
${operation}= Create Service Command Operation
59+
... ${AGENT_XID}
60+
... {"command":"RESTART","serviceName":"tedge-agent","serviceType":"service"}
61+
Cumulocity.Operation Should Be SUCCESSFUL ${operation} timeout=180
62+
63+
ThinEdgeIO.Service Health Status Should Be Up tedge-agent
64+
${after}= Get Service PID tedge-agent
65+
Should Not Be Equal ${before} ${after} tedge-agent was not restarted
66+
67+
68+
*** Keywords ***
69+
Custom Setup
70+
${sn}= Setup
71+
Set Suite Variable $DEVICE_SN ${sn}
72+
Set Suite Variable $SERVICE_XID ${sn}:device:main:service:${SERVICE_NAME}
73+
Set Suite Variable $AGENT_XID ${sn}:device:main:service:tedge-agent
74+
Set Suite Variable $MAPPER_XID ${sn}:device:main:service:tedge-mapper-c8y
75+
Cumulocity.External Identity Should Exist ${sn} show_info=${False}
76+
77+
# The service is registered under its systemd unit name.
78+
# Cumulocity sends this name back in the operation, and the workflow passes it to systemctl.
79+
ThinEdgeIO.Transfer To Device ${CURDIR}/dummy-service.service /etc/systemd/system/
80+
Execute Command systemctl daemon-reload && systemctl start ${SERVICE_NAME}
81+
82+
Execute Command
83+
... tedge mqtt pub --retain te/device/main/service/${SERVICE_NAME} '{"name":"${SERVICE_NAME}","@type":"service"}'
84+
Cumulocity.External Identity Should Exist ${SERVICE_XID} show_info=${False}
85+
Execute Command tedge mqtt pub -q 1 --retain te/device/main/service/${SERVICE_NAME}/cmd/restart '{}'
86+
87+
Supported Service Commands Should Be
88+
[Arguments] ${external_id} @{expected}
89+
Cumulocity.External Identity Should Exist ${external_id} show_info=${False}
90+
Wait Until Keyword Succeeds 30x 2s Managed Object Service Commands Should Be @{expected}
91+
92+
Managed Object Service Commands Should Be
93+
[Arguments] @{expected}
94+
${mo}= Cumulocity.Managed Object Should Have Fragments c8y_SupportedServiceCommands
95+
${actual}= Evaluate sorted($mo["c8y_SupportedServiceCommands"])
96+
${wanted}= Evaluate sorted($expected)
97+
Should Be Equal ${actual} ${wanted}
98+
99+
Create Service Command Operation
100+
[Arguments] ${external_id} ${fragment}
101+
Cumulocity.External Identity Should Exist ${external_id} show_info=${False}
102+
${operation}= Cumulocity.Create Operation
103+
... fragments={"c8y_ServiceCommand":${fragment}}
104+
... description=Service command
105+
RETURN ${operation}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
operation = "freeze"
2+
type = "service"
3+
4+
[init]
5+
action = "proceed"
6+
on_success = "executing"
7+
8+
[executing]
9+
action = "proceed"
10+
on_success = "execute"
11+
12+
[execute]
13+
script = "sudo -n tedge service ${.topic.operation} ${.payload.serviceName} --type ${.payload.serviceType}"
14+
timeout_second = 180
15+
on_exit.0 = "successful"
16+
on_exit.1 = { status = "failed", reason = "The action failed, see the operation log for the reason" }
17+
on_exit.2 = { status = "failed", reason = "This action is not supported for that type of service" }
18+
on_exit.3-255 = { status = "failed", reason = "The action failed, see the operation log for the reason" }
19+
on_kill = { status = "failed", reason = "The action did not complete in time and was cancelled" }
20+
21+
[successful]
22+
action = "cleanup"
23+
24+
[failed]
25+
action = "cleanup"
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
*** Settings ***
2+
Resource ../../../resources/common.resource
3+
Library Cumulocity
4+
Library ThinEdgeIO
5+
6+
Suite Setup Custom Setup
7+
Test Setup Execute Command rm -f ${PLUGIN_LOG}
8+
Test Teardown Get Logs
9+
10+
Test Tags theme:c8y theme:services theme:plugins
11+
12+
13+
*** Variables ***
14+
${DEVICE_SN} ${EMPTY}
15+
${SERVICE_NAME} nodered
16+
${SERVICE_TYPE} container-test
17+
${SERVICE_XID} ${EMPTY}
18+
${PLUGIN_DIR} /usr/share/tedge/service-plugins
19+
${PLUGIN_LOG} /tmp/container-test-plugin.log
20+
21+
22+
*** Test Cases ***
23+
Runs the shipped restart workflow through the plugin of the service type
24+
${operation}= Create Service Command Operation
25+
... {"command":"RESTART","serviceName":"${SERVICE_NAME}","serviceType":"${SERVICE_TYPE}"}
26+
Cumulocity.Operation Should Be SUCCESSFUL ${operation} timeout=120
27+
Plugin Should Have Been Called With restart ${SERVICE_NAME}
28+
29+
Runs a custom freeze workflow through the plugin of the service type
30+
${operation}= Create Service Command Operation
31+
... {"command":"FREEZE","serviceName":"${SERVICE_NAME}","serviceType":"${SERVICE_TYPE}"}
32+
Cumulocity.Operation Should Be SUCCESSFUL ${operation} timeout=120
33+
Plugin Should Have Been Called With freeze ${SERVICE_NAME}
34+
35+
Takes the service name from the operation
36+
${operation}= Create Service Command Operation
37+
... {"command":"RESTART","serviceName":"Node-RED","serviceType":"${SERVICE_TYPE}"}
38+
Cumulocity.Operation Should Be SUCCESSFUL ${operation} timeout=120
39+
40+
${operation_id}= Set Variable ${operation.to_json()["id"]}
41+
Should Have MQTT Messages
42+
... te/device/main/service/${SERVICE_NAME}/cmd/restart/c8y-mapper-${operation_id}
43+
... message_contains="serviceName":"Node-RED"
44+
Plugin Should Have Been Called With restart Node-RED
45+
46+
Takes the service name and type from the registered entity when the operation gives none
47+
${operation}= Create Service Command Operation
48+
... {"command":"RESTART"}
49+
Cumulocity.Operation Should Be SUCCESSFUL ${operation} timeout=120
50+
51+
${operation_id}= Set Variable ${operation.to_json()["id"]}
52+
Should Have MQTT Messages
53+
... te/device/main/service/${SERVICE_NAME}/cmd/restart/c8y-mapper-${operation_id}
54+
... message_contains="serviceType":"${SERVICE_TYPE}"
55+
Plugin Should Have Been Called With restart ${SERVICE_NAME}
56+
57+
58+
*** Keywords ***
59+
Custom Setup
60+
${sn}= Setup
61+
Set Suite Variable $DEVICE_SN ${sn}
62+
Set Suite Variable $SERVICE_XID ${sn}:device:main:service:${SERVICE_NAME}
63+
Cumulocity.External Identity Should Exist ${sn} show_info=${False}
64+
65+
# PLUGIN_DIR must be created by the package
66+
Execute Command test -d ${PLUGIN_DIR}
67+
ThinEdgeIO.Transfer To Device ${CURDIR}/${SERVICE_TYPE} ${PLUGIN_DIR}/
68+
Execute Command chown root:root ${PLUGIN_DIR}/${SERVICE_TYPE} && chmod 755 ${PLUGIN_DIR}/${SERVICE_TYPE}
69+
70+
ThinEdgeIO.Transfer To Device ${CURDIR}/service_freeze.toml /etc/tedge/operations/
71+
72+
Execute Command
73+
... tedge mqtt pub --retain te/device/main/service/${SERVICE_NAME} '{"@type":"service","name":"${SERVICE_NAME}","type":"${SERVICE_TYPE}"}'
74+
Cumulocity.External Identity Should Exist ${SERVICE_XID} show_info=${False}
75+
76+
Execute Command tedge mqtt pub -q 1 --retain te/device/main/service/${SERVICE_NAME}/cmd/restart '{}'
77+
Execute Command tedge mqtt pub -q 1 --retain te/device/main/service/${SERVICE_NAME}/cmd/freeze '{}'
78+
79+
Create Service Command Operation
80+
[Arguments] ${fragment}
81+
Cumulocity.External Identity Should Exist ${SERVICE_XID} show_info=${False}
82+
${operation}= Cumulocity.Create Operation
83+
... fragments={"c8y_ServiceCommand":${fragment}}
84+
... description=Service command
85+
RETURN ${operation}
86+
87+
Plugin Should Have Been Called With
88+
[Arguments] ${arguments}
89+
${calls}= Execute Command cat ${PLUGIN_LOG} strip=${True}
90+
Should Be Equal ${calls} ${arguments}

‎tests/RobotFramework/tests/cumulocity/supported_operations/mapper-publishing-agent-supported-ops.robot‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,19 @@ Agent gets the software list request once it comes up
6060
Re-publish supported operations by signal channel
6161
Execute Command tedge mqtt pub -r te/device/child01// '{"@type": "child-device"}'
6262
Execute Command tedge mqtt pub -r te/device/child01///cmd/restart '{}'
63+
Execute Command tedge mqtt pub -r te/device/child01/service/foo '{"@type": "service"}'
64+
Execute Command tedge mqtt pub -r te/device/child01/service/foo/cmd/restart '{}'
6365

6466
Execute Command tedge mqtt pub te/device/main/service/tedge-mapper-c8y/signal/sync '{}'
6567
Should Have MQTT Messages
6668
... c8y/s/us
6769
... message_contains=114,c8y_Command,c8y_DeviceProfile,c8y_DownloadConfigFile,c8y_LogfileRequest,c8y_RemoteAccessConnect,c8y_Restart,c8y_SoftwareUpdate,c8y_UploadConfigFile
6870
Should Have MQTT Messages c8y/s/us/${DEVICE_SN}:device:child01 message_contains=114,c8y_Restart
71+
# On a service, a `cmd/<action>` capability is an action of that service, so the operation
72+
# registered for it is `c8y_ServiceCommand`, whatever the action.
73+
Should Have MQTT Messages
74+
... c8y/s/us/${DEVICE_SN}:device:child01:service:foo
75+
... message_contains=114,c8y_ServiceCommand
6976

7077

7178
*** Keywords ***

‎tests/RobotFramework/tests/cumulocity/supported_operations/service-supported-ops.robot‎

Lines changed: 0 additions & 64 deletions
This file was deleted.

‎tests/RobotFramework/tests/tedge/service/tedge_service.robot‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Run tedge service for service plugin
3434
# Unsupported action should return exit code 2
3535
Execute Command tedge service invalid name --type dummy exp_exit_code=2
3636

37+
Run tedge service for a service type with no plugin
38+
Execute Command tedge service restart name --type no_such_backend exp_exit_code=2
39+
3740
tedge service does not support name and is_available
3841
${stderr}= Execute Command
3942
... tedge service name sleeper strip=True exp_exit_code=2 stdout=False stderr=True

0 commit comments

Comments
 (0)