Skip to content

Commit

Permalink
ci: support using shopping app for integration testing in device farm (
Browse files Browse the repository at this point in the history
  • Loading branch information
zhu-xiaowei authored Feb 4, 2024
1 parent 2bd2962 commit 16328f2
Show file tree
Hide file tree
Showing 8 changed files with 727 additions and 14 deletions.
152 changes: 152 additions & 0 deletions .github/workflows/integration_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
name: Integration Test

on:
pull_request:
branches: [ "main" ]

jobs:
e2e-test:
runs-on: macos-13-xl
permissions:
contents: write
checks: write
pull-requests: write
id-token: write
env:
iam_role_to_assume: ${{ secrets.ROLE_ARN }}
device_farm_project_arn: ${{ secrets.DEVICE_FARM_PROJECT_ARN }}
device_farm_pool_arn: ${{ secrets.DEVICE_FARM_POOL_ARN }}
device_farm_test_spec_arn: ${{ secrets.DEVICE_FARM_TEST_SPEC_ARN }}
clickstream_app_id: ${{ secrets.CLICKSTREAM_APP_ID }}
clickstream_endpoint: ${{ secrets.CLICKSTREAM_ENDPOINT }}
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.PROJECT_TOKEN }}
- name: Modify SDK for integration test
run: |
sed -i '' -e "s#private(set) var bundleSequenceId: Int#private(set) var bundleSequenceId: Int\n var allEventJson: String = \"\"#g" Sources/Clickstream/Dependency/Clickstream/Analytics/EventRecorder.swift
sed -i '' -e "s#toPrettierJsonString())\")#toPrettierJsonString())\")\n allEventJson.append(\"Saved event \\\(event.eventType):\\\(eventObject.toJsonString())\\\n\")\n UIPasteboard.general.string = allEventJson#g" Sources/Clickstream/Dependency/Clickstream/Analytics/EventRecorder.swift
sed -i '' -e "s#batchEvent.eventCount) events\")#batchEvent.eventCount) events\")\n allEventJson.append(\"Send \\\(batchEvent.eventCount) events\\\n\")\n UIPasteboard.general.string = allEventJson#g" Sources/Clickstream/Dependency/Clickstream/Analytics/EventRecorder.swift
git diff
- name: Prepare sample iOS app
run: |
cd ..
git clone https://github.com/aws-samples/clickstream-sdk-samples
cd clickstream-sdk-samples/ios
sed -i '' -e "s#\"appId\": \"your appId\"#\"appId\": \"${{ env.clickstream_app_id }}\"#g" ModerneShopping/amplifyconfiguration.json
sed -i '' -e "s#\"endpoint\": \"your endpoint\"#\"endpoint\": \"${{ env.clickstream_endpoint }}\"#g" ModerneShopping/amplifyconfiguration.json
sed -i '' -e "s#if index==0 || index==1 {}#if index==0 || index==1 {\n cart.addToCart(addedProduct: product, quantity: 1)\n }#g" ModerneShopping/Views/ProductViews/ProductList.swift
sed -i '' -e "s#3A1001882A1DDF4300DF72CB /\* XCRemoteSwiftPackageReference \"clickstream-swift\" \*\/,#3A67FCB62B6F26C60098082A /\* XCLocalSwiftPackageReference \"../../clickstream-swift\" \*\/,#g" ModerneShopping.xcodeproj/project.pbxproj
perl -0777 -pi -e 's#/\* Begin XCRemoteSwiftPackageReference section \*/\n(\t+)3A1001882A1DDF4300DF72CB /\* XCRemoteSwiftPackageReference \"clickstream-swift\" \*/ = {\n(\t+)isa = XCRemoteSwiftPackageReference;\n(\t+)repositoryURL = \"https://github.com/awslabs/clickstream-swift.git\";\n(\t+)requirement = {\n(\t+)branch = main;\n(\t+)kind = branch;\n(\t+)};\n(\t+)};#/\* Begin XCLocalSwiftPackageReference section \*/\n\t\t3A67FCB62B6F26C60098082A /\* XCLocalSwiftPackageReference \"../../clickstream-swift\" \*/ = {\n$2isa = XCLocalSwiftPackageReference;\n$3relativePath = \"../../clickstream-swift\";\n$1};\n/\* End XCLocalSwiftPackageReference section \*/\n\n/* Begin XCRemoteSwiftPackageReference section \*/#' ModerneShopping.xcodeproj/project.pbxproj
perl -0777 -pi -e 's#isa = XCSwiftPackageProductDependency;\n(\t+)package = 3A1001882A1DDF4300DF72CB /\* XCRemoteSwiftPackageReference \"clickstream-swift\" \*/;#isa = XCSwiftPackageProductDependency;#' ModerneShopping.xcodeproj/project.pbxproj
perl -0777 -pi -e 's#\n {\n "identity" : "clickstream-swift",\n "kind" : "remoteSourceControl",\n "location" : "https://github.com/awslabs/clickstream-swift.git",\n "state" : {\n "branch" : "main",\n "revision" : "2bd29626068a6dff158f41f9d81295a6eaa59be5"\n }\n },##' ModerneShopping.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
perl -0777 -pi -e 's#objectVersion = 54;#objectVersion = 60;#' ModerneShopping.xcodeproj/project.pbxproj
git diff
- name: Generate export options
run: |
echo '${{ vars.EXPORT_OPTIONS }}' >> ExportOptions.plist
cat ExportOptions.plist
ls
- name: Install the Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.P12_BASE64 }}
P12_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.MOBILEPROVISION_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/shoppingmacdev.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# apply provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
- name: Build archive
run: |
sudo xcode-select -s '/Applications/Xcode_15.2.app/Contents/Developer'
xcode-select --print-path
cd ../clickstream-sdk-samples/ios/
xcodebuild -resolvePackageDependencies
echo "start build app"
xcodebuild -scheme "ModerneShopping" \
-archivePath $RUNNER_TEMP/ModerneShopping.xcarchive \
-sdk iphoneos \
-configuration Release \
-destination generic/platform=iOS \
clean archive | xcpretty
- name: Export ipa
run: |
EXPORT_OPTS_PATH=ExportOptions.plist
xcodebuild -exportArchive -archivePath $RUNNER_TEMP/ModerneShopping.xcarchive -exportOptionsPlist $EXPORT_OPTS_PATH -exportPath output
cd output
ls
- name: Build Device Farm test file
run: |
cd IntegrationTest
pip install virtualenv
virtualenv --help
virtualenv workspace
cd workspace
source bin/activate
pip install -r ../requirements.txt
mkdir tests
cp ../appium/shopping_test.py tests/
find tests/
py.test --collect-only tests/
cd tests/
find . -name '__pycache__' -type d -exec rm -r {} +
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
cd ..
pip freeze > requirements.txt
zip -r test_bundle.zip tests/ requirements.txt
ls
cd ..
- name: Configure AWS Credentials
if: ${{ env.iam_role_to_assume != '' }}
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.iam_role_to_assume }}
aws-region: us-west-2
- name: Execute device farm test
run: |
cd IntegrationTest
pip install -r requirements.txt
cd devicefarm
cp ../../output/ModerneShopping.ipa ./
cp ../workspace/test_bundle.zip ./
ls
python -u -c "from automate_device_farm import upload_and_test_ios; upload_and_test_ios('ModerneShopping.ipa', 'test_bundle.zip', '${{ env.device_farm_project_arn }}', '${{ env.device_farm_test_spec_arn }}', '${{ env.device_farm_pool_arn }}')"
- name: Execute logcat test
run: |
cd IntegrationTest/devicefarm
pytest logcat_test.py -s --junitxml=report/logcat_test_report.xml --html=report/logcat_test_report.html
- name: Publish Test Report
uses: mikepenz/action-junit-report@v4
if: success() || failure()
with:
report_paths: 'IntegrationTest/devicefarm/report/*.xml'
require_tests: true
detailed_summary: true
include_passed: true
fail_on_failure: true
job_name: integration test
- name: Upload test result
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: test-result
path: |
IntegrationTest/devicefarm/report/
IntegrationTest/devicefarm/MyAndroidAppTest-*/**
44 changes: 30 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
Expand All @@ -22,17 +22,33 @@ jobs:
chmod +x release.sh
./release.sh ${{ env.NEW_VERSION }}
git diff
git config user.name '${{ vars.USER_NAME }}'
git config user.email '${{ vars.USER_EMAIL }}'
git add .
git commit -m 'release: clickstream Swift ${{ env.NEW_VERSION }}'
git push
git tag ${{ env.NEW_VERSION }}
git push origin ${{ env.NEW_VERSION }}
- name: Create GitHub release
uses: softprops/action-gh-release@v1
git config user.name "github-actions"
git config user.email "[email protected]"
- name: Create Pull Request
id: create-pr
uses: peter-evans/create-pull-request@v5
with:
name: "Clickstream Swift ${{ env.NEW_VERSION }}"
tag_name: "${{ env.NEW_VERSION }}"
prerelease: true
generate_release_notes: true
token: ${{ secrets.PROJECT_TOKEN }}
commit-message: 'release: clickstream Swift ${{ env.NEW_VERSION }}'
title: 'release: clickstream Swift ${{ env.NEW_VERSION }}'
author: github-actions <[email protected]>
committer: github-actions <[email protected]>
signoff: true
body: |
## Description
1. release: clickstream Swift ${{ env.NEW_VERSION }}
## General Checklist
<!-- Check or cross out if not relevant -->
- [x] Added new tests to cover change, if needed
- [x] Build succeeds using Swift Package Manager
- [x] All unit tests pass
- [x] Documentation update for the change if required
- [x] PR title conforms to conventional commit style
- [x] If breaking change, documentation/changelog update with migration instructions
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
labels: release
branch: release_${{ env.NEW_VERSION }}
36 changes: 36 additions & 0 deletions .github/workflows/tag_and_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Create Tag And Release
on:
push:
branches: [ "main" ]

jobs:
release:
if: ${{ startsWith(github.event.head_commit.message, 'release:') }}
runs-on: ubuntu-latest
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
token: ${{ secrets.PROJECT_TOKEN }}
- name: Create new tag
run: |
echo "${{ env.COMMIT_MESSAGE }}"
version=$(echo "${{ env.COMMIT_MESSAGE }}" | grep -oP 'Swift \K\d+\.\d+\.\d+')
echo "release_version=$version" >> "$GITHUB_ENV"
echo $version
git config user.name '${{ vars.USER_NAME }}'
git config user.email '${{ vars.USER_EMAIL }}'
git tag v$version
git push origin v$version
- name: Create GitHub release
uses: softprops/action-gh-release@v1
with:
name: "Clickstream Swift ${{ env.release_version }}"
tag_name: "${{ env.release_version }}"
prerelease: true
generate_release_notes: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
.idea
74 changes: 74 additions & 0 deletions IntegrationTest/appium/shopping_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
with the License. A copy of the License is located at
http://www.apache.org/licenses/LICENSE-2.0
or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
and limitations under the License.
"""
import pytest
from time import sleep

from appium import webdriver
from appium.options.ios import XCUITestOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.common.exceptions import NoSuchElementException

capabilities = dict(
platformName='ios',
automationName='xcuitest',
deviceName='iPhone',
bundleId='software.aws.solution.ModerneShopping',
language='en',
locale='US',
)

appium_server_url = 'http://0.0.0.0:4723/wd/hub'


class TestShopping:
def setup_method(self):
self.driver = webdriver.Remote(appium_server_url, options=XCUITestOptions().load_capabilities(capabilities))
self.driver.implicitly_wait(10)

def teardown_method(self):
if self.driver:
self.driver.quit()

@pytest.mark.parametrize("test_suite", [
"test suite 1",
"test suite 2"
])
def test_shopping(self, test_suite):
sleep(3)
self.perform_click_element('Profile')
self.perform_click_element('sign_in')
sleep(3)
self.perform_click_element('Cart')
self.perform_click_element('check_out')
self.perform_click_element('purchase')
self.perform_click_element('Profile')
self.perform_click_element("sign_out")
self.driver.execute_script('mobile: backgroundApp', {"seconds": 5})
sleep(1)
self.perform_click_element("show_log_text")
event_log = self.driver.find_element(by=AppiumBy.ID, value="event_log")
self.driver.log_event("app_event_log", event_log.text)
print(event_log.text)
sleep(1)

def perform_click_element(self, element_id):
try:
element = self.driver.find_element(by=AppiumBy.ID, value=element_id)
element.click()
sleep(2)
except NoSuchElementException:
pytest.skip(f"Element with ID '{element_id}' not found. Skipped the test")


if __name__ == '__main__':
TestShopping.test_shopping()
Loading

0 comments on commit 16328f2

Please sign in to comment.