-
Notifications
You must be signed in to change notification settings - Fork 222
Device Advisor CI automation #291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
568d0ff
add github ci to enable device advisor tests
xiazhvera 4dc9d23
rename run script
xiazhvera db97826
clean up run script, remove debug scripts
xiazhvera 6cfbdc1
fix script syntax bug
xiazhvera f74de59
create thing for every test suite
xiazhvera d2ae654
remove logic of delete thing
xiazhvera 76d14b2
1. update test sample time out time. 2.wait for subscribe future result
xiazhvera 29db57b
remove comments
xiazhvera 0ff1069
Merge branch 'main' of https://github.com/aws/aws-iot-device-sdk-pyth…
xiazhvera 8dfa60a
Merge branch 'main' into deviceadvisor_githubci
xiazhvera 814149e
Merge branch 'main' into deviceadvisor_githubci
xiazhvera File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- '*' | ||
- '!main' | ||
|
||
env: | ||
BUILDER_VERSION: v0.8.28 | ||
BUILDER_SOURCE: releases | ||
BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net | ||
PACKAGE_NAME: aws-iot-device-sdk-python-v2 | ||
LINUX_BASE_IMAGE: ubuntu-16-x64 | ||
RUN: ${{ github.run_id }}-${{ github.run_number }} | ||
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | ||
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | ||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_DATEST_ACCESS_KEY_ID }} | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_DATEST_SECRET_ACCESS_KEY }} | ||
AWS_DEFAULT_REGION: us-east-1 | ||
|
||
jobs: | ||
|
||
al2: | ||
runs-on: ubuntu-latest | ||
steps: | ||
# We can't use the `uses: docker://image` version yet, GitHub lacks authentication for actions -> packages | ||
- name: Build ${{ env.PACKAGE_NAME }} | ||
run: | | ||
aws s3 cp s3://aws-crt-test-stuff/ci/${{ env.BUILDER_VERSION }}/linux-container-ci.sh ./linux-container-ci.sh && chmod a+x ./linux-container-ci.sh | ||
./linux-container-ci.sh ${{ env.BUILDER_VERSION }} aws-crt-al2-x64 build -p ${{ env.PACKAGE_NAME }} | ||
|
||
windows: | ||
runs-on: windows-latest | ||
steps: | ||
- name: Build ${{ env.PACKAGE_NAME }} | ||
run: | | ||
python -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder.pyz')" | ||
python builder.pyz build -p ${{ env.PACKAGE_NAME }} | ||
|
||
osx: | ||
runs-on: macos-latest | ||
steps: | ||
- name: Build ${{ env.PACKAGE_NAME }} | ||
run: | | ||
python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" | ||
chmod a+x builder | ||
./builder build -p ${{ env.PACKAGE_NAME }} | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"tests" :["MQTT Connect", "MQTT Publish", "MQTT Subscribe", "Shadow Publish", "Shadow Update"], | ||
"test_suite_ids" : | ||
{ | ||
"MQTT Connect" : "ejbdzmo3hf3v", | ||
"MQTT Publish" : "euw7favf6an4", | ||
"MQTT Subscribe" : "01o8vo6no7sd", | ||
"Shadow Publish" : "elztm2jebc1q", | ||
"Shadow Update" : "vuydgrbbbfce" | ||
}, | ||
"test_exe_path" : | ||
{ | ||
"MQTT Connect" : "mqtt_connect.py", | ||
"MQTT Publish" : "mqtt_publish.py", | ||
"MQTT Subscribe" : "mqtt_subscribe.py", | ||
"Shadow Publish" : "shadow_update.py", | ||
"Shadow Update" : "shadow_update.py" | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
import boto3 | ||
import uuid | ||
import json | ||
import os | ||
import subprocess | ||
from time import sleep | ||
|
||
############################################## | ||
# Cleanup Certificates and Things and created certificate and private key file | ||
def delete_thing_with_certi(thingName, certiId, certiArn): | ||
client.detach_thing_principal( | ||
thingName = thingName, | ||
principal = certiArn) | ||
client.update_certificate( | ||
certificateId =certiId, | ||
newStatus ='INACTIVE') | ||
client.delete_certificate(certificateId = certiId, forceDelete = True) | ||
client.delete_thing(thingName = thingName) | ||
os.remove(os.environ["DA_CERTI"]) | ||
os.remove(os.environ["DA_KEY"]) | ||
|
||
|
||
############################################## | ||
# Initialize variables | ||
# create aws clients | ||
client = boto3.client('iot') | ||
dataClient = boto3.client('iot-data') | ||
deviceAdvisor = boto3.client('iotdeviceadvisor') | ||
|
||
# load test config | ||
f = open('deviceadvisor/script/DATestConfig.json') | ||
DATestConfig = json.load(f) | ||
f.close() | ||
|
||
# create an temporary certificate/key file path | ||
certificate_path = os.path.join(os.getcwd(), 'certificate.pem.crt') | ||
key_path = os.path.join(os.getcwd(), 'private.pem.key') | ||
|
||
# load environment variables requried for testing | ||
shadowProperty = os.environ['DA_SHADOW_PROPERTY'] | ||
shadowDefault = os.environ['DA_SHADOW_VALUE_DEFAULT'] | ||
|
||
# test result | ||
test_result = {} | ||
|
||
############################################## | ||
# create a test thing | ||
thing_name = "DATest_" + str(uuid.uuid4()) | ||
try: | ||
# create_thing_response: | ||
# { | ||
# 'thingName': 'string', | ||
# 'thingArn': 'string', | ||
# 'thingId': 'string' | ||
# } | ||
print("[Device Advisor]Info: Started to create thing...") | ||
create_thing_response = client.create_thing( | ||
thingName=thing_name | ||
) | ||
os.environ["DA_THING_NAME"] = thing_name | ||
|
||
except Exception as e: | ||
print("[Device Advisor]Error: Failed to create thing: " + thing_name) | ||
exit(-1) | ||
|
||
|
||
############################################## | ||
# create certificate and keys used for testing | ||
try: | ||
print("[Device Advisor]Info: Started to create certificate...") | ||
# create_cert_response: | ||
# { | ||
# 'certificateArn': 'string', | ||
# 'certificateId': 'string', | ||
# 'certificatePem': 'string', | ||
# 'keyPair': | ||
# { | ||
# 'PublicKey': 'string', | ||
# 'PrivateKey': 'string' | ||
# } | ||
# } | ||
create_cert_response = client.create_keys_and_certificate( | ||
setAsActive=True | ||
) | ||
# write certificate to file | ||
f = open(certificate_path, "w") | ||
f.write(create_cert_response['certificatePem']) | ||
f.close() | ||
|
||
# write private key to file | ||
f = open(key_path, "w") | ||
f.write(create_cert_response['keyPair']['PrivateKey']) | ||
f.close() | ||
|
||
# setup environment variable | ||
os.environ["DA_CERTI"] = certificate_path | ||
os.environ["DA_KEY"] = key_path | ||
|
||
except: | ||
client.delete_thing(thingName = thing_name) | ||
print("[Device Advisor]Error: Failed to create certificate.") | ||
exit(-1) | ||
|
||
############################################## | ||
# attach certification to thing | ||
try: | ||
print("[Device Advisor]Info: Attach certificate to test thing...") | ||
# attache the certificate to thing | ||
client.attach_thing_principal( | ||
thingName = thing_name, | ||
principal = create_cert_response['certificateArn'] | ||
) | ||
|
||
certificate_arn = create_cert_response['certificateArn'] | ||
certificate_id = create_cert_response['certificateId'] | ||
|
||
except: | ||
delete_thing_with_certi(thing_name, certificate_id ,certificate_arn ) | ||
print("[Device Advisor]Error: Failed to attach certificate.") | ||
exit(-1) | ||
|
||
|
||
############################################## | ||
# Run device advisor | ||
for test_name in DATestConfig['tests']: | ||
try: | ||
###################################### | ||
# set default shadow, for shadow update, if the | ||
# shadow does not exists, update will fail | ||
payload_shadow = json.dumps( | ||
{ | ||
"state": { | ||
"desired": { | ||
shadowProperty: shadowDefault | ||
}, | ||
"reported": { | ||
shadowProperty: shadowDefault | ||
} | ||
} | ||
}) | ||
shadow_response = dataClient.update_thing_shadow( | ||
thingName = thing_name, | ||
payload = payload_shadow) | ||
get_shadow_response = dataClient.get_thing_shadow(thingName = thing_name) | ||
# make sure shadow is created before we go to next step | ||
while(get_shadow_response is None): | ||
get_shadow_response = dataClient.get_thing_shadow(thingName = thing_name) | ||
|
||
# start device advisor test | ||
# test_start_response | ||
# { | ||
# 'suiteRunId': 'string', | ||
# 'suiteRunArn': 'string', | ||
# 'createdAt': datetime(2015, 1, 1) | ||
# } | ||
print("[Device Advisor]Info: Start device advisor test: " + test_name) | ||
test_start_response = deviceAdvisor.start_suite_run( | ||
suiteDefinitionId=DATestConfig['test_suite_ids'][test_name], | ||
suiteRunConfiguration={ | ||
'primaryDevice': { | ||
'thingArn': create_thing_response['thingArn'], | ||
}, | ||
'parallelRun': True | ||
}) | ||
|
||
# get DA endpoint | ||
endpoint_response = deviceAdvisor.get_endpoint( | ||
thingArn = create_thing_response['thingArn'] | ||
) | ||
os.environ['DA_ENDPOINT'] = endpoint_response['endpoint'] | ||
|
||
while True: | ||
# sleep for 1s every loop to avoid TooManyRequestsException | ||
sleep(1) | ||
test_result_responds = deviceAdvisor.get_suite_run( | ||
suiteDefinitionId=DATestConfig['test_suite_ids'][test_name], | ||
suiteRunId=test_start_response['suiteRunId'] | ||
) | ||
# If the status is PENDING or the responds does not loaded, the test suite is still loading | ||
if (test_result_responds['status'] == 'PENDING' or | ||
len(test_result_responds['testResult']['groups']) == 0 or # test group has not been loaded | ||
len(test_result_responds['testResult']['groups'][0]['tests']) == 0 or #test case has not been loaded | ||
test_result_responds['testResult']['groups'][0]['tests'][0]['status'] == 'PENDING'): | ||
continue | ||
|
||
# Start to run the test sample after the status turns into RUNNING | ||
elif (test_result_responds['status'] == 'RUNNING' and | ||
test_result_responds['testResult']['groups'][0]['tests'][0]['status'] == 'RUNNING'): | ||
exe_path = os.path.join("deviceadvisor/tests/",DATestConfig['test_exe_path'][test_name]) | ||
result = subprocess.run('python3 ' + exe_path, timeout = 60*5, shell = True) | ||
# If the test finalizing then store the test result | ||
elif (test_result_responds['status'] != 'RUNNING'): | ||
test_result[test_name] = test_result_responds['status'] | ||
break | ||
except Exception as e: | ||
print("[Device Advisor]Error: Failed to test: "+ test_name + e) | ||
exit(-1) | ||
|
||
############################################## | ||
# print result and cleanup things | ||
print(test_result) | ||
failed = False | ||
for test in test_result: | ||
if(test_result[test] != "PASS" and | ||
test_result[test] != "PASS_WITH_WARNINGS"): | ||
print("[Device Advisor]Error: Test \"" + test + "\" Failed with status:" + test_result[test]) | ||
failed = True | ||
if failed: | ||
# if the test failed, we dont clean the Thing so that we can track the error | ||
exit(-1) | ||
|
||
delete_thing_with_certi(thing_name, certificate_id ,certificate_arn ) | ||
exit(0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these commented lines be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I leave it there in case we need in future, but you are right. I will remove it before merge.