From 46825fc8a594dcd14f3ea6ad29fcefd5da591963 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 12 Jan 2026 15:57:51 -0800 Subject: [PATCH 001/114] enable android build --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 9e542d150d..1c49b5cef9 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -244,7 +244,6 @@ jobs: pool: vmImage: ubuntu-latest displayName: Android Build - condition: false steps: - powershell: ./vsts/echo_versions.ps1 displayName: 'Echo Versions' @@ -294,7 +293,6 @@ jobs: - job: AndroidTest timeoutInMinutes: 50 - condition: false pool: vmImage: 'macOS-latest' strategy: From 5a55acfacf0289e1a32ad01f7b8f9e409743b746 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 12 Jan 2026 16:09:30 -0800 Subject: [PATCH 002/114] ? --- vsts/build_e2e_tests.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vsts/build_e2e_tests.ps1 b/vsts/build_e2e_tests.ps1 index 5b190ea1c6..19b4177588 100644 --- a/vsts/build_e2e_tests.ps1 +++ b/vsts/build_e2e_tests.ps1 @@ -1,2 +1 @@ -mvn `-Dmaven.javadoc.skip=true --projects :iot-e2e-common ` - --also-make clean install `-DskipTests --batch-mode `-q \ No newline at end of file +mvn install `-DskipTests `-Dmaven.javadoc.skip=true -T 2C --batch-mode -q \ No newline at end of file From 37309ba20a8d7dc65789c81416041b986ddf17fa Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 12 Jan 2026 16:18:32 -0800 Subject: [PATCH 003/114] install java 8 --- vsts/build_e2e_tests.ps1 | 3 ++- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/vsts/build_e2e_tests.ps1 b/vsts/build_e2e_tests.ps1 index 19b4177588..5b190ea1c6 100644 --- a/vsts/build_e2e_tests.ps1 +++ b/vsts/build_e2e_tests.ps1 @@ -1 +1,2 @@ -mvn install `-DskipTests `-Dmaven.javadoc.skip=true -T 2C --batch-mode -q \ No newline at end of file +mvn `-Dmaven.javadoc.skip=true --projects :iot-e2e-common ` + --also-make clean install `-DskipTests --batch-mode `-q \ No newline at end of file diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 1c49b5cef9..2ca637f0b2 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -245,6 +245,11 @@ jobs: vmImage: ubuntu-latest displayName: Android Build steps: + - task: JavaToolInstaller@0 + inputs: + versionSpec: 8 + jdkArchitectureOption: 'x64' + jdkSourceOption: 'PreInstalled' - powershell: ./vsts/echo_versions.ps1 displayName: 'Echo Versions' env: From 56495095a6e7c00115cc2ee933b643578e567c1c Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 14 Jan 2026 15:15:25 -0800 Subject: [PATCH 004/114] ? --- vsts/gradle_build.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index 5393b575ed..4be5c12537 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -3,11 +3,11 @@ cd iot-e2e-tests\android # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions -Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-6.8.3-bin.zip" -OutFile ./gradle.zip +Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-bin.zip" -OutFile ./gradle.zip Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-6.8.3/bin/gradle wrapper +./gradle/gradle-9.2.1/bin/gradle wrapper Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From 65ca661da5cfdcde0fb1ab42eda51c720b964169 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 14 Jan 2026 15:18:39 -0800 Subject: [PATCH 005/114] 1 --- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 2ca637f0b2..67da04000d 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -44,6 +44,7 @@ jobs: ### Windows ### - job: Windows timeoutInMinutes: 180 + condition: false dependsOn: DeployCloudTestResources variables: IOTHUB_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.IOTHUB_CONNECTION_STRING'] ] @@ -150,6 +151,7 @@ jobs: DPS_IDSCOPE: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.DPS_IDSCOPE'] ] PROVISIONING_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.PROVISIONING_CONNECTION_STRING'] ] timeoutInMinutes: 180 + condition: false pool: # If this is changed, don't forget to update supported_platforms.md in the root directory. That document outlines what OS we test on and should stay up to date. vmImage: ubuntu-latest @@ -301,32 +303,10 @@ jobs: pool: vmImage: 'macOS-latest' strategy: - maxParallel: 12 + maxParallel: 1 matrix: TestGroup1: ANDROID_TEST_GROUP_ID: TestGroup1 - TestGroup2: - ANDROID_TEST_GROUP_ID: TestGroup2 - TestGroup3: - ANDROID_TEST_GROUP_ID: TestGroup3 - TestGroup4: - ANDROID_TEST_GROUP_ID: TestGroup4 - TestGroup5: - ANDROID_TEST_GROUP_ID: TestGroup5 - TestGroup6: - ANDROID_TEST_GROUP_ID: TestGroup6 - TestGroup7: - ANDROID_TEST_GROUP_ID: TestGroup7 - TestGroup8: - ANDROID_TEST_GROUP_ID: TestGroup8 - TestGroup9: - ANDROID_TEST_GROUP_ID: TestGroup9 - TestGroup10: - ANDROID_TEST_GROUP_ID: TestGroup10 - TestGroup11: - ANDROID_TEST_GROUP_ID: TestGroup11 - TestGroup12: - ANDROID_TEST_GROUP_ID: TestGroup12 displayName: Android Test dependsOn: AndroidBuild From 705ea58f6c48de9b096f42d2826d03470c60fefd Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 14 Jan 2026 15:29:07 -0800 Subject: [PATCH 006/114] 17 --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 67da04000d..881e350b90 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -249,9 +249,10 @@ jobs: steps: - task: JavaToolInstaller@0 inputs: - versionSpec: 8 + versionSpec: 17 jdkArchitectureOption: 'x64' jdkSourceOption: 'PreInstalled' + - powershell: ./vsts/echo_versions.ps1 displayName: 'Echo Versions' env: From 70f2df6442081572413288b8497b8d06a1f06741 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 14 Jan 2026 15:49:10 -0800 Subject: [PATCH 007/114] lombok version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index db0d0fbbc3..20b1149a89 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ org.projectlombok lombok - 1.18.12 + 1.18.30 com.microsoft.azure From 5391435656483baea40782f73e2579f271a38b55 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 14 Jan 2026 16:06:53 -0800 Subject: [PATCH 008/114] logs --- vsts/gradle_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index 4be5c12537..123ab98474 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -7,7 +7,7 @@ Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-b Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-9.2.1/bin/gradle wrapper +./gradle/gradle-9.2.1/bin/gradle wrapper --info Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From a1925038aa8c4715a95d6221d722be5a6592ff00 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 14 Jan 2026 16:19:34 -0800 Subject: [PATCH 009/114] stacktrace --- vsts/gradle_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index 123ab98474..d08164e4e1 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -7,7 +7,7 @@ Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-b Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-9.2.1/bin/gradle wrapper --info +./gradle/gradle-9.2.1/bin/gradle wrapper --stacktrace Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From ca8df82293b1ec0a25ede749bf42fb3a07ef964b Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 14 Jan 2026 16:46:06 -0800 Subject: [PATCH 010/114] 7.3.3 --- vsts/gradle_build.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index d08164e4e1..dedf951295 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -3,11 +3,11 @@ cd iot-e2e-tests\android # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions -Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-bin.zip" -OutFile ./gradle.zip +Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-7.3.3-bin.zip" -OutFile ./gradle.zip Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-9.2.1/bin/gradle wrapper --stacktrace +./gradle/gradle-7.3.3/bin/gradle wrapper --stacktrace Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From 02c6adf604c167e975e9a0969c0066f19119e445 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:09:42 -0800 Subject: [PATCH 011/114] dummy project --- iot-e2e-tests/android2/.gitignore | 15 +++++++ iot-e2e-tests/android2/.idea/.gitignore | 3 ++ iot-e2e-tests/android2/.idea/.name | 1 + .../android2/.idea/AndroidProjectSystem.xml | 6 +++ iot-e2e-tests/android2/.idea/compiler.xml | 6 +++ .../.idea/deploymentTargetSelector.xml | 10 +++++ iot-e2e-tests/android2/.idea/gradle.xml | 18 +++++++++ iot-e2e-tests/android2/.idea/migrations.xml | 10 +++++ iot-e2e-tests/android2/.idea/misc.xml | 10 +++++ .../android2/.idea/runConfigurations.xml | 17 ++++++++ iot-e2e-tests/android2/.idea/vcs.xml | 6 +++ iot-e2e-tests/android2/app/.gitignore | 1 + iot-e2e-tests/android2/app/build.gradle | 39 +++++++++++++++++++ iot-e2e-tests/android2/app/proguard-rules.pro | 21 ++++++++++ .../sdk/iot/androidtest/ExampleTest.java | 26 +++++++++++++ .../android2/app/src/main/AndroidManifest.xml | 15 +++++++ iot-e2e-tests/android2/build.gradle | 4 ++ .../android2/gradle/libs.versions.toml | 18 +++++++++ iot-e2e-tests/android2/settings.gradle | 23 +++++++++++ 19 files changed, 249 insertions(+) create mode 100644 iot-e2e-tests/android2/.gitignore create mode 100644 iot-e2e-tests/android2/.idea/.gitignore create mode 100644 iot-e2e-tests/android2/.idea/.name create mode 100644 iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml create mode 100644 iot-e2e-tests/android2/.idea/compiler.xml create mode 100644 iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml create mode 100644 iot-e2e-tests/android2/.idea/gradle.xml create mode 100644 iot-e2e-tests/android2/.idea/migrations.xml create mode 100644 iot-e2e-tests/android2/.idea/misc.xml create mode 100644 iot-e2e-tests/android2/.idea/runConfigurations.xml create mode 100644 iot-e2e-tests/android2/.idea/vcs.xml create mode 100644 iot-e2e-tests/android2/app/.gitignore create mode 100644 iot-e2e-tests/android2/app/build.gradle create mode 100644 iot-e2e-tests/android2/app/proguard-rules.pro create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java create mode 100644 iot-e2e-tests/android2/app/src/main/AndroidManifest.xml create mode 100644 iot-e2e-tests/android2/build.gradle create mode 100644 iot-e2e-tests/android2/gradle/libs.versions.toml create mode 100644 iot-e2e-tests/android2/settings.gradle diff --git a/iot-e2e-tests/android2/.gitignore b/iot-e2e-tests/android2/.gitignore new file mode 100644 index 0000000000..aa724b7707 --- /dev/null +++ b/iot-e2e-tests/android2/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/iot-e2e-tests/android2/.idea/.gitignore b/iot-e2e-tests/android2/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/iot-e2e-tests/android2/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/iot-e2e-tests/android2/.idea/.name b/iot-e2e-tests/android2/.idea/.name new file mode 100644 index 0000000000..b3405b3b32 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/.name @@ -0,0 +1 @@ +My Application \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml b/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000000..4a53bee8cb --- /dev/null +++ b/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/compiler.xml b/iot-e2e-tests/android2/.idea/compiler.xml new file mode 100644 index 0000000000..b86273d942 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml b/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000000..b268ef36cd --- /dev/null +++ b/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/gradle.xml b/iot-e2e-tests/android2/.idea/gradle.xml new file mode 100644 index 0000000000..97f0a8e140 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/migrations.xml b/iot-e2e-tests/android2/.idea/migrations.xml new file mode 100644 index 0000000000..f8051a6f97 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/misc.xml b/iot-e2e-tests/android2/.idea/misc.xml new file mode 100644 index 0000000000..74dd639e4e --- /dev/null +++ b/iot-e2e-tests/android2/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/runConfigurations.xml b/iot-e2e-tests/android2/.idea/runConfigurations.xml new file mode 100644 index 0000000000..16660f1d80 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/vcs.xml b/iot-e2e-tests/android2/.idea/vcs.xml new file mode 100644 index 0000000000..b2bdec2d71 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/.gitignore b/iot-e2e-tests/android2/app/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/iot-e2e-tests/android2/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle new file mode 100644 index 0000000000..f159b4b5e6 --- /dev/null +++ b/iot-e2e-tests/android2/app/build.gradle @@ -0,0 +1,39 @@ +plugins { + alias(libs.plugins.android.application) +} + +android { + namespace 'com.microsoft.azure.sdk.iot.androidtest' + compileSdk { + version = release(36) + } + + defaultConfig { + applicationId "com.microsoft.azure.sdk.iot.androidtest" + minSdk 24 + targetSdk 36 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } +} + +dependencies { + implementation libs.appcompat + implementation libs.material + testImplementation libs.junit + androidTestImplementation libs.ext.junit + androidTestImplementation libs.espresso.core +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/proguard-rules.pro b/iot-e2e-tests/android2/app/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/iot-e2e-tests/android2/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java new file mode 100644 index 0000000000..dfb2433eef --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java @@ -0,0 +1,26 @@ +package com.microsoft.azure.sdk.iot.androidtest; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleTest { + @Test + public void shouldPass() { + + } + + @Test + public void shouldFail() { + Assert.fail(); + } + +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..5993852e3c --- /dev/null +++ b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/build.gradle b/iot-e2e-tests/android2/build.gradle new file mode 100644 index 0000000000..37562787fc --- /dev/null +++ b/iot-e2e-tests/android2/build.gradle @@ -0,0 +1,4 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + alias(libs.plugins.android.application) apply false +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/gradle/libs.versions.toml b/iot-e2e-tests/android2/gradle/libs.versions.toml new file mode 100644 index 0000000000..c3aac0a29c --- /dev/null +++ b/iot-e2e-tests/android2/gradle/libs.versions.toml @@ -0,0 +1,18 @@ +[versions] +agp = "8.13.2" +junit = "4.13.2" +junitVersion = "1.1.5" +espressoCore = "3.5.1" +appcompat = "1.6.1" +material = "1.10.0" + +[libraries] +junit = { group = "junit", name = "junit", version.ref = "junit" } +ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } + diff --git a/iot-e2e-tests/android2/settings.gradle b/iot-e2e-tests/android2/settings.gradle new file mode 100644 index 0000000000..437187ca7f --- /dev/null +++ b/iot-e2e-tests/android2/settings.gradle @@ -0,0 +1,23 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "My Application" +include ':app' From 808ad2565bf3142b5bcb12991782af586fdf674a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:12:17 -0800 Subject: [PATCH 012/114] 2 --- vsts/gradle_build.ps1 | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index dedf951295..0d038bdebd 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -1,13 +1,13 @@ # This script assumes it is being run from the root of the repository -cd iot-e2e-tests\android +cd iot-e2e-tests\android2 # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions -Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-7.3.3-bin.zip" -OutFile ./gradle.zip +Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-bin.zip" -OutFile ./gradle.zip Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-7.3.3/bin/gradle wrapper --stacktrace +./gradle/gradle-9.2.1/bin/gradle wrapper --stacktrace Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug @@ -17,13 +17,4 @@ Write-Host "Assembling the source APK" # and the emulators have no access to the environment variables on the OS that runs the emulator, # so this is the only way to pass along these secrets. Write-Host "Assembling the test APK with the provided secrets" -./gradlew :app:assembleDebugAndroidTest ` - `-PIOTHUB_CONNECTION_STRING=$env:IOTHUB_CONNECTION_STRING ` - `-PIOT_DPS_CONNECTION_STRING=$env:IOT_DPS_CONNECTION_STRING ` - `-PIOT_DPS_ID_SCOPE=$env:DEVICE_PROVISIONING_SERVICE_ID_SCOPE ` - `-PDPS_GLOBALDEVICEENDPOINT_INVALIDCERT=$env:INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT ` - `-PPROVISIONING_CONNECTION_STRING_INVALIDCERT=$env:INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING ` - `-PDPS_GLOBALDEVICEENDPOINT=$env:DPS_GLOBALDEVICEENDPOINT ` - `-PIS_BASIC_TIER_HUB=$env:IS_BASIC_TIER_HUB ` - `-PIS_PULL_REQUEST=$env:isPullRequestBuild ` - `-PRECYCLE_TEST_IDENTITIES=true +./gradlew :app:assembleDebugAndroidTest From ff0b94e59a5c8c93cf70d0c08a50ce74dc4a132c Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:20:03 -0800 Subject: [PATCH 013/114] don't deploy cloud resources --- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 881e350b90..16d4151025 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -21,7 +21,8 @@ jobs: vmImage: windows-latest steps: - task: AzureCLI@2 - name: deployCloudTestResources + name: deployCloudTestResources + condition: false inputs: azureSubscription: 'iot hub sdk service connection' scriptType: 'pscore' @@ -237,11 +238,11 @@ jobs: ### Android, Multi configuration build (Multiple different test groups to cover) ### - job: AndroidBuild - dependsOn: DeployCloudTestResources - variables: - IOTHUB_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.IOTHUB_CONNECTION_STRING'] ] - DPS_IDSCOPE: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.DPS_IDSCOPE'] ] - PROVISIONING_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.PROVISIONING_CONNECTION_STRING'] ] + #dependsOn: DeployCloudTestResources + #variables: + # IOTHUB_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.IOTHUB_CONNECTION_STRING'] ] + # DPS_IDSCOPE: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.DPS_IDSCOPE'] ] + # PROVISIONING_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.PROVISIONING_CONNECTION_STRING'] ] timeoutInMinutes: 30 pool: vmImage: ubuntu-latest @@ -268,11 +269,11 @@ jobs: displayName: 'Gradle Build' env: JAVA_VERSION: $(JAVA_VERSION) - IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) - IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) - IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) - TARGET_BRANCH: $(System.PullRequest.TargetBranch) - RECYCLE_TEST_IDENTITIES: true + #IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) + #IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) + #IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) + #TARGET_BRANCH: $(System.PullRequest.TargetBranch) + #RECYCLE_TEST_IDENTITIES: true condition: always() - task: CopyFiles@2 @@ -359,7 +360,7 @@ jobs: condition : always() - job: TearDownCloudTestResources - condition: always() + condition: false dependsOn: - Windows - Linux From 9dd412454f026d5479f892147383015efd077f1a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:25:40 -0800 Subject: [PATCH 014/114] gradle properties --- iot-e2e-tests/android2/gradle.properties | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 iot-e2e-tests/android2/gradle.properties diff --git a/iot-e2e-tests/android2/gradle.properties b/iot-e2e-tests/android2/gradle.properties new file mode 100644 index 0000000000..4387edc225 --- /dev/null +++ b/iot-e2e-tests/android2/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file From ffd9497b5ff2d0773d3ce5eb1b55283c23aaec79 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:26:36 -0800 Subject: [PATCH 015/114] more --- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 16d4151025..f451d99a88 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -313,16 +313,16 @@ jobs: displayName: Android Test dependsOn: AndroidBuild steps: - - task: PowerShell@2 - displayName: 'determine if testing needed' - condition: always() - inputs: - targetType: 'filePath' - filePath: ./vsts/determine_if_android_test_group_needs_to_run.ps1 - env: - TEST_GROUP_ID: $(ANDROID_TEST_GROUP_ID) - IS_BASIC_TIER_HUB: $(IS-BASIC-TIER-HUB) - TARGET_BRANCH: $(System.PullRequest.TargetBranch) + #- task: PowerShell@2 + # displayName: 'determine if testing needed' + # condition: always() + # inputs: + # targetType: 'filePath' + # filePath: ./vsts/determine_if_android_test_group_needs_to_run.ps1 + # env: + # TEST_GROUP_ID: $(ANDROID_TEST_GROUP_ID) + # IS_BASIC_TIER_HUB: $(IS-BASIC-TIER-HUB) + # TARGET_BRANCH: $(System.PullRequest.TargetBranch) - task: DownloadPipelineArtifact@0 displayName: "Download APKs to test from previous job" From 16aae9d8343b97fad81f2a6f4c4dcc20f814370a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:26:53 -0800 Subject: [PATCH 016/114] 2 --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index f451d99a88..ad06d884fe 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -329,7 +329,7 @@ jobs: condition: eq(variables['task.android.needToRunTestGroup'], 'yes') inputs: artifactName: 'androidBuildFiles' - targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk + targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk - task: Bash@3 condition: eq(variables['task.android.needToRunTestGroup'], 'yes') From 48c283d94d8398fdcb2619d5d2da55e4a3c48302 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:33:30 -0800 Subject: [PATCH 017/114] manifest --- iot-e2e-tests/android2/app/src/main/AndroidManifest.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml index 5993852e3c..bbbae723e7 100644 --- a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml +++ b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml @@ -4,12 +4,7 @@ + android:supportsRtl="true"/> \ No newline at end of file From 77d5cc2e70fe81c8ede2aec753c76c1562c75004 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:37:40 -0800 Subject: [PATCH 018/114] yep --- iot-e2e-tests/android2/app/src/main/AndroidManifest.xml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml index bbbae723e7..44008a4332 100644 --- a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml +++ b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml @@ -1,10 +1,4 @@ - - - + \ No newline at end of file From 060d652d47ac75be5b099af2bdb1a163fb29d136 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:48:27 -0800 Subject: [PATCH 019/114] asdf --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index ad06d884fe..5557e254d3 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -290,7 +290,7 @@ jobs: displayName: 'Publish APKs to test in next job' inputs: artifactName: 'androidBuildFiles' - targetPath: 'iot-e2e-tests/android/app/build/outputs/apk' + targetPath: 'iot-e2e-tests/android2/app/build/outputs/apk' - task: ComponentGovernanceComponentDetection@0 displayName: Component Governance Detection From 39160993340f63b1f429b8779a459663f9fc91be Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 11:58:27 -0800 Subject: [PATCH 020/114] asdf --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 5557e254d3..2f5045618d 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -279,7 +279,7 @@ jobs: - task: CopyFiles@2 displayName: 'Copy Test Results to Artifact Staging Directory' inputs: - SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk' + SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk' Contents: | *.* TargetFolder: '$(Build.ArtifactStagingDirectory)' @@ -326,13 +326,13 @@ jobs: - task: DownloadPipelineArtifact@0 displayName: "Download APKs to test from previous job" - condition: eq(variables['task.android.needToRunTestGroup'], 'yes') + #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') inputs: artifactName: 'androidBuildFiles' targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk - task: Bash@3 - condition: eq(variables['task.android.needToRunTestGroup'], 'yes') + #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') displayName: 'Start Android Emulator' timeoutInMinutes: 15 continueOnError: false @@ -342,7 +342,7 @@ jobs: - task: Bash@3 #only run tests on emulator if tests should be run, and if the emulator boot up was successful - condition: and(succeeded(), eq(variables['task.android.needToRunTestGroup'], 'yes')) + #condition: and(succeeded(), eq(variables['task.android.needToRunTestGroup'], 'yes')) displayName: 'Run tests on emulator' timeoutInMinutes: 45 inputs: From 708664f996f4773ed9f971feb85d8f21b1d31fcd Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 14:27:55 -0800 Subject: [PATCH 021/114] 2 --- vsts/RunTestsOnEmulator.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index c1e3367d0d..ec53bd9dd5 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -2,27 +2,28 @@ # This APK file is generated by the Android build task and then is copied into the android test run task. If the APK file # is missing, then either the copy failed, or the APK was never successfully built. -if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk" ]; then +if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi -if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then +if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi # -e flag to force this command to run on what should be the only emulator active on this machine echo 'Installing APKs on emulator' -adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk -adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk +adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk +adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk #List instrumentation classes, for logging purposes only echo 'Listing available instrumentations:' adb -e shell pm list instrumentation echo '' -annotationString="com.microsoft.azure.sdk.iot.android.helper.${TEST_GROUP_ID}" +#annotationString="com.microsoft.azure.sdk.iot.android.helper.${TEST_GROUP_ID}" +annotationString="com.microsoft.azure.sdk.iot.android.helper.1" echo 'Running android tests with annotation' echo $annotationString From f8490c3242c9c105c69b1be80aba56408d3a5ed1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 15:16:14 -0800 Subject: [PATCH 022/114] ? --- vsts/StartEmulator.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index f9874bd503..7e17792fc7 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -24,9 +24,9 @@ nohup $ANDROID_HOME/emulator/emulator -avd $avdName -gpu auto -no-snapshot > /de echo '' echo 'Waiting for emulator to boot up...' -nohup $ANDROID_HOME/emulator/emulator -avd $avdName -no-snapshot -no-audio -no-boot-anim -accel auto -gpu auto -qemu -lcd-density 420 > /dev/null 2>&1 & - $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' - $ANDROID_HOME/platform-tools/adb devices echo "Emulator started" +# Start emulator in background +nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot -no-window -no-audio -no-boot-anim -accel on > /dev/null 2>&1 & +$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d "\r") ]]; do sleep 1; done; input keyevent 82' $ANDROID_HOME/platform-tools/adb devices From db256fcf08947cc307b0c683d5c2ca238ddbb5d4 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 15:39:20 -0800 Subject: [PATCH 023/114] ? --- vsts/StartEmulator.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index 7e17792fc7..eb0ad5ea99 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -26,7 +26,7 @@ echo '' echo 'Waiting for emulator to boot up...' # Start emulator in background nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot -no-window -no-audio -no-boot-anim -accel on > /dev/null 2>&1 & -$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d "\r") ]]; do sleep 1; done; input keyevent 82' +$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;' $ANDROID_HOME/platform-tools/adb devices From f7de16a6406d462aaed5793b03171f9372818979 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 16:17:28 -0800 Subject: [PATCH 024/114] timeout --- vsts/StartEmulator.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index eb0ad5ea99..17851aba3a 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -24,9 +24,9 @@ nohup $ANDROID_HOME/emulator/emulator -avd $avdName -gpu auto -no-snapshot > /de echo '' echo 'Waiting for emulator to boot up...' -# Start emulator in background -nohup $ANDROID_HOME/emulator/emulator -avd xamarin_android_emulator -no-snapshot -no-window -no-audio -no-boot-anim -accel on > /dev/null 2>&1 & -$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;' +nohup $ANDROID_HOME/emulator/emulator -avd $avdName -no-snapshot -no-audio -no-boot-anim -accel auto -gpu auto -qemu -lcd-density 420 > /dev/null 2>&1 & +timeout 600 $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' +$ANDROID_HOME/platform-tools/adb devices echo "Emulator started" $ANDROID_HOME/platform-tools/adb devices From fc6e58b972d5d9836076e641cadbdf14ee4eb9a1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 16:33:23 -0800 Subject: [PATCH 025/114] path? --- vsts/StartEmulator.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index 17851aba3a..5bba96bc96 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -25,7 +25,7 @@ nohup $ANDROID_HOME/emulator/emulator -avd $avdName -gpu auto -no-snapshot > /de echo '' echo 'Waiting for emulator to boot up...' nohup $ANDROID_HOME/emulator/emulator -avd $avdName -no-snapshot -no-audio -no-boot-anim -accel auto -gpu auto -qemu -lcd-density 420 > /dev/null 2>&1 & -timeout 600 $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' +/usr/bin/timeout 600 $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' $ANDROID_HOME/platform-tools/adb devices echo "Emulator started" $ANDROID_HOME/platform-tools/adb devices From b91667b3c15350940c7ab876579203bce58baf1b Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 17:21:39 -0800 Subject: [PATCH 026/114] asdf --- vsts/StartEmulator.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index 5bba96bc96..9678b4f4ae 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -22,10 +22,13 @@ echo '' echo "Starting emulator in background thread" nohup $ANDROID_HOME/emulator/emulator -avd $avdName -gpu auto -no-snapshot > /dev/null 2>&1 & +apt-get update +apt-get install coreutils + echo '' echo 'Waiting for emulator to boot up...' nohup $ANDROID_HOME/emulator/emulator -avd $avdName -no-snapshot -no-audio -no-boot-anim -accel auto -gpu auto -qemu -lcd-density 420 > /dev/null 2>&1 & -/usr/bin/timeout 600 $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' +timeout 600 $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' $ANDROID_HOME/platform-tools/adb devices echo "Emulator started" $ANDROID_HOME/platform-tools/adb devices From 51e31ab6adfadee581efba930bbf72f34a9c226f Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 17:40:16 -0800 Subject: [PATCH 027/114] asdf --- vsts/StartEmulator.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index 9678b4f4ae..9d9b0db3f8 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -22,8 +22,7 @@ echo '' echo "Starting emulator in background thread" nohup $ANDROID_HOME/emulator/emulator -avd $avdName -gpu auto -no-snapshot > /dev/null 2>&1 & -apt-get update -apt-get install coreutils +yum install coreutils echo '' echo 'Waiting for emulator to boot up...' From f8a4d0bb95d3747751be132c66e87520726a49e3 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 17:54:09 -0800 Subject: [PATCH 028/114] asdf --- vsts/StartEmulator.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index 9d9b0db3f8..31335ec92e 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -22,12 +22,11 @@ echo '' echo "Starting emulator in background thread" nohup $ANDROID_HOME/emulator/emulator -avd $avdName -gpu auto -no-snapshot > /dev/null 2>&1 & -yum install coreutils echo '' echo 'Waiting for emulator to boot up...' nohup $ANDROID_HOME/emulator/emulator -avd $avdName -no-snapshot -no-audio -no-boot-anim -accel auto -gpu auto -qemu -lcd-density 420 > /dev/null 2>&1 & -timeout 600 $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' +$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' $ANDROID_HOME/platform-tools/adb devices echo "Emulator started" $ANDROID_HOME/platform-tools/adb devices From 1ba9c714b967057c5d17cfed23865ca9dc69f94a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Thu, 15 Jan 2026 18:18:25 -0800 Subject: [PATCH 029/114] 60 --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 2f5045618d..3db136eacd 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -334,7 +334,7 @@ jobs: - task: Bash@3 #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') displayName: 'Start Android Emulator' - timeoutInMinutes: 15 + timeoutInMinutes: 60 continueOnError: false inputs: targetType: 'filePath' From c1b76fd1c951a8eec2979dc1a10e597c5b27e313 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 13:53:36 -0800 Subject: [PATCH 030/114] Update ExampleTest.java --- .../com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java index dfb2433eef..d68ac2430c 100644 --- a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java @@ -20,7 +20,7 @@ public void shouldPass() { @Test public void shouldFail() { - Assert.fail(); + Assert.fail("lolololol"); } } \ No newline at end of file From 32b223bb2d8ad68589049819dbd34e97e9e88897 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 13:54:52 -0800 Subject: [PATCH 031/114] asdf --- vsts/RunTestsOnEmulator.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index ec53bd9dd5..12a406d5ca 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -28,7 +28,7 @@ echo 'Running android tests with annotation' echo $annotationString #Return code from adb shell isn't returned as one would expect. Need to capture output logs and analyze them to determine if this test run was a success or not -TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.iothub.azure.microsoft.com.androide2e.test/android.support.test.runner.AndroidJUnitRunner) +TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/android.support.test.runner.AndroidJUnitRunner) echo 'Result of running tests' echo "$TestLogs" From f0688bc1b04567bbeb180dce96d6350b07267544 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 14:08:51 -0800 Subject: [PATCH 032/114] diff script? --- vsts/StartEmulator.sh | 40 +++++++++---------- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index 31335ec92e..cb13ec21e1 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -3,31 +3,27 @@ echo 'Listing available android sdks for installation' $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --list | grep system-images -emulatorImage='system-images;android-28;google_apis;x86_64' -avdName='Pixel_9.0' +SDK="${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" +AVD="${ANDROID_HOME}/cmdline-tools/latest/bin/avdmanager" +EMU="${ANDROID_HOME}/emulator/emulator" +ADB="${ANDROID_HOME}/platform-tools/adb" -echo '' -echo "Installing emulator image ${emulatorImage}" -echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install $emulatorImage +NAME_EMU="android_emulator" +IMG_EMU='system-images;android-28;google_apis;x86' -echo '' -echo "Creating android emulator with name ${avdName}" -echo "no" | $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd -n $avdName -k $emulatorImage --force +# Install AVD files +echo "y" | $SDK --install "${IMG_EMU}" -echo '' -echo 'Listing active android emulators' -$ANDROID_HOME/emulator/emulator -list-avds +# Create emulator +echo "no" | $AVD create avd -n ${NAME_EMU} -k "${IMG_EMU}" --force -echo '' -echo "Starting emulator in background thread" -nohup $ANDROID_HOME/emulator/emulator -avd $avdName -gpu auto -no-snapshot > /dev/null 2>&1 & +echo "" +echo "List AVDs:" +$EMU -list-avds +# Start emulator in background and with no UI (-no-window), as we're only running database tests. +nohup $EMU -avd ${NAME_EMU} -no-window -no-snapshot -no-audio -no-boot-anim > /dev/null 2>&1 & -echo '' -echo 'Waiting for emulator to boot up...' -nohup $ANDROID_HOME/emulator/emulator -avd $avdName -no-snapshot -no-audio -no-boot-anim -accel auto -gpu auto -qemu -lcd-density 420 > /dev/null 2>&1 & -$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do sleep 1; done' -$ANDROID_HOME/platform-tools/adb devices echo "Emulator started" - -$ANDROID_HOME/platform-tools/adb devices - +$ADB wait-for-device +$ADB shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; input keyevent 82' +$ADB devices \ No newline at end of file diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 3db136eacd..30149e91de 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -303,7 +303,7 @@ jobs: - job: AndroidTest timeoutInMinutes: 50 pool: - vmImage: 'macOS-latest' + vmImage: 'macOS-11' strategy: maxParallel: 1 matrix: From 6bbea434fbe91f9b221efb68d11f222432ae0108 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 14:20:13 -0800 Subject: [PATCH 033/114] groups --- .../azure/sdk/iot/androidtest/ExampleTest.java | 4 ++++ .../sdk/iot/androidtest/testgroup/TestGroup1.java | 11 +++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup10.java | 11 +++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup11.java | 11 +++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup12.java | 11 +++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup2.java | 10 ++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup3.java | 10 ++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup4.java | 10 ++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup5.java | 10 ++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup6.java | 11 +++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup7.java | 11 +++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup8.java | 11 +++++++++++ .../sdk/iot/androidtest/testgroup/TestGroup9.java | 11 +++++++++++ vsts/RunTestsOnEmulator.sh | 3 +-- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 4 +++- 15 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java index d68ac2430c..8d25d4106f 100644 --- a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java @@ -2,6 +2,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.microsoft.azure.sdk.iot.androidtest.testgroup.TestGroup1; +import com.microsoft.azure.sdk.iot.androidtest.testgroup.TestGroup2; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -14,11 +16,13 @@ @RunWith(AndroidJUnit4.class) public class ExampleTest { @Test + @TestGroup1 public void shouldPass() { } @Test + @TestGroup2 public void shouldFail() { Assert.fail("lolololol"); } diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java new file mode 100644 index 0000000000..8de46b727d --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java @@ -0,0 +1,11 @@ +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup1 +{ +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java new file mode 100644 index 0000000000..533af07e34 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java @@ -0,0 +1,11 @@ + +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup10 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java new file mode 100644 index 0000000000..278ee9247e --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java @@ -0,0 +1,11 @@ + +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup11 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java new file mode 100644 index 0000000000..af16ec7a91 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java @@ -0,0 +1,11 @@ + +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup12 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java new file mode 100644 index 0000000000..44ec552979 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java @@ -0,0 +1,10 @@ +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup2 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java new file mode 100644 index 0000000000..c612439162 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java @@ -0,0 +1,10 @@ +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup3 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java new file mode 100644 index 0000000000..e4f3ad4db6 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java @@ -0,0 +1,10 @@ +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup4 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java new file mode 100644 index 0000000000..8f3b4b103e --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java @@ -0,0 +1,10 @@ +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup5 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java new file mode 100644 index 0000000000..b17980bf52 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java @@ -0,0 +1,11 @@ + +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup6 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java new file mode 100644 index 0000000000..091f459217 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java @@ -0,0 +1,11 @@ + +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup7 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java new file mode 100644 index 0000000000..f71b5b1818 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java @@ -0,0 +1,11 @@ + +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup8 { +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java new file mode 100644 index 0000000000..8b10c5a6c7 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java @@ -0,0 +1,11 @@ + +package com.microsoft.azure.sdk.iot.androidtest.testgroup; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestGroup9 { +} diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index 12a406d5ca..da4bd3f367 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -22,8 +22,7 @@ echo 'Listing available instrumentations:' adb -e shell pm list instrumentation echo '' -#annotationString="com.microsoft.azure.sdk.iot.android.helper.${TEST_GROUP_ID}" -annotationString="com.microsoft.azure.sdk.iot.android.helper.1" +annotationString="com.microsoft.azure.sdk.iot.androidtest.testgroup.${TEST_GROUP_ID}" echo 'Running android tests with annotation' echo $annotationString diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 30149e91de..f902d5661b 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -303,12 +303,14 @@ jobs: - job: AndroidTest timeoutInMinutes: 50 pool: - vmImage: 'macOS-11' + vmImage: 'macOS-latest' strategy: maxParallel: 1 matrix: TestGroup1: ANDROID_TEST_GROUP_ID: TestGroup1 + TestGroup2: + ANDROID_TEST_GROUP_ID: TestGroup2 displayName: Android Test dependsOn: AndroidBuild From 0ca60e3b65cbdbd9572428e2e9fbc2cc2cad7151 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 14:28:56 -0800 Subject: [PATCH 034/114] default apis --- vsts/StartEmulator.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/StartEmulator.sh b/vsts/StartEmulator.sh index cb13ec21e1..3e71305093 100644 --- a/vsts/StartEmulator.sh +++ b/vsts/StartEmulator.sh @@ -9,7 +9,7 @@ EMU="${ANDROID_HOME}/emulator/emulator" ADB="${ANDROID_HOME}/platform-tools/adb" NAME_EMU="android_emulator" -IMG_EMU='system-images;android-28;google_apis;x86' +IMG_EMU='system-images;android-28;default;x86' # Install AVD files echo "y" | $SDK --install "${IMG_EMU}" From 7bc6b0b7613db59361932e470d75e3cbaae1edb1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 14:51:21 -0800 Subject: [PATCH 035/114] 12 parallel --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index f902d5661b..bc6c228850 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -305,7 +305,7 @@ jobs: pool: vmImage: 'macOS-latest' strategy: - maxParallel: 1 + maxParallel: 12 matrix: TestGroup1: ANDROID_TEST_GROUP_ID: TestGroup1 From c4b997f938cf53dbac47d080eeb5bca1d64d37a5 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 15:08:23 -0800 Subject: [PATCH 036/114] AndroidJUnit4 --- vsts/RunTestsOnEmulator.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index da4bd3f367..e6a584ecd3 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -27,7 +27,7 @@ echo 'Running android tests with annotation' echo $annotationString #Return code from adb shell isn't returned as one would expect. Need to capture output logs and analyze them to determine if this test run was a success or not -TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/android.support.test.runner.AndroidJUnitRunner) +TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/androidx.test.ext.junit.runners.AndroidJUnit4) echo 'Result of running tests' echo "$TestLogs" From 02192e61a0344afb3fd90a18215bf34d9553f814 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 15:27:51 -0800 Subject: [PATCH 037/114] instrumentation? --- vsts/RunTestsOnEmulator.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index e6a584ecd3..4f62cef0a7 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -27,7 +27,7 @@ echo 'Running android tests with annotation' echo $annotationString #Return code from adb shell isn't returned as one would expect. Need to capture output logs and analyze them to determine if this test run was a success or not -TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/androidx.test.ext.junit.runners.AndroidJUnit4) +TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/androidx.test.runner.AndroidJUnitRunner) echo 'Result of running tests' echo "$TestLogs" From 35ed90f9a5ade8ef50a3d679b3723ab290006cb0 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 15:51:35 -0800 Subject: [PATCH 038/114] 15 --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index bc6c228850..7a04ac2a05 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -336,7 +336,7 @@ jobs: - task: Bash@3 #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') displayName: 'Start Android Emulator' - timeoutInMinutes: 60 + timeoutInMinutes: 15 continueOnError: false inputs: targetType: 'filePath' From 00779f13d65ba4175b2242340a66768f5fd905df Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 16:01:18 -0800 Subject: [PATCH 039/114] dep --- iot-e2e-tests/android2/app/build.gradle | 1 + iot-e2e-tests/android2/gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index f159b4b5e6..06eed108f9 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -31,6 +31,7 @@ android { } dependencies { + androidTestImplementation libs.runner implementation libs.appcompat implementation libs.material testImplementation libs.junit diff --git a/iot-e2e-tests/android2/gradle/libs.versions.toml b/iot-e2e-tests/android2/gradle/libs.versions.toml index c3aac0a29c..dcd4625cf4 100644 --- a/iot-e2e-tests/android2/gradle/libs.versions.toml +++ b/iot-e2e-tests/android2/gradle/libs.versions.toml @@ -5,6 +5,7 @@ junitVersion = "1.1.5" espressoCore = "3.5.1" appcompat = "1.6.1" material = "1.10.0" +runner = "1.7.0" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -12,6 +13,7 @@ ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitV espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } +runner = { module = "androidx.test:runner", version.ref = "runner" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 35e1be837bebed3707c24b27b1f19ebece16a646 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 16:28:35 -0800 Subject: [PATCH 040/114] list available instrumentations --- vsts/RunTestsOnEmulator.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index 4f62cef0a7..9a65f5cdf9 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -26,6 +26,8 @@ annotationString="com.microsoft.azure.sdk.iot.androidtest.testgroup.${TEST_GROUP echo 'Running android tests with annotation' echo $annotationString + adb shell pm list instrumentation + #Return code from adb shell isn't returned as one would expect. Need to capture output logs and analyze them to determine if this test run was a success or not TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/androidx.test.runner.AndroidJUnitRunner) From 81e90447ee43932b0d2d06a08dee307e58afa671 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 16:29:02 -0800 Subject: [PATCH 041/114] nevermind --- vsts/RunTestsOnEmulator.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index 9a65f5cdf9..4f62cef0a7 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -26,8 +26,6 @@ annotationString="com.microsoft.azure.sdk.iot.androidtest.testgroup.${TEST_GROUP echo 'Running android tests with annotation' echo $annotationString - adb shell pm list instrumentation - #Return code from adb shell isn't returned as one would expect. Need to capture output logs and analyze them to determine if this test run was a success or not TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/androidx.test.runner.AndroidJUnitRunner) From 3bf161e539ae4e6590f17722c1d0038110876db1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 16:30:10 -0800 Subject: [PATCH 042/114] maybe? --- vsts/RunTestsOnEmulator.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index 4f62cef0a7..4ef5215a85 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -27,7 +27,7 @@ echo 'Running android tests with annotation' echo $annotationString #Return code from adb shell isn't returned as one would expect. Need to capture output logs and analyze them to determine if this test run was a success or not -TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest/androidx.test.runner.AndroidJUnitRunner) +TestLogs=$(adb -e shell am instrument -w -e annotation $annotationString com.microsoft.azure.sdk.iot.androidtest.test/androidx.test.runner.AndroidJUnitRunner) echo 'Result of running tests' echo "$TestLogs" From 61f973de6c1ea15f6cbf9f27fd2016fe4221b11b Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:05:08 -0800 Subject: [PATCH 043/114] one real test --- iot-e2e-tests/android2/app/build.gradle | 26 ++++++++++++++++++- .../ConnectionTestsAndroidRunner.java | 19 ++++++++++++++ ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 23 ++++++++-------- 3 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ConnectionTestsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 06eed108f9..cb87d21ac7 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -14,7 +14,16 @@ android { targetSdk 36 versionCode 1 versionName "1.0" - + each { + buildConfigField STRING, 'IOTHUB_CONNECTION_STRING', IOTHUB_CONNECTION_STRING_ENV_VAR_NAME + buildConfigField STRING, 'IOT_DPS_CONNECTION_STRING', IOT_DPS_CONNECTION_STRING + buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT + buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING + buildConfigField STRING, 'IOT_DPS_ID_SCOPE', DEVICE_PROVISIONING_SERVICE_ID_SCOPE + buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB + buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST + buildConfigField STRING, 'RECYCLE_TEST_IDENTITIES', RECYCLE_TEST_IDENTITIES + } testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -31,10 +40,25 @@ android { } dependencies { + + // This jar contains the test code that will be run on android. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run + implementation files('../../common/target/iot-e2e-common-1.0.0-tests.jar') + + // This jar contains the dependencies of the test code. DeviceClient, for instance. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run + implementation files('../../common/target/iot-e2e-common-1.0.0-with-deps.jar') + + implementation ('org.apache.commons:commons-lang3:3.6') + implementation ('javax.xml.stream:stax-api:1.0-2') + androidTestImplementation libs.runner implementation libs.appcompat implementation libs.material testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core +} + +repositories { + mavenLocal() + mavenCentral() } \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ConnectionTestsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ConnectionTestsAndroidRunner.java new file mode 100644 index 0000000000..6151f7b850 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ConnectionTestsAndroidRunner.java @@ -0,0 +1,19 @@ +package com.microsoft.azure.sdk.iot.androidtest; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.TestGroup11; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.connection.ConnectionTests; + +@TestGroup11 +@RunWith(Parameterized.class) +public class ConnectionTestsAndroidRunner extends ConnectionTests +{ + public ConnectionTestsAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean withProxy) throws Exception + { + super(protocol, authenticationType, clientType, withProxy); + } +} diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 7a04ac2a05..99c9833df0 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -22,7 +22,6 @@ jobs: steps: - task: AzureCLI@2 name: deployCloudTestResources - condition: false inputs: azureSubscription: 'iot hub sdk service connection' scriptType: 'pscore' @@ -238,11 +237,11 @@ jobs: ### Android, Multi configuration build (Multiple different test groups to cover) ### - job: AndroidBuild - #dependsOn: DeployCloudTestResources - #variables: - # IOTHUB_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.IOTHUB_CONNECTION_STRING'] ] - # DPS_IDSCOPE: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.DPS_IDSCOPE'] ] - # PROVISIONING_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.PROVISIONING_CONNECTION_STRING'] ] + dependsOn: DeployCloudTestResources + variables: + IOTHUB_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.IOTHUB_CONNECTION_STRING'] ] + DPS_IDSCOPE: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.DPS_IDSCOPE'] ] + PROVISIONING_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.PROVISIONING_CONNECTION_STRING'] ] timeoutInMinutes: 30 pool: vmImage: ubuntu-latest @@ -269,11 +268,11 @@ jobs: displayName: 'Gradle Build' env: JAVA_VERSION: $(JAVA_VERSION) - #IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) - #IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) - #IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) - #TARGET_BRANCH: $(System.PullRequest.TargetBranch) - #RECYCLE_TEST_IDENTITIES: true + IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) + IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) + IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) + TARGET_BRANCH: $(System.PullRequest.TargetBranch) + RECYCLE_TEST_IDENTITIES: true condition: always() - task: CopyFiles@2 @@ -311,6 +310,8 @@ jobs: ANDROID_TEST_GROUP_ID: TestGroup1 TestGroup2: ANDROID_TEST_GROUP_ID: TestGroup2 + TestGroup11: + ANDROID_TEST_GROUP_ID: TestGroup11 displayName: Android Test dependsOn: AndroidBuild From 67f26cc325ccbdee1b02e6e008043f8a94b2532c Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:12:43 -0800 Subject: [PATCH 044/114] tear down --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 99c9833df0..2c17c1a3c4 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -363,7 +363,6 @@ jobs: condition : always() - job: TearDownCloudTestResources - condition: false dependsOn: - Windows - Linux From 387632d3514c2aec39f4180e08fd240075f1b1ca Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:17:01 -0800 Subject: [PATCH 045/114] vars --- iot-e2e-tests/android2/app/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index cb87d21ac7..5beb07d761 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -17,11 +17,11 @@ android { each { buildConfigField STRING, 'IOTHUB_CONNECTION_STRING', IOTHUB_CONNECTION_STRING_ENV_VAR_NAME buildConfigField STRING, 'IOT_DPS_CONNECTION_STRING', IOT_DPS_CONNECTION_STRING - buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT - buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING + //buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT + //buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING buildConfigField STRING, 'IOT_DPS_ID_SCOPE', DEVICE_PROVISIONING_SERVICE_ID_SCOPE - buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB - buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST + //buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB + //buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST buildConfigField STRING, 'RECYCLE_TEST_IDENTITIES', RECYCLE_TEST_IDENTITIES } testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From 010390c131595f182d3800ce6ccfeb9019693113 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:28:22 -0800 Subject: [PATCH 046/114] string? --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 2c17c1a3c4..2856d78151 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -272,7 +272,7 @@ jobs: IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) TARGET_BRANCH: $(System.PullRequest.TargetBranch) - RECYCLE_TEST_IDENTITIES: true + RECYCLE_TEST_IDENTITIES: "true" condition: always() - task: CopyFiles@2 From 28bfdcf49c7fc5564cffb62ac16c2a853fa3dd78 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:29:15 -0800 Subject: [PATCH 047/114] always tear down --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 2856d78151..94117eeac8 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -363,6 +363,7 @@ jobs: condition : always() - job: TearDownCloudTestResources + condition: always() dependsOn: - Windows - Linux From e73cd3ca509149f45dcc7bb5681424ca03795cb8 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:37:36 -0800 Subject: [PATCH 048/114] depend --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 94117eeac8..fd5d130441 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -367,6 +367,7 @@ jobs: dependsOn: - Windows - Linux + - AndroidTest - DeployCloudTestResources variables: RESOURCE_GROUP_NAME: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.RESOURCE_GROUP_NAME'] ] From d969879f4578729fa9c989b8b7ab21cf4cbca992 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:40:41 -0800 Subject: [PATCH 049/114] derp --- iot-e2e-tests/android2/app/build.gradle | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 5beb07d761..34eb2fdc2f 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -2,6 +2,19 @@ plugins { alias(libs.plugins.android.application) } +//***********************************************************************************************// +def IOTHUB_CONNECTION_STRING_ENV_VAR_NAME = project.hasProperty('IOTHUB_CONNECTION_STRING') ? '"'+project.property('IOTHUB_CONNECTION_STRING')+'"' : '""' +def IOT_DPS_CONNECTION_STRING = project.hasProperty('IOT_DPS_CONNECTION_STRING') ? '"'+project.property('IOT_DPS_CONNECTION_STRING')+'"': '""' +def INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT = project.hasProperty('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT') ? '"'+project.property('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT')+'"': '""' +def INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING = project.hasProperty('PROVISIONING_CONNECTION_STRING_INVALIDCERT') ? '"'+project.property('PROVISIONING_CONNECTION_STRING_INVALIDCERT')+'"': '""' +def DEVICE_PROVISIONING_SERVICE_ID_SCOPE = project.hasProperty('IOT_DPS_ID_SCOPE') ? '"'+project.property('IOT_DPS_ID_SCOPE')+'"': '""' +def IS_BASIC_TIER_HUB = project.hasProperty('IS_BASIC_TIER_HUB') ? '"'+project.property('IS_BASIC_TIER_HUB')+'"' : '"false"' +def IS_PULL_REQUEST = project.hasProperty('IS_PULL_REQUEST') ? '"'+project.property('IS_PULL_REQUEST')+'"' : '"false"' +def RECYCLE_TEST_IDENTITIES = project.hasProperty('RECYCLE_TEST_IDENTITIES') ? '"'+project.property('RECYCLE_TEST_IDENTITIES')+'"' : '"false"' + +def STRING='String' +//***********************************************************************************************// + android { namespace 'com.microsoft.azure.sdk.iot.androidtest' compileSdk { @@ -20,8 +33,8 @@ android { //buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT //buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING buildConfigField STRING, 'IOT_DPS_ID_SCOPE', DEVICE_PROVISIONING_SERVICE_ID_SCOPE - //buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB - //buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST + buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB + buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST buildConfigField STRING, 'RECYCLE_TEST_IDENTITIES', RECYCLE_TEST_IDENTITIES } testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From adebfc92ff779a6ea355e4bfa5a9a5d34e63223e Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 17:51:59 -0800 Subject: [PATCH 050/114] ? --- iot-e2e-tests/android2/settings.gradle | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/iot-e2e-tests/android2/settings.gradle b/iot-e2e-tests/android2/settings.gradle index 437187ca7f..50ec35ed9a 100644 --- a/iot-e2e-tests/android2/settings.gradle +++ b/iot-e2e-tests/android2/settings.gradle @@ -9,13 +9,7 @@ pluginManagement { } mavenCentral() gradlePluginPortal() - } -} -dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) - repositories { - google() - mavenCentral() + mavenLocal() } } From 9b3ff2b2ad6554fbe217d6b3a82f628b43862e06 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 18:16:21 -0800 Subject: [PATCH 051/114] android.buildFeatures.buildConfig = true --- iot-e2e-tests/android2/app/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 34eb2fdc2f..d32e80158c 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -15,12 +15,14 @@ def RECYCLE_TEST_IDENTITIES = project.hasProperty('RECYCLE_TEST_IDENTITIES') ? ' def STRING='String' //***********************************************************************************************// +android.buildFeatures.buildConfig = true + android { namespace 'com.microsoft.azure.sdk.iot.androidtest' compileSdk { version = release(36) } - + defaultConfig { applicationId "com.microsoft.azure.sdk.iot.androidtest" minSdk 24 From 57d6406b24a3358cb42f6d360618bc56f662a8b4 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 18:33:02 -0800 Subject: [PATCH 052/114] google --- iot-e2e-tests/android2/settings.gradle | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/iot-e2e-tests/android2/settings.gradle b/iot-e2e-tests/android2/settings.gradle index 50ec35ed9a..55c8fe60f6 100644 --- a/iot-e2e-tests/android2/settings.gradle +++ b/iot-e2e-tests/android2/settings.gradle @@ -1,12 +1,6 @@ pluginManagement { repositories { - google { - content { - includeGroupByRegex("com\\.android.*") - includeGroupByRegex("com\\.google.*") - includeGroupByRegex("androidx.*") - } - } + google() mavenCentral() gradlePluginPortal() mavenLocal() From c471effe5d9a328f9927d5df033702060e6c046c Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 18:47:56 -0800 Subject: [PATCH 053/114] asdf --- iot-e2e-tests/android2/app/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index d32e80158c..50d53afe60 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -74,6 +74,8 @@ dependencies { } repositories { - mavenLocal() + google() mavenCentral() + gradlePluginPortal() + mavenLocal() } \ No newline at end of file From ea77a8f0664f8fd045648956564739f859b9314b Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 19:10:34 -0800 Subject: [PATCH 054/114] 28 --- iot-e2e-tests/android2/app/build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 50d53afe60..a97ade902a 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -25,8 +25,9 @@ android { defaultConfig { applicationId "com.microsoft.azure.sdk.iot.androidtest" - minSdk 24 - targetSdk 36 + minSdkVersion 24 + targetSdk 28 + multiDexEnabled true versionCode 1 versionName "1.0" each { From 4f3c785934aa5cb7820564f3b067edad81299c6a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 16 Jan 2026 19:37:52 -0800 Subject: [PATCH 055/114] min 26 --- iot-e2e-tests/android2/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index a97ade902a..85354e2c11 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -25,7 +25,7 @@ android { defaultConfig { applicationId "com.microsoft.azure.sdk.iot.androidtest" - minSdkVersion 24 + minSdkVersion 26 targetSdk 28 multiDexEnabled true versionCode 1 From fef5bf74492a80b6640a6485dfe9902a0797c323 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 09:36:08 -0800 Subject: [PATCH 056/114] asdf --- iot-e2e-tests/android2/app/build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 85354e2c11..583e51649e 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -57,9 +57,6 @@ android { dependencies { - // This jar contains the test code that will be run on android. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run - implementation files('../../common/target/iot-e2e-common-1.0.0-tests.jar') - // This jar contains the dependencies of the test code. DeviceClient, for instance. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run implementation files('../../common/target/iot-e2e-common-1.0.0-with-deps.jar') From af6246378dce6e58201f9557bf10d9cf2b1c13d5 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 09:53:37 -0800 Subject: [PATCH 057/114] Revert "asdf" This reverts commit fef5bf74492a80b6640a6485dfe9902a0797c323. --- iot-e2e-tests/android2/app/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 583e51649e..85354e2c11 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -57,6 +57,9 @@ android { dependencies { + // This jar contains the test code that will be run on android. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run + implementation files('../../common/target/iot-e2e-common-1.0.0-tests.jar') + // This jar contains the dependencies of the test code. DeviceClient, for instance. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run implementation files('../../common/target/iot-e2e-common-1.0.0-with-deps.jar') From 9cd8681f8e4b79ef31b6b2110ec94d0714c8ae21 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 10:56:24 -0800 Subject: [PATCH 058/114] dup? --- iot-e2e-tests/common/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index fd7fdfd2f8..a2216fd8ac 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,6 +248,7 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl + com.google.errorprone.annotations:error_prone_annotations From 194a3364a4725913467dc2a21d2c852e7685e871 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 10:58:12 -0800 Subject: [PATCH 059/114] asdf --- iot-e2e-tests/common/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index a2216fd8ac..c6b8bfe2d1 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -249,6 +249,7 @@ org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl com.google.errorprone.annotations:error_prone_annotations + com.google.guava:guava From f9e30e97fd0a997c78721a2d5380346c76878239 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 11:15:23 -0800 Subject: [PATCH 060/114] dup? --- iot-e2e-tests/common/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index c6b8bfe2d1..1a9d57fce0 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,7 +248,8 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl - com.google.errorprone.annotations:error_prone_annotations + com.google.errorprone:error_prone_core + com.google.errorprone:error_prone_annotations com.google.guava:guava From ba3c38ef74fb7522a73c6c58084a0835e44485bd Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 13:58:33 -0800 Subject: [PATCH 061/114] missing --- vsts/gradle_build.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index 0d038bdebd..fb4ea5a8a3 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -17,4 +17,8 @@ Write-Host "Assembling the source APK" # and the emulators have no access to the environment variables on the OS that runs the emulator, # so this is the only way to pass along these secrets. Write-Host "Assembling the test APK with the provided secrets" -./gradlew :app:assembleDebugAndroidTest +./gradlew :app:assembleDebugAndroidTest ` + `-PIOTHUB_CONNECTION_STRING=$env:IOTHUB_CONNECTION_STRING ` + `-PIOT_DPS_CONNECTION_STRING=$env:IOT_DPS_CONNECTION_STRING ` + `-PIOT_DPS_ID_SCOPE=$env:DEVICE_PROVISIONING_SERVICE_ID_SCOPE ` + `-PRECYCLE_TEST_IDENTITIES=true From eb9cd4f1517366e4e4f58dd0115b8b514f73f77b Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 14:24:55 -0800 Subject: [PATCH 062/114] bob --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index fd5d130441..5daa5c3e36 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -270,7 +270,7 @@ jobs: JAVA_VERSION: $(JAVA_VERSION) IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) - IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) + IOTHUB_CONNECTION_STRING: "bob" TARGET_BRANCH: $(System.PullRequest.TargetBranch) RECYCLE_TEST_IDENTITIES: "true" condition: always() From a8e3777abf4d94cbf01bf74314fca81eea25b68b Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 14:54:15 -0800 Subject: [PATCH 063/114] ? --- iot-e2e-tests/android2/app/build.gradle | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 85354e2c11..5950fe4151 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -30,16 +30,14 @@ android { multiDexEnabled true versionCode 1 versionName "1.0" - each { - buildConfigField STRING, 'IOTHUB_CONNECTION_STRING', IOTHUB_CONNECTION_STRING_ENV_VAR_NAME - buildConfigField STRING, 'IOT_DPS_CONNECTION_STRING', IOT_DPS_CONNECTION_STRING - //buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT - //buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING - buildConfigField STRING, 'IOT_DPS_ID_SCOPE', DEVICE_PROVISIONING_SERVICE_ID_SCOPE - buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB - buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST - buildConfigField STRING, 'RECYCLE_TEST_IDENTITIES', RECYCLE_TEST_IDENTITIES - } + buildConfigField STRING, 'IOTHUB_CONNECTION_STRING', IOTHUB_CONNECTION_STRING_ENV_VAR_NAME + buildConfigField STRING, 'IOT_DPS_CONNECTION_STRING', IOT_DPS_CONNECTION_STRING + //buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT + //buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING + buildConfigField STRING, 'IOT_DPS_ID_SCOPE', DEVICE_PROVISIONING_SERVICE_ID_SCOPE + buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB + buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST + buildConfigField STRING, 'RECYCLE_TEST_IDENTITIES', RECYCLE_TEST_IDENTITIES testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } From d01820ddd1148a28ad8300d9916b85240abd38d5 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 15:23:52 -0800 Subject: [PATCH 064/114] ? --- .../integration/com/microsoft/azure/sdk/iot/helpers/Tools.java | 3 ++- .../tests/integration/com/microsoft/azure/sdk/iot/Tools.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java index cd4e229c44..d1fcf789bf 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java @@ -64,7 +64,8 @@ public class Tools private static final long WAIT_FOR_RETRY = 2000; private static boolean IS_ANDROID = false; - private static final String ANDROID_BUILD_CONFIG_CLASS = "com.iothub.azure.microsoft.com.androide2e.test.BuildConfig"; +//TODO this guy? + private static final String ANDROID_BUILD_CONFIG_CLASS = "com.microsoft.azure.sdk.iot.androidtest.test.BuildConfig"; private static final Map ANDROID_ENV_VAR = retrieveAndroidEnvVariables(); public static String retrieveEnvironmentVariableValue(String environmentVariableName) diff --git a/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java b/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java index 8a6dd7c332..487a895c11 100644 --- a/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java +++ b/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java @@ -22,6 +22,7 @@ public class Tools public static final String iotHubConnectionString = retrieveEnvironmentVariableValue(IOT_HUB_CONNECTION_STRING_ENV_VAR_NAME); public static final boolean isBasicTierHub = Boolean.parseBoolean(retrieveEnvironmentVariableValue(IS_BASIC_TIER_HUB_ENV_VAR_NAME)); +//UNUSED? JVM test project private static final String ANDROID_BUILD_CONFIG_CLASS = "com.iothub.azure.microsoft.com.androide2e.test.BuildConfig"; public static String retrieveEnvironmentVariableValue(String environmentVariableName) From 8359d6ce484faae70ba180a5f355ea19bb3ae61c Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Mon, 19 Jan 2026 15:47:56 -0800 Subject: [PATCH 065/114] no bob --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 5daa5c3e36..fd5d130441 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -270,7 +270,7 @@ jobs: JAVA_VERSION: $(JAVA_VERSION) IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) - IOTHUB_CONNECTION_STRING: "bob" + IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) TARGET_BRANCH: $(System.PullRequest.TargetBranch) RECYCLE_TEST_IDENTITIES: "true" condition: always() From 016e2139aa73f4ba65b56e03587019dff3529289 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 10:33:11 -0800 Subject: [PATCH 066/114] deps list --- iot-e2e-tests/common/pom.xml | 3 --- vsts/gradle_build.ps1 | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index 1a9d57fce0..fd7fdfd2f8 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,9 +248,6 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl - com.google.errorprone:error_prone_core - com.google.errorprone:error_prone_annotations - com.google.guava:guava diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index fb4ea5a8a3..bf96088b47 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -12,6 +12,9 @@ Write-Host "Starting the Gradle Wrapper" Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug +Write-Host "Android dependencies:" +./gradlew app:dependencies + # Unlike in the Linux/Windows e2e tests, these secrets are loaded into the Android BuildConfig.java # file that is generated during this assembly. This is done because the android tests run on emulators # and the emulators have no access to the environment variables on the OS that runs the emulator, From b1e2e2f42a308cdb9699e61ce589bc6018705dcd Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 10:54:35 -0800 Subject: [PATCH 067/114] ? --- iot-e2e-tests/android2/app/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 5950fe4151..b7abb91806 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,6 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') + implementation ('com.google.guava:guava:32.0.0-jre') androidTestImplementation libs.runner implementation libs.appcompat From a62b379a1887cd4833d4d8d52f77eae57810f5df Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 10:58:04 -0800 Subject: [PATCH 068/114] latest? --- iot-e2e-tests/android2/app/build.gradle | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index b7abb91806..cc98010ba4 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - implementation ('com.google.guava:guava:32.0.0-jre') + //implementation ('com.google.guava:guava:33.3.1-jre') androidTestImplementation libs.runner implementation libs.appcompat diff --git a/pom.xml b/pom.xml index 20b1149a89..754a66ba45 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ com.google.guava guava - 32.0.0-jre + 33.3.1-jre com.fasterxml.woodstox From 4c64ec702015081ba357d6d49c6490ee53093ef5 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 11:00:16 -0800 Subject: [PATCH 069/114] latest in android proj too --- iot-e2e-tests/android2/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index cc98010ba4..c155a0ad40 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - //implementation ('com.google.guava:guava:33.3.1-jre') + implementation ('com.google.guava:guava:33.3.1-jre') androidTestImplementation libs.runner implementation libs.appcompat From 59efb4492b6b2a1ab56c0b0239edad240fc73a68 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 11:23:23 -0800 Subject: [PATCH 070/114] andr --- iot-e2e-tests/android2/app/build.gradle | 2 +- iot-e2e-tests/common/pom.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index c155a0ad40..0a5c461ebe 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - implementation ('com.google.guava:guava:33.3.1-jre') + implementation ('com.google.guava:guava:33.3.1-android') androidTestImplementation libs.runner implementation libs.appcompat diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index fd7fdfd2f8..238cdc4a0d 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,6 +248,7 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl + com.google.guava:guava:33.3.1-jre From d4ec174a5f9be7c80d54ac7014eda523a522b769 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 11:52:03 -0800 Subject: [PATCH 071/114] ? --- iot-e2e-tests/android2/app/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 0a5c461ebe..b2840976df 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -71,6 +71,12 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core + + modules { + module("com.google.guava:listenablefuture") { + replacedBy("com.google.guava:guava", "listenablefuture is part of guava") + } + } } repositories { From f9f449b4269abaf6ff7a359406d106ae7d5e6393 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 12:06:43 -0800 Subject: [PATCH 072/114] ? --- iot-e2e-tests/android2/app/build.gradle | 1 - iot-e2e-tests/common/pom.xml | 1 - 2 files changed, 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index b2840976df..d1ff2716e0 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,6 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - implementation ('com.google.guava:guava:33.3.1-android') androidTestImplementation libs.runner implementation libs.appcompat diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index 238cdc4a0d..fd7fdfd2f8 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,7 +248,6 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl - com.google.guava:guava:33.3.1-jre From ace5f34d3c4f329e5f50fcb86f267d25528691ac Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 13:59:52 -0800 Subject: [PATCH 073/114] back to 6.8.3 --- iot-e2e-tests/android2/app/build.gradle | 6 ------ vsts/gradle_build.ps1 | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index d1ff2716e0..5950fe4151 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -70,12 +70,6 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core - - modules { - module("com.google.guava:listenablefuture") { - replacedBy("com.google.guava:guava", "listenablefuture is part of guava") - } - } } repositories { diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index bf96088b47..b6aa9df35d 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -3,11 +3,11 @@ cd iot-e2e-tests\android2 # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions -Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-bin.zip" -OutFile ./gradle.zip +Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-6.8.3-bin.zip" -OutFile ./gradle.zip Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-9.2.1/bin/gradle wrapper --stacktrace +./gradle/gradle-6.8.3/bin/gradle wrapper --stacktrace Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From 29021b4c5b379389856ac2361a185b73fbfde0d4 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 14:41:41 -0800 Subject: [PATCH 074/114] back to 9.2.1 --- vsts/gradle_build.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index b6aa9df35d..bf96088b47 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -3,11 +3,11 @@ cd iot-e2e-tests\android2 # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions -Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-6.8.3-bin.zip" -OutFile ./gradle.zip +Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-bin.zip" -OutFile ./gradle.zip Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-6.8.3/bin/gradle wrapper --stacktrace +./gradle/gradle-9.2.1/bin/gradle wrapper --stacktrace Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From 3c463c1439e7d3ad493d8d0db57970dc8da52e01 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:25:54 -0800 Subject: [PATCH 075/114] Revert "back to 9.2.1" This reverts commit 29021b4c5b379389856ac2361a185b73fbfde0d4. --- vsts/gradle_build.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index bf96088b47..b6aa9df35d 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -3,11 +3,11 @@ cd iot-e2e-tests\android2 # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions -Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-bin.zip" -OutFile ./gradle.zip +Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-6.8.3-bin.zip" -OutFile ./gradle.zip Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-9.2.1/bin/gradle wrapper --stacktrace +./gradle/gradle-6.8.3/bin/gradle wrapper --stacktrace Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From 8fccb1ab1cda77cb47e5eca42ee4a7b39d992208 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:25:57 -0800 Subject: [PATCH 076/114] Revert "back to 6.8.3" This reverts commit ace5f34d3c4f329e5f50fcb86f267d25528691ac. --- iot-e2e-tests/android2/app/build.gradle | 6 ++++++ vsts/gradle_build.ps1 | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 5950fe4151..d1ff2716e0 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -70,6 +70,12 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core + + modules { + module("com.google.guava:listenablefuture") { + replacedBy("com.google.guava:guava", "listenablefuture is part of guava") + } + } } repositories { diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index b6aa9df35d..bf96088b47 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -3,11 +3,11 @@ cd iot-e2e-tests\android2 # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions -Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-6.8.3-bin.zip" -OutFile ./gradle.zip +Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-9.2.1-bin.zip" -OutFile ./gradle.zip Expand-Archive ./gradle.zip Write-Host "Starting the Gradle Wrapper" -./gradle/gradle-6.8.3/bin/gradle wrapper --stacktrace +./gradle/gradle-9.2.1/bin/gradle wrapper --stacktrace Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug From 112dd1a6f00daf569c64f1bd316a3fe35ea9185f Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:00 -0800 Subject: [PATCH 077/114] Revert "?" This reverts commit f9f449b4269abaf6ff7a359406d106ae7d5e6393. --- iot-e2e-tests/android2/app/build.gradle | 1 + iot-e2e-tests/common/pom.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index d1ff2716e0..b2840976df 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,6 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') + implementation ('com.google.guava:guava:33.3.1-android') androidTestImplementation libs.runner implementation libs.appcompat diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index fd7fdfd2f8..238cdc4a0d 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,6 +248,7 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl + com.google.guava:guava:33.3.1-jre From a162e39566e920f5ce0d387d1a1efd7f61262a7e Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:03 -0800 Subject: [PATCH 078/114] Revert "?" This reverts commit d4ec174a5f9be7c80d54ac7014eda523a522b769. --- iot-e2e-tests/android2/app/build.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index b2840976df..0a5c461ebe 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -71,12 +71,6 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core - - modules { - module("com.google.guava:listenablefuture") { - replacedBy("com.google.guava:guava", "listenablefuture is part of guava") - } - } } repositories { From 25d406e22887f3fa54007c4280347bcfe2e2e9a7 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:05 -0800 Subject: [PATCH 079/114] Revert "andr" This reverts commit 59efb4492b6b2a1ab56c0b0239edad240fc73a68. --- iot-e2e-tests/android2/app/build.gradle | 2 +- iot-e2e-tests/common/pom.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index 0a5c461ebe..c155a0ad40 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - implementation ('com.google.guava:guava:33.3.1-android') + implementation ('com.google.guava:guava:33.3.1-jre') androidTestImplementation libs.runner implementation libs.appcompat diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index 238cdc4a0d..fd7fdfd2f8 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,7 +248,6 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl - com.google.guava:guava:33.3.1-jre From d75369e155e5d2982542fdf3b05bba6a450a26f6 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:07 -0800 Subject: [PATCH 080/114] Revert "latest in android proj too" This reverts commit 4c64ec702015081ba357d6d49c6490ee53093ef5. --- iot-e2e-tests/android2/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index c155a0ad40..cc98010ba4 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - implementation ('com.google.guava:guava:33.3.1-jre') + //implementation ('com.google.guava:guava:33.3.1-jre') androidTestImplementation libs.runner implementation libs.appcompat From 990845535b1f5c4b0ed42bd16a22fddadfd5e21c Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:14 -0800 Subject: [PATCH 081/114] Revert "latest?" This reverts commit a62b379a1887cd4833d4d8d52f77eae57810f5df. --- iot-e2e-tests/android2/app/build.gradle | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index cc98010ba4..b7abb91806 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,7 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - //implementation ('com.google.guava:guava:33.3.1-jre') + implementation ('com.google.guava:guava:32.0.0-jre') androidTestImplementation libs.runner implementation libs.appcompat diff --git a/pom.xml b/pom.xml index 754a66ba45..20b1149a89 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ com.google.guava guava - 33.3.1-jre + 32.0.0-jre com.fasterxml.woodstox From 7e4e997b14d550c2c5bf14f3e1b99dd6fadd0101 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:17 -0800 Subject: [PATCH 082/114] Revert "?" This reverts commit b1e2e2f42a308cdb9699e61ce589bc6018705dcd. --- iot-e2e-tests/android2/app/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle index b7abb91806..5950fe4151 100644 --- a/iot-e2e-tests/android2/app/build.gradle +++ b/iot-e2e-tests/android2/app/build.gradle @@ -63,7 +63,6 @@ dependencies { implementation ('org.apache.commons:commons-lang3:3.6') implementation ('javax.xml.stream:stax-api:1.0-2') - implementation ('com.google.guava:guava:32.0.0-jre') androidTestImplementation libs.runner implementation libs.appcompat From 9156777be852e6fe116a12b9beec3e450d2e6655 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:20 -0800 Subject: [PATCH 083/114] Revert "deps list" This reverts commit 016e2139aa73f4ba65b56e03587019dff3529289. --- iot-e2e-tests/common/pom.xml | 3 +++ vsts/gradle_build.ps1 | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index fd7fdfd2f8..1a9d57fce0 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -248,6 +248,9 @@ org.apache.logging.log4j:log4j-api org.apache.logging.log4j:log4j-core org.apache.logging.log4j:log4j-slf4j-impl + com.google.errorprone:error_prone_core + com.google.errorprone:error_prone_annotations + com.google.guava:guava diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index bf96088b47..fb4ea5a8a3 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -12,9 +12,6 @@ Write-Host "Starting the Gradle Wrapper" Write-Host "Assembling the source APK" ./gradlew :app:assembleDebug -Write-Host "Android dependencies:" -./gradlew app:dependencies - # Unlike in the Linux/Windows e2e tests, these secrets are loaded into the Android BuildConfig.java # file that is generated during this assembly. This is done because the android tests run on emulators # and the emulators have no access to the environment variables on the OS that runs the emulator, From 1806aab91fed0160b6c63a79f80740b6270e59e3 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:26:22 -0800 Subject: [PATCH 084/114] Revert "no bob" This reverts commit 8359d6ce484faae70ba180a5f355ea19bb3ae61c. --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index fd5d130441..5daa5c3e36 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -270,7 +270,7 @@ jobs: JAVA_VERSION: $(JAVA_VERSION) IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) - IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) + IOTHUB_CONNECTION_STRING: "bob" TARGET_BRANCH: $(System.PullRequest.TargetBranch) RECYCLE_TEST_IDENTITIES: "true" condition: always() From f8ceb79d526df57854b4dc94228c22ecce6d5d0c Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:43:11 -0800 Subject: [PATCH 085/114] proxy lib --- .../digitaltwin/DigitalTwinClientTests.java | 10 +- .../iot/helpers/BasicProxyAuthenticator.java | 37 - .../iot/helpers/proxy/ActivityTracker.java | 155 -- .../helpers/proxy/ActivityTrackerAdapter.java | 68 - .../sdk/iot/helpers/proxy/ChainedProxy.java | 77 - .../helpers/proxy/ChainedProxyAdapter.java | 64 - .../helpers/proxy/ChainedProxyManager.java | 38 - .../helpers/proxy/DefaultHostResolver.java | 19 - .../sdk/iot/helpers/proxy/FlowContext.java | 46 - .../iot/helpers/proxy/FullFlowContext.java | 40 - .../sdk/iot/helpers/proxy/HostResolver.java | 12 - .../sdk/iot/helpers/proxy/HttpFilters.java | 211 --- .../iot/helpers/proxy/HttpFiltersAdapter.java | 106 -- .../iot/helpers/proxy/HttpFiltersSource.java | 50 - .../proxy/HttpFiltersSourceAdapter.java | 32 - .../iot/helpers/proxy/HttpProxyServer.java | 67 - .../proxy/HttpProxyServerBootstrap.java | 338 ---- .../sdk/iot/helpers/proxy/MitmManager.java | 54 - .../iot/helpers/proxy/ProxyAuthenticator.java | 28 - .../iot/helpers/proxy/SslEngineSource.java | 33 - .../iot/helpers/proxy/TransportProtocol.java | 8 - .../UnknownTransportProtocolException.java | 12 - .../proxy/extras/SelfSignedMitmManager.java | 31 - .../extras/SelfSignedSslEngineSource.java | 207 --- .../proxy/impl/CategorizedThreadFactory.java | 52 - .../proxy/impl/ClientToProxyConnection.java | 1432 ----------------- .../helpers/proxy/impl/ConnectionFlow.java | 219 --- .../proxy/impl/ConnectionFlowStep.java | 116 -- .../helpers/proxy/impl/ConnectionState.java | 81 - .../proxy/impl/DefaultHttpProxyServer.java | 905 ----------- .../iot/helpers/proxy/impl/NetworkUtils.java | 47 - .../helpers/proxy/impl/ProxyConnection.java | 834 ---------- .../helpers/proxy/impl/ProxyThreadPools.java | 64 - .../proxy/impl/ProxyToServerConnection.java | 1009 ------------ .../iot/helpers/proxy/impl/ProxyUtils.java | 640 -------- .../iot/helpers/proxy/impl/ServerGroup.java | 291 ---- .../proxy/impl/ThreadPoolConfiguration.java | 62 - .../azure/sdk/iot/helpers/proxy/readme.md | 5 - .../azure/sdk/iot/iothub/FileUploadTests.java | 10 +- .../iot/iothub/MultiplexingClientTests.java | 12 +- .../sdk/iot/iothub/TokenRenewalTests.java | 11 +- .../iothub/connection/ConnectionTests.java | 11 +- .../iot/iothub/setup/SendMessagesCommon.java | 2 - iot-e2e-tests/pom.xml | 9 + 44 files changed, 29 insertions(+), 7526 deletions(-) delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTracker.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTrackerAdapter.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxy.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyAdapter.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyManager.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/DefaultHostResolver.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FlowContext.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FullFlowContext.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HostResolver.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFilters.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersAdapter.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSource.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSourceAdapter.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServer.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServerBootstrap.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/MitmManager.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ProxyAuthenticator.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/SslEngineSource.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/TransportProtocol.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/UnknownTransportProtocolException.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedMitmManager.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedSslEngineSource.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/CategorizedThreadFactory.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ClientToProxyConnection.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlow.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlowStep.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionState.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/DefaultHttpProxyServer.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/NetworkUtils.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyConnection.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyThreadPools.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyToServerConnection.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyUtils.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ServerGroup.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ThreadPoolConfiguration.java delete mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/readme.md diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/digitaltwin/DigitalTwinClientTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/digitaltwin/DigitalTwinClientTests.java index 7ddecea86b..13e9170bfb 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/digitaltwin/DigitalTwinClientTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/digitaltwin/DigitalTwinClientTests.java @@ -3,6 +3,7 @@ package tests.integration.com.microsoft.azure.sdk.iot.digitaltwin; +import com.github.monkeywie.proxyee.server.HttpProxyServer; import com.google.gson.JsonElement; import com.microsoft.azure.sdk.iot.device.*; import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException; @@ -36,8 +37,6 @@ import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.DigitalTwinTest; import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.IotHubTest; import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.StandardTierHubOnlyTest; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.DefaultHttpProxyServer; import java.io.IOException; import java.net.URISyntaxException; @@ -135,15 +134,14 @@ private DeviceClient createDeviceClient(IotHubClientProtocol protocol, String mo @BeforeClass public static void startProxy() { - proxyServer = DefaultHttpProxyServer.bootstrap() - .withPort(testProxyPort) - .start(); + proxyServer = new HttpProxyServer(); + proxyServer.start(testProxyPort); } @AfterClass public static void stopProxy() { - proxyServer.stop(); + proxyServer.close(); } // Open a multiplexed connection with two devices, each with a different model Id. Verify that their reported twin has diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java deleted file mode 100644 index fc4b5b130e..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package tests.integration.com.microsoft.azure.sdk.iot.helpers; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.ProxyAuthenticator; - -public class BasicProxyAuthenticator implements ProxyAuthenticator -{ - private final String expectedUsername; - private final String expectedPassword; - - public BasicProxyAuthenticator(String expectedUsername, char[] expectedPassword) - { - this.expectedUsername = expectedUsername; - this.expectedPassword = new String(expectedPassword); - } - - @Override - public boolean authenticate(String username, String password) - { - if (username == null || password == null) - { - return false; - } - - return username.equals(expectedUsername) && password.equals(expectedPassword); - } - - @Override - public String getRealm() - { - return null; - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTracker.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTracker.java deleted file mode 100644 index cb37c196b7..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTracker.java +++ /dev/null @@ -1,155 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; - -import javax.net.ssl.SSLSession; -import java.net.InetSocketAddress; - -/** - *

- * Interface for receiving information about activity in the proxy. - *

- * - *

- * Sub-classes may wish to extend {@link ActivityTrackerAdapter} for sensible - * defaults. - *

- */ -public interface ActivityTracker { - - /** - * Record that a client connected. - * - * @param clientAddress - */ - void clientConnected(InetSocketAddress clientAddress); - - /** - * Record that a client's SSL handshake completed. - * - * @param clientAddress - * @param sslSession - */ - void clientSSLHandshakeSucceeded(InetSocketAddress clientAddress, - SSLSession sslSession); - - /** - * Record that a client disconnected. - * - * @param clientAddress - * @param sslSession - */ - void clientDisconnected(InetSocketAddress clientAddress, - SSLSession sslSession); - - /** - * Record that the proxy received bytes from the client. - * - * @param flowContext - * if full information is available, this will be a - * {@link FullFlowContext}. - * @param numberOfBytes - */ - void bytesReceivedFromClient(FlowContext flowContext, - int numberOfBytes); - - /** - *

- * Record that proxy received an {@link HttpRequest} from the client. - *

- * - *

- * Note - on chunked transfers, this is only called once (for the initial - * HttpRequest object). - *

- * - * @param flowContext - * if full information is available, this will be a - * {@link FullFlowContext}. - * @param httpRequest - */ - void requestReceivedFromClient(FlowContext flowContext, - HttpRequest httpRequest); - - /** - * Record that the proxy attempted to send bytes to the server. - * - * @param flowContext - * provides contextual information about the flow - * @param numberOfBytes - */ - void bytesSentToServer(FullFlowContext flowContext, int numberOfBytes); - - /** - *

- * Record that proxy attempted to send a request to the server. - *

- * - *

- * Note - on chunked transfers, this is only called once (for the initial - * HttpRequest object). - *

- * - * @param flowContext - * provides contextual information about the flow - * @param httpRequest - */ - void requestSentToServer(FullFlowContext flowContext, - HttpRequest httpRequest); - - /** - * Record that the proxy received bytes from the server. - * - * @param flowContext - * provides contextual information about the flow - * @param numberOfBytes - */ - void bytesReceivedFromServer(FullFlowContext flowContext, int numberOfBytes); - - /** - *

- * Record that the proxy received an {@link HttpResponse} from the server. - *

- * - *

- * Note - on chunked transfers, this is only called once (for the initial - * HttpRequest object). - *

- * - * @param flowContext - * provides contextual information about the flow - * @param httpResponse - */ - void responseReceivedFromServer(FullFlowContext flowContext, - HttpResponse httpResponse); - - /** - * Record that the proxy sent bytes to the client. - * - * @param flowContext - * if full information is available, this will be a - * {@link FullFlowContext}. - * @param numberOfBytes - */ - void bytesSentToClient(FlowContext flowContext, int numberOfBytes); - - /** - *

- * Record that the proxy sent a response to the client. - *

- * - *

- * Note - on chunked transfers, this is only called once (for the initial - * HttpRequest object). - *

- * - * @param flowContext - * if full information is available, this will be a - * {@link FullFlowContext}. - * @param httpResponse - */ - void responseSentToClient(FlowContext flowContext, - HttpResponse httpResponse); - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTrackerAdapter.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTrackerAdapter.java deleted file mode 100644 index c74ebcefce..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ActivityTrackerAdapter.java +++ /dev/null @@ -1,68 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; - -import javax.net.ssl.SSLSession; -import java.net.InetSocketAddress; - -/** - * Adapter of {@link ActivityTracker} interface that provides default no-op - * implementations of all methods. - */ -public class ActivityTrackerAdapter implements ActivityTracker { - - @Override - public void bytesReceivedFromClient(FlowContext flowContext, - int numberOfBytes) { - } - - @Override - public void requestReceivedFromClient(FlowContext flowContext, - HttpRequest httpRequest) { - } - - @Override - public void bytesSentToServer(FullFlowContext flowContext, int numberOfBytes) { - } - - @Override - public void requestSentToServer(FullFlowContext flowContext, - HttpRequest httpRequest) { - } - - @Override - public void bytesReceivedFromServer(FullFlowContext flowContext, - int numberOfBytes) { - } - - @Override - public void responseReceivedFromServer(FullFlowContext flowContext, - HttpResponse httpResponse) { - } - - @Override - public void bytesSentToClient(FlowContext flowContext, - int numberOfBytes) { - } - - @Override - public void responseSentToClient(FlowContext flowContext, - HttpResponse httpResponse) { - } - - @Override - public void clientConnected(InetSocketAddress clientAddress) { - } - - @Override - public void clientSSLHandshakeSucceeded(InetSocketAddress clientAddress, - SSLSession sslSession) { - } - - @Override - public void clientDisconnected(InetSocketAddress clientAddress, - SSLSession sslSession) { - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxy.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxy.java deleted file mode 100644 index b1545e66ff..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxy.java +++ /dev/null @@ -1,77 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.handler.codec.http.HttpObject; - -import java.net.InetSocketAddress; - -/** - *

- * Encapsulates information needed to connect to a chained proxy. - *

- * - *

- * Sub-classes may wish to extend {@link ChainedProxyAdapter} for sensible - * defaults. - *

- */ -public interface ChainedProxy extends SslEngineSource -{ - /** - * Return the {@link InetSocketAddress} for connecting to the chained proxy. - * Returning null indicates that we won't chain. - * - * @return The Chain Proxy with Host and Port. - */ - InetSocketAddress getChainedProxyAddress(); - - /** - * (Optional) ensure that the connection is opened from a specific local - * address (useful when doing NAT traversal). - * - * @return - */ - InetSocketAddress getLocalAddress(); - - /** - * Tell LittleProxy what kind of TransportProtocol to use to communicate - * with the chained proxy. - * - * @return - */ - TransportProtocol getTransportProtocol(); - - /** - * Implement this method to tell LittleProxy whether or not to encrypt - * connections to the chained proxy for the given request. If true, - * LittleProxy will call {@link SslEngineSource#newSslEngine()} to obtain an - * SSLContext used by the downstream proxy. - * - * @return true of the connection to the chained proxy should be encrypted - */ - boolean requiresEncryption(); - - /** - * Filters requests on their way to the chained proxy. - * - * @param httpObject - */ - void filterRequest(HttpObject httpObject); - - /** - * Called to let us know that connecting to this proxy succeeded. - */ - void connectionSucceeded(); - - /** - * Called to let us know that connecting to this proxy failed. - * - * @param cause - * exception that caused this failure (may be null) - */ - void connectionFailed(Throwable cause); - - /** - * Called to let us know that we were disconnected. - */ - void disconnected(); -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyAdapter.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyAdapter.java deleted file mode 100644 index 089b189bb8..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyAdapter.java +++ /dev/null @@ -1,64 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.handler.codec.http.HttpObject; - -import javax.net.ssl.SSLEngine; -import java.net.InetSocketAddress; - -/** - * Convenience base class for implementations of {@link ChainedProxy}. - */ -public class ChainedProxyAdapter implements ChainedProxy -{ - /** - * {@link ChainedProxy} that simply has the downstream proxy make a direct - * connection to the upstream server. - */ - public static ChainedProxy FALLBACK_TO_DIRECT_CONNECTION = new ChainedProxyAdapter(); - - @Override - public InetSocketAddress getChainedProxyAddress() { - return null; - } - - @Override - public InetSocketAddress getLocalAddress() { - return null; - } - - @Override - public TransportProtocol getTransportProtocol() { - return TransportProtocol.TCP; - } - - @Override - public boolean requiresEncryption() { - return false; - } - - @Override - public SSLEngine newSslEngine() { - return null; - } - - @Override - public void filterRequest(HttpObject httpObject) { - } - - @Override - public void connectionSucceeded() { - } - - @Override - public void connectionFailed(Throwable cause) { - } - - @Override - public void disconnected() { - } - - @Override - public SSLEngine newSslEngine(String peerHost, int peerPort) { - return null; - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyManager.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyManager.java deleted file mode 100644 index 97c8d36e3d..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ChainedProxyManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.handler.codec.http.HttpRequest; - -import java.util.Queue; - -/** - *

- * Interface for classes that manage chained proxies. - *

- */ -public interface ChainedProxyManager { - - /** - *

- * Based on the given httpRequest, add any {@link ChainedProxy}s to the list - * that should be used to process the request. The downstream proxy will - * attempt to connect to each of these in the order that they appear until - * it successfully connects to one. - *

- * - *

- * To allow the proxy to fall back to a direct connection, you can add - * {@link ChainedProxyAdapter#FALLBACK_TO_DIRECT_CONNECTION} to the end of - * the list. - *

- * - *

- * To keep the proxy from attempting any connection, leave the list blank. - * This will cause the proxy to return a 502 response. - *

- * - * @param httpRequest - * @param chainedProxies - */ - void lookupChainedProxies(HttpRequest httpRequest, - Queue chainedProxies); -} \ No newline at end of file diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/DefaultHostResolver.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/DefaultHostResolver.java deleted file mode 100644 index cddd8e8d16..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/DefaultHostResolver.java +++ /dev/null @@ -1,19 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; - -/** - * Default implementation of {@link HostResolver} that just uses - * {@link InetAddress#getByName(String)}. - */ -public class DefaultHostResolver implements HostResolver -{ - @Override - public InetSocketAddress resolve(String host, int port) - throws UnknownHostException { - InetAddress addr = InetAddress.getByName(host); - return new InetSocketAddress(addr, port); - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FlowContext.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FlowContext.java deleted file mode 100644 index a7c7b7d154..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FlowContext.java +++ /dev/null @@ -1,46 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ClientToProxyConnection; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSession; -import java.net.InetSocketAddress; - -/** - *

- * Encapsulates contextual information for flow information that's being - * reported to a {@link ActivityTracker}. - *

- */ -public class FlowContext { - private final InetSocketAddress clientAddress; - private final SSLSession clientSslSession; - - public FlowContext(ClientToProxyConnection clientConnection) { - super(); - this.clientAddress = clientConnection.getClientAddress(); - SSLEngine sslEngine = clientConnection.getSslEngine(); - this.clientSslSession = sslEngine != null ? sslEngine.getSession() - : null; - } - - /** - * The address of the client. - * - * @return - */ - public InetSocketAddress getClientAddress() { - return clientAddress; - } - - /** - * If using SSL, this returns the {@link SSLSession} on the client - * connection. - * - * @return - */ - public SSLSession getClientSslSession() { - return clientSslSession; - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FullFlowContext.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FullFlowContext.java deleted file mode 100644 index e4ae61d123..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/FullFlowContext.java +++ /dev/null @@ -1,40 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ClientToProxyConnection; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ProxyToServerConnection; - -/** - * Extension of {@link FlowContext} that provides additional information (which - * we know after actually processing the request from the client). - */ -public class FullFlowContext extends FlowContext -{ - private final String serverHostAndPort; - private final ChainedProxy chainedProxy; - - public FullFlowContext(ClientToProxyConnection clientConnection, - ProxyToServerConnection serverConnection) { - super(clientConnection); - this.serverHostAndPort = serverConnection.getServerHostAndPort(); - this.chainedProxy = serverConnection.getChainedProxy(); - } - - /** - * The host and port for the server (i.e. the ultimate endpoint). - * - * @return - */ - public String getServerHostAndPort() { - return serverHostAndPort; - } - - /** - * The chained proxy (if proxy chaining). - * - * @return - */ - public ChainedProxy getChainedProxy() { - return chainedProxy; - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HostResolver.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HostResolver.java deleted file mode 100644 index a42eec5a9c..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HostResolver.java +++ /dev/null @@ -1,12 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import java.net.InetSocketAddress; -import java.net.UnknownHostException; - -/** - * Resolves host and port into an InetSocketAddress. - */ -public interface HostResolver { - public InetSocketAddress resolve(String host, int port) - throws UnknownHostException; -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFilters.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFilters.java deleted file mode 100644 index 703068cbac..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFilters.java +++ /dev/null @@ -1,211 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.*; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ProxyUtils; - -import java.net.InetSocketAddress; - -/** - *

- * Interface for objects that filter {@link HttpObject}s, including both - * requests and responses, and informs of different steps in request/response. - *

- * - *

- * Multiple methods are defined, corresponding to different steps in the request - * processing lifecycle. Some of these methods is given the current object - * (request, response or chunk) and is allowed to modify it in place. Others - * provide a notification of when specific operations happen (i.e. connection in - * queue, DNS resolution, SSL handshaking and so forth). - *

- * - *

- * Because HTTP transfers can be chunked, for any given request or response, the - * filter methods that can modify request/response in place may be called - * multiple times, once for the initial {@link HttpRequest} or - * {@link HttpResponse}, and once for each subsequent {@link HttpContent}. The - * last chunk will always be a {@link LastHttpContent} and can be checked for - * being last using {@link ProxyUtils#isLastChunk(HttpObject)}. - *

- * - *

- * {@link HttpFiltersSource#getMaximumRequestBufferSizeInBytes()} and - * {@link HttpFiltersSource#getMaximumResponseBufferSizeInBytes()} can be used - * to instruct the proxy to buffer the {@link HttpObject}s sent to all of its - * request/response filters, in which case it will buffer up to the specified - * limit and then send either complete {@link HttpRequest}s or - * {@link HttpResponse}s to the filter methods. When buffering, if the proxy - * receives more data than fits in the specified maximum bytes to buffer, the - * proxy will stop processing the request and respond with a 502 Bad Gateway - * error. - *

- * - *

- * A new instance of {@link HttpFilters} is created for each request, so these - * objects can be stateful. - *

- * - *

- * To monitor (and time measure?) the different steps the request/response goes - * through, many informative methods are provided. Those steps are reported in - * the following order: - *

    - *
  1. clientToProxyRequest
  2. - *
  3. proxyToServerConnectionQueued
  4. - *
  5. proxyToServerResolutionStarted
  6. - *
  7. proxyToServerResolutionSucceeded
  8. - *
  9. proxyToServerRequest (can be multiple if chunked)
  10. - *
  11. proxyToServerConnectionStarted
  12. - *
  13. proxyToServerConnectionFailed (if connection couldn't be established)
  14. - *
  15. proxyToServerConnectionSSLHandshakeStarted (only if HTTPS required)
  16. - *
  17. proxyToServerConnectionSucceeded
  18. - *
  19. proxyToServerRequestSending
  20. - *
  21. proxyToServerRequestSent
  22. - *
  23. serverToProxyResponseReceiving
  24. - *
  25. serverToProxyResponse (can be multiple if chuncked)
  26. - *
  27. serverToProxyResponseReceived
  28. - *
  29. proxyToClientResponse
  30. - *
- */ -public interface HttpFilters { - /** - * Filters requests on their way from the client to the proxy. To interrupt processing of this request and return a - * response to the client immediately, return an HttpResponse here. Otherwise, return null to continue processing as - * usual. - *

- * Important: When returning a response, you must include a mechanism to allow the client to determine the length - * of the message (see RFC 7230, section 3.3.3: https://tools.ietf.org/html/rfc7230#section-3.3.3 ). For messages that - * may contain a body, you may do this by setting the Transfer-Encoding to chunked, setting an appropriate - * Content-Length, or by adding a "Connection: close" header to the response (which will instruct LittleProxy to close - * the connection). If the short-circuit response contains body content, it is recommended that you return a - * FullHttpResponse. - * - * @param httpObject Client to Proxy HttpRequest (and HttpContent, if chunked) - * @return a short-circuit response, or null to continue processing as usual - */ - HttpResponse clientToProxyRequest(HttpObject httpObject); - - /** - * Filters requests on their way from the proxy to the server. To interrupt processing of this request and return a - * response to the client immediately, return an HttpResponse here. Otherwise, return null to continue processing as - * usual. - *

- * Important: When returning a response, you must include a mechanism to allow the client to determine the length - * of the message (see RFC 7230, section 3.3.3: https://tools.ietf.org/html/rfc7230#section-3.3.3 ). For messages that - * may contain a body, you may do this by setting the Transfer-Encoding to chunked, setting an appropriate - * Content-Length, or by adding a "Connection: close" header to the response. (which will instruct LittleProxy to close - * the connection). If the short-circuit response contains body content, it is recommended that you return a - * FullHttpResponse. - * - * @param httpObject Proxy to Server HttpRequest (and HttpContent, if chunked) - * @return a short-circuit response, or null to continue processing as usual - */ - HttpResponse proxyToServerRequest(HttpObject httpObject); - - /** - * Informs filter that proxy to server request is being sent. - */ - void proxyToServerRequestSending(); - - /** - * Informs filter that the HTTP request, including any content, has been sent. - */ - void proxyToServerRequestSent(); - - /** - * Filters responses on their way from the server to the proxy. - * - * @param httpObject - * Server to Proxy HttpResponse (and HttpContent, if chunked) - * @return the modified (or unmodified) HttpObject. Returning null will - * force a disconnect. - */ - HttpObject serverToProxyResponse(HttpObject httpObject); - - /** - * Informs filter that a timeout occurred before the server response was received by the client. The timeout may have - * occurred while the client was sending the request, waiting for a response, or after the client started receiving - * a response (i.e. if the response from the server "stalls"). - * - * See {@link HttpProxyServerBootstrap#withIdleConnectionTimeout(int)} for information on setting the timeout. - */ - void serverToProxyResponseTimedOut(); - - /** - * Informs filter that server to proxy response is being received. - */ - void serverToProxyResponseReceiving(); - - /** - * Informs filter that server to proxy response has been received. - */ - void serverToProxyResponseReceived(); - - /** - * Filters responses on their way from the proxy to the client. - * - * @param httpObject - * Proxy to Client HttpResponse (and HttpContent, if chunked) - * @return the modified (or unmodified) HttpObject. Returning null will - * force a disconnect. - */ - HttpObject proxyToClientResponse(HttpObject httpObject); - - /** - * Informs filter that proxy to server connection is in queue. - */ - void proxyToServerConnectionQueued(); - - /** - * Filter DNS resolution from proxy to server. - * - * @param resolvingServerHostAndPort - * Server "HOST:PORT" - * @return alternative address resolution. Returning null will let normal - * DNS resolution continue. - */ - InetSocketAddress proxyToServerResolutionStarted( - String resolvingServerHostAndPort); - - /** - * Informs filter that proxy to server DNS resolution failed for the specified host and port. - * - * @param hostAndPort hostname and port the proxy failed to resolve - */ - void proxyToServerResolutionFailed(String hostAndPort); - - /** - * Informs filter that proxy to server DNS resolution has happened. - * - * @param serverHostAndPort - * Server "HOST:PORT" - * @param resolvedRemoteAddress - * Address it was proxyToServerResolutionSucceeded to - */ - void proxyToServerResolutionSucceeded(String serverHostAndPort, - InetSocketAddress resolvedRemoteAddress); - - /** - * Informs filter that proxy to server connection is initiating. - */ - void proxyToServerConnectionStarted(); - - /** - * Informs filter that proxy to server ssl handshake is initiating. - */ - void proxyToServerConnectionSSLHandshakeStarted(); - - /** - * Informs filter that proxy to server connection has failed. - */ - void proxyToServerConnectionFailed(); - - /** - * Informs filter that proxy to server connection has succeeded. - * - * @param serverCtx the {@link ChannelHandlerContext} used to connect to the server - */ - void proxyToServerConnectionSucceeded(ChannelHandlerContext serverCtx); - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersAdapter.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersAdapter.java deleted file mode 100644 index b0f55db535..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersAdapter.java +++ /dev/null @@ -1,106 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpObject; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; - -import java.net.InetSocketAddress; - -/** - * Convenience base class for implementations of {@link HttpFilters}. - */ -public class HttpFiltersAdapter implements HttpFilters { - /** - * A default, stateless, no-op {@link HttpFilters} instance. - */ - public static final HttpFiltersAdapter NOOP_FILTER = new HttpFiltersAdapter(null); - - protected final HttpRequest originalRequest; - protected final ChannelHandlerContext ctx; - - public HttpFiltersAdapter(HttpRequest originalRequest, - ChannelHandlerContext ctx) { - this.originalRequest = originalRequest; - this.ctx = ctx; - } - - public HttpFiltersAdapter(HttpRequest originalRequest) { - this(originalRequest, null); - } - - @Override - public HttpResponse clientToProxyRequest(HttpObject httpObject) { - return null; - } - - @Override - public HttpResponse proxyToServerRequest(HttpObject httpObject) { - return null; - } - - @Override - public void proxyToServerRequestSending() { - } - - @Override - public void proxyToServerRequestSent() { - } - - @Override - public HttpObject serverToProxyResponse(HttpObject httpObject) { - return httpObject; - } - - @Override - public void serverToProxyResponseTimedOut() { - } - - @Override - public void serverToProxyResponseReceiving() { - } - - @Override - public void serverToProxyResponseReceived() { - } - - @Override - public HttpObject proxyToClientResponse(HttpObject httpObject) { - return httpObject; - } - - @Override - public void proxyToServerConnectionQueued() { - } - - @Override - public InetSocketAddress proxyToServerResolutionStarted( - String resolvingServerHostAndPort) { - return null; - } - - @Override - public void proxyToServerResolutionFailed(String hostAndPort) { - } - - @Override - public void proxyToServerResolutionSucceeded(String serverHostAndPort, - InetSocketAddress resolvedRemoteAddress) { - } - - @Override - public void proxyToServerConnectionStarted() { - } - - @Override - public void proxyToServerConnectionSSLHandshakeStarted() { - } - - @Override - public void proxyToServerConnectionFailed() { - } - - @Override - public void proxyToServerConnectionSucceeded(ChannelHandlerContext serverCtx) { - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSource.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSource.java deleted file mode 100644 index 182b192de2..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSource.java +++ /dev/null @@ -1,50 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.FullHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; - -/** - * Factory for {@link HttpFilters}. - */ -public interface HttpFiltersSource { - /** - * Return an {@link HttpFilters} object for this request if and only if we - * want to filter the request and/or its responses. - * - * @param originalRequest - * @return - */ - HttpFilters filterRequest(HttpRequest originalRequest, - ChannelHandlerContext ctx); - - /** - * Indicate how many (if any) bytes to buffer for incoming - * {@link HttpRequest}s. A value of 0 or less indicates that no buffering - * should happen and that messages will be passed to the {@link HttpFilters} - * request filtering methods chunk by chunk. A positive value will cause - * LittleProxy to try an create a {@link FullHttpRequest} using the data - * received from the client, with its content already decompressed (in case - * the client was compressing it). If the request size exceeds the maximum - * buffer size, the request will fail. - * - * @return - */ - int getMaximumRequestBufferSizeInBytes(); - - /** - * Indicate how many (if any) bytes to buffer for incoming - * {@link HttpResponse}s. A value of 0 or less indicates that no buffering - * should happen and that messages will be passed to the {@link HttpFilters} - * response filtering methods chunk by chunk. A positive value will cause - * LittleProxy to try an create a {@link FullHttpResponse} using the data - * received from the server, with its content already decompressed (in case - * the server was compressing it). If the response size exceeds the maximum - * buffer size, the response will fail. - * - * @return - */ - int getMaximumResponseBufferSizeInBytes(); -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSourceAdapter.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSourceAdapter.java deleted file mode 100644 index 2fe57205b1..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpFiltersSourceAdapter.java +++ /dev/null @@ -1,32 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpRequest; - -/** - * Convenience base class for implementations of {@link HttpFiltersSource}. - */ -public class HttpFiltersSourceAdapter implements HttpFiltersSource -{ - - public HttpFilters filterRequest(HttpRequest originalRequest) { - return new HttpFiltersAdapter(originalRequest, null); - } - - @Override - public HttpFilters filterRequest(HttpRequest originalRequest, - ChannelHandlerContext ctx) { - return filterRequest(originalRequest); - } - - @Override - public int getMaximumRequestBufferSizeInBytes() { - return 0; - } - - @Override - public int getMaximumResponseBufferSizeInBytes() { - return 0; - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServer.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServer.java deleted file mode 100644 index 95427d7e8e..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServer.java +++ /dev/null @@ -1,67 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import java.net.InetSocketAddress; - -/** - * Interface for the top-level proxy server class. - */ -public interface HttpProxyServer { - - int getIdleConnectionTimeout(); - - void setIdleConnectionTimeout(int idleConnectionTimeout); - - /** - * Returns the maximum time to wait, in milliseconds, to connect to a server. - */ - int getConnectTimeout(); - - /** - * Sets the maximum time to wait, in milliseconds, to connect to a server. - */ - void setConnectTimeout(int connectTimeoutMs); - - /** - *

- * Clone the existing server, with a port 1 higher and everything else the - * same. If the proxy was started with port 0 (JVM-assigned port), the cloned proxy will also use a JVM-assigned - * port. - *

- * - *

- * The new server will share event loops with the original server. The event - * loops will use whatever name was given to the first server in the clone - * group. The server group will not terminate until the original server and all clones terminate. - *

- * - * @return a bootstrap that allows customizing and starting the cloned - * server - */ - HttpProxyServerBootstrap clone(); - - /** - * Stops the server and all related clones. Waits for traffic to stop before shutting down. - */ - void stop(); - - /** - * Stops the server and all related clones immediately, without waiting for traffic to stop. - */ - void abort(); - - /** - * Return the address on which this proxy is listening. - * - * @return - */ - InetSocketAddress getListenAddress(); - - /** - *

- * Set the read/write throttle bandwidths (in bytes/second) for this proxy. - *

- * @param readThrottleBytesPerSecond - * @param writeThrottleBytesPerSecond - */ - void setThrottle(long readThrottleBytesPerSecond, long writeThrottleBytesPerSecond); -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServerBootstrap.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServerBootstrap.java deleted file mode 100644 index 9d8a691cb3..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/HttpProxyServerBootstrap.java +++ /dev/null @@ -1,338 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ThreadPoolConfiguration; - -import java.net.InetSocketAddress; - -/** - * Configures and starts an {@link HttpProxyServer}. The HttpProxyServer is - * built using {@link #start()}. Sensible defaults are available for all - * parameters such that {@link #start()} could be called immediately if you - * wish. - */ -public interface HttpProxyServerBootstrap { - - /** - *

- * Give the server a name (used for naming threads, useful for logging). - *

- * - *

- * Default = LittleProxy - *

- * - * @param name - * @return - */ - HttpProxyServerBootstrap withName(String name); - - /** - *

- * Specify the {@link TransportProtocol} to use for incoming connections. - *

- * - *

- * Default = TCP - *

- * - * @param transportProtocol - * @return - */ - HttpProxyServerBootstrap withTransportProtocol( - TransportProtocol transportProtocol); - - /** - *

- * Listen for incoming connections on the given address. - *

- * - *

- * Default = [bound ip]:8080 - *

- * - * @param address - * @return - */ - HttpProxyServerBootstrap withAddress(InetSocketAddress address); - - /** - *

- * Listen for incoming connections on the given port. - *

- * - *

- * Default = 8080 - *

- * - * @param port - * @return - */ - HttpProxyServerBootstrap withPort(int port); - - /** - *

- * Specify whether or not to only allow local connections. - *

- * - *

- * Default = true - *

- * - * @param allowLocalOnly - * @return - */ - HttpProxyServerBootstrap withAllowLocalOnly(boolean allowLocalOnly); - - /** - * This method has no effect and will be removed in a future release. - * @deprecated use {@link #withNetworkInterface(InetSocketAddress)} to avoid listening on all local addresses - */ - @Deprecated - HttpProxyServerBootstrap withListenOnAllAddresses(boolean listenOnAllAddresses); - - /** - *

- * Specify an {@link SslEngineSource} to use for encrypting inbound - * connections. Enabling this will enable SSL client authentication - * by default (see {@link #withAuthenticateSslClients(boolean)}) - *

- * - *

- * Default = null - *

- * - *

- * Note - This and {@link #withManInTheMiddle(MitmManager)} are - * mutually exclusive. - *

- * - * @param sslEngineSource - * @return - */ - HttpProxyServerBootstrap withSslEngineSource( - SslEngineSource sslEngineSource); - - /** - *

- * Specify whether or not to authenticate inbound SSL clients (only applies - * if {@link #withSslEngineSource(SslEngineSource)} has been set). - *

- * - *

- * Default = true - *

- * - * @param authenticateSslClients - * @return - */ - HttpProxyServerBootstrap withAuthenticateSslClients( - boolean authenticateSslClients); - - /** - *

- * Specify a {@link ProxyAuthenticator} to use for doing basic HTTP - * authentication of clients. - *

- * - *

- * Default = null - *

- * - * @param proxyAuthenticator - * @return - */ - HttpProxyServerBootstrap withProxyAuthenticator( - ProxyAuthenticator proxyAuthenticator); - - /** - *

- * Specify a {@link ChainedProxyManager} to use for chaining requests to - * another proxy. - *

- * - *

- * Default = null - *

- * - * @param chainProxyManager - * @return - */ - HttpProxyServerBootstrap withChainProxyManager( - ChainedProxyManager chainProxyManager); - - /** - *

- * Specify an {@link MitmManager} to use for making this proxy act as an SSL - * man in the middle - *

- * - *

- * Default = null - *

- * - *

- * Note - This and {@link #withSslEngineSource(SslEngineSource)} are - * mutually exclusive. - *

- * - * @param mitmManager - * @return - */ - HttpProxyServerBootstrap withManInTheMiddle( - MitmManager mitmManager); - - /** - *

- * Specify a {@link HttpFiltersSource} to use for filtering requests and/or - * responses through this proxy. - *

- * - *

- * Default = null - *

- * - * @param filtersSource - * @return - */ - HttpProxyServerBootstrap withFiltersSource( - HttpFiltersSource filtersSource); - - /** - *

- * Specify whether or not to use secure DNS lookups for outbound - * connections. - *

- * - *

- * Default = false - *

- * - * @param useDnsSec - * @return - */ - HttpProxyServerBootstrap withUseDnsSec( - boolean useDnsSec); - - /** - *

- * Specify whether or not to run this proxy as a transparent proxy. - *

- * - *

- * Default = false - *

- * - * @param transparent - * @return - */ - HttpProxyServerBootstrap withTransparent( - boolean transparent); - - /** - *

- * Specify the timeout after which to disconnect idle connections, in - * seconds. - *

- * - *

- * Default = 70 - *

- * - * @param idleConnectionTimeout - * @return - */ - HttpProxyServerBootstrap withIdleConnectionTimeout( - int idleConnectionTimeout); - - /** - *

- * Specify the timeout for connecting to the upstream server on a new - * connection, in milliseconds. - *

- * - *

- * Default = 40000 - *

- * - * @param connectTimeout - * @return - */ - HttpProxyServerBootstrap withConnectTimeout( - int connectTimeout); - - /** - * Specify a custom {@link HostResolver} for resolving server addresses. - * - * @param serverResolver - * @return - */ - HttpProxyServerBootstrap withServerResolver(HostResolver serverResolver); - - /** - *

- * Add an {@link ActivityTracker} for tracking activity in this proxy. - *

- * - * @param activityTracker - * @return - */ - HttpProxyServerBootstrap plusActivityTracker(ActivityTracker activityTracker); - - /** - *

- * Specify the read and/or write bandwidth throttles for this proxy server. 0 indicates not throttling. - *

- * @param readThrottleBytesPerSecond - * @param writeThrottleBytesPerSecond - * @return - */ - HttpProxyServerBootstrap withThrottling(long readThrottleBytesPerSecond, long writeThrottleBytesPerSecond); - - /** - * All outgoing-communication of the proxy-instance is goin' to be routed via the given network-interface - * - * @param inetSocketAddress to be used for outgoing communication - */ - HttpProxyServerBootstrap withNetworkInterface(InetSocketAddress inetSocketAddress); - - HttpProxyServerBootstrap withMaxInitialLineLength(int maxInitialLineLength); - - HttpProxyServerBootstrap withMaxHeaderSize(int maxHeaderSize); - - HttpProxyServerBootstrap withMaxChunkSize(int maxChunkSize); - - /** - * When true, the proxy will accept requests that appear to be directed at an origin server (i.e. the URI in the HTTP - * request will contain an origin-form, rather than an absolute-form, as specified in RFC 7230, section 5.3). - * This is useful when the proxy is acting as a gateway/reverse proxy. Note: This feature should not be - * enabled when running as a forward proxy; doing so may cause an infinite loop if the client requests the URI of the proxy. - * - * @param allowRequestToOriginServer when true, the proxy will accept origin-form HTTP requests - */ - HttpProxyServerBootstrap withAllowRequestToOriginServer(boolean allowRequestToOriginServer); - - /** - * Sets the alias to use when adding Via headers to incoming and outgoing HTTP messages. The alias may be any - * pseudonym, or if not specified, defaults to the hostname of the local machine. See RFC 7230, section 5.7.1. - * - * @param alias the pseudonym to add to Via headers - */ - HttpProxyServerBootstrap withProxyAlias(String alias); - - /** - *

- * Build and starts the server. - *

- * - * @return the newly built and started server - */ - HttpProxyServer start(); - - /** - * Set the configuration parameters for the proxy's thread pools. - * - * @param configuration thread pool configuration - * @return proxy server bootstrap for chaining - */ - HttpProxyServerBootstrap withThreadPoolConfiguration(ThreadPoolConfiguration configuration); -} \ No newline at end of file diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/MitmManager.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/MitmManager.java deleted file mode 100644 index 2493bfc711..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/MitmManager.java +++ /dev/null @@ -1,54 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import io.netty.handler.codec.http.HttpRequest; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSession; - -/** - * MITMManagers encapsulate the logic required for letting LittleProxy act as a - * man in the middle for HTTPS requests. - */ -public interface MitmManager { - /** - * Creates an {@link SSLEngine} for encrypting the server connection. The SSLEngine created by this method - * may use the given peer information to send SNI information when connecting to the upstream host. - * - * @param peerHost to start a client connection to the server. - * @param peerPort to start a client connection to the server. - * - * @return an SSLEngine used to connect to an upstream server - */ - SSLEngine serverSslEngine(String peerHost, int peerPort); - - /** - * Creates an {@link SSLEngine} for encrypting the server connection. - * - * @return an SSLEngine used to connect to an upstream server - */ - SSLEngine serverSslEngine(); - - /** - *

- * Creates an {@link SSLEngine} for encrypting the client connection based - * on the given serverSslSession. - *

- * - *

- * The serverSslSession is provided in case this method needs to inspect the - * server's certificates or something else about the encryption on the way - * to the server. - *

- * - *

- * This is the place where one would implement impersonation of the server - * by issuing replacement certificates signed by the proxy's own - * certificate. - *

- * - * @param httpRequest the HTTP CONNECT request that is being man-in-the-middled - * @param serverSslSession the {@link SSLSession} that's been established with the server - * @return the SSLEngine used to connect to the client - */ - SSLEngine clientSslEngineFor(HttpRequest httpRequest, SSLSession serverSslSession); -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ProxyAuthenticator.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ProxyAuthenticator.java deleted file mode 100644 index 855b455820..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/ProxyAuthenticator.java +++ /dev/null @@ -1,28 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -/** - * Interface for objects that can authenticate someone for using our Proxy on - * the basis of a username and password. - */ -public interface ProxyAuthenticator { - /** - * Authenticates the user using the specified userName and password. - * - * @param userName - * The user name. - * @param password - * The password. - * @return true if the credentials are acceptable, otherwise - * false. - */ - boolean authenticate(String userName, String password); - - /** - * The realm value to be used in the request for proxy authentication - * ("Proxy-Authenticate" header). Returning null will cause the string - * "Restricted Files" to be used by default. - * - * @return - */ - String getRealm(); -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/SslEngineSource.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/SslEngineSource.java deleted file mode 100644 index 8489fffe1d..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/SslEngineSource.java +++ /dev/null @@ -1,33 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -import javax.net.ssl.SSLEngine; - -/** - * Source for {@link SSLEngine}s. - */ -public interface SslEngineSource { - - /** - * Returns an {@link SSLEngine} to use for a server connection from - * LittleProxy to the client. - * - * @return - */ - SSLEngine newSslEngine(); - - /** - * Returns an {@link SSLEngine} to use for a client connection from - * LittleProxy to the upstream server. * - * - * Note: Peer information is needed to send the server_name extension in - * handshake with Server Name Indication (SNI). - * - * @param peerHost - * to start a client connection to the server. - * @param peerPort - * to start a client connection to the server. - * @return - */ - SSLEngine newSslEngine(String peerHost, int peerPort); - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/TransportProtocol.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/TransportProtocol.java deleted file mode 100644 index f8b2eb9422..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/TransportProtocol.java +++ /dev/null @@ -1,8 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -/** - * Enumeration of transport protocols supported by LittleProxy. - */ -public enum TransportProtocol { - TCP, UDT -} \ No newline at end of file diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/UnknownTransportProtocolException.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/UnknownTransportProtocolException.java deleted file mode 100644 index da64d6350e..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/UnknownTransportProtocolException.java +++ /dev/null @@ -1,12 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy; - -/** - * This exception indicates that the system was asked to use a TransportProtocol that it didn't know how to handle. - */ -public class UnknownTransportProtocolException extends RuntimeException { - private static final long serialVersionUID = 1L; - - public UnknownTransportProtocolException(TransportProtocol transportProtocol) { - super(String.format("Unknown TransportProtocol: %1$s", transportProtocol)); - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedMitmManager.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedMitmManager.java deleted file mode 100644 index b9fbaede0f..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedMitmManager.java +++ /dev/null @@ -1,31 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.extras; - -import io.netty.handler.codec.http.HttpRequest; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.MitmManager; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSession; - -/** - * {@link MitmManager} that uses self-signed certs for everything. - */ -public class SelfSignedMitmManager implements MitmManager -{ - SelfSignedSslEngineSource selfSignedSslEngineSource = - new SelfSignedSslEngineSource(true); - - @Override - public SSLEngine serverSslEngine(String peerHost, int peerPort) { - return selfSignedSslEngineSource.newSslEngine(peerHost, peerPort); - } - - @Override - public SSLEngine serverSslEngine() { - return selfSignedSslEngineSource.newSslEngine(); - } - - @Override - public SSLEngine clientSslEngineFor(HttpRequest httpRequest, SSLSession serverSslSession) { - return selfSignedSslEngineSource.newSslEngine(); - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedSslEngineSource.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedSslEngineSource.java deleted file mode 100644 index ff9ed07e12..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/extras/SelfSignedSslEngineSource.java +++ /dev/null @@ -1,207 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.extras; - -import com.google.common.io.ByteStreams; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.SslEngineSource; - -import javax.net.ssl.*; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.Security; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Arrays; - -/** - * Basic {@link SslEngineSource} for testing. The {@link SSLContext} uses - * self-signed certificates that are generated lazily if the given key store - * file doesn't yet exist. - */ -public class SelfSignedSslEngineSource implements SslEngineSource -{ - private static final Logger LOG = LoggerFactory - .getLogger(SelfSignedSslEngineSource.class); - - private static final String ALIAS = "littleproxy"; - private static final String PASSWORD = "Be Your Own Lantern"; - private static final String PROTOCOL = "TLSv1.2"; - private final File keyStoreFile; - private final boolean trustAllServers; - private final boolean sendCerts; - - private SSLContext sslContext; - - public SelfSignedSslEngineSource(String keyStorePath, - boolean trustAllServers, boolean sendCerts) { - this.trustAllServers = trustAllServers; - this.sendCerts = sendCerts; - this.keyStoreFile = new File(keyStorePath); - initializeKeyStore(); - initializeSSLContext(); - } - - public SelfSignedSslEngineSource(String keyStorePath) { - this(keyStorePath, false, true); - } - - public SelfSignedSslEngineSource(boolean trustAllServers) { - this(trustAllServers, true); - } - - public SelfSignedSslEngineSource(boolean trustAllServers, boolean sendCerts) { - this("littleproxy_keystore.jks", trustAllServers, sendCerts); - } - - public SelfSignedSslEngineSource() { - this(false); - } - - @Override - public SSLEngine newSslEngine() { - return sslContext.createSSLEngine(); - } - - @Override - public SSLEngine newSslEngine(String peerHost, int peerPort) { - return sslContext.createSSLEngine(peerHost, peerPort); - } - - public SSLContext getSslContext() { - return sslContext; - } - - private void initializeKeyStore() { - if (keyStoreFile.isFile()) { - LOG.info("Not deleting keystore"); - return; - } - - nativeCall("keytool", "-genkey", "-alias", ALIAS, "-keysize", - "4096", "-validity", "36500", "-keyalg", "RSA", "-dname", - "CN=littleproxy", "-keypass", PASSWORD, "-storepass", - PASSWORD, "-keystore", keyStoreFile.getName()); - - nativeCall("keytool", "-exportcert", "-alias", ALIAS, "-keystore", - keyStoreFile.getName(), "-storepass", PASSWORD, "-file", - "littleproxy_cert"); - } - - private void initializeSSLContext() { - String algorithm = Security - .getProperty("ssl.KeyManagerFactory.algorithm"); - if (algorithm == null) { - algorithm = "SunX509"; - } - - try { - final KeyStore ks = KeyStore.getInstance("JKS"); - // ks.load(new FileInputStream("keystore.jks"), - // "changeit".toCharArray()); - ks.load(new FileInputStream(keyStoreFile), PASSWORD.toCharArray()); - - // Set up key manager factory to use our key store - final KeyManagerFactory kmf = - KeyManagerFactory.getInstance(algorithm); - kmf.init(ks, PASSWORD.toCharArray()); - - // Set up a trust manager factory to use our key store - TrustManagerFactory tmf = TrustManagerFactory - .getInstance(algorithm); - tmf.init(ks); - - TrustManager[] trustManagers = null; - if (!trustAllServers) { - trustManagers = tmf.getTrustManagers(); - } else { - trustManagers = new TrustManager[] { new X509TrustManager() { - // TrustManager that trusts all servers - @Override - public void checkClientTrusted(X509Certificate[] certs, - String authType) - throws CertificateException { - } - - @Override - public void checkServerTrusted(X509Certificate[] certs, - String authType) - throws CertificateException { - if (certs == null || certs.length == 0) - { - throw new IllegalArgumentException("Null or zero-length certificate chain"); - } - if (authType == null || authType.length() == 0) - { - throw new IllegalArgumentException("Null or zero-length authentication type"); - } - // Checks if any certificate in the certificate chain is stored in the key store. - boolean isChainTrusted = false; - try - { - for (X509Certificate cert : certs) - { - if (ks.getCertificateAlias(cert) != null) - { - isChainTrusted = true; - break; - } - } - } - catch(KeyStoreException e) - { - isChainTrusted = false; - } - - if (!isChainTrusted) - { - throw new CertificateException("Certificate chain is not trusted by this TrustManager"); - } - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } }; - } - - KeyManager[] keyManagers = null; - if (sendCerts) { - keyManagers = kmf.getKeyManagers(); - } else { - keyManagers = new KeyManager[0]; - } - - // Initialize the SSLContext to work with our key managers. - sslContext = SSLContext.getInstance(PROTOCOL); - sslContext.init(keyManagers, trustManagers, null); - } catch (final Exception e) { - throw new Error( - "Failed to initialize the server-side SSLContext", e); - } - } - - private String nativeCall(final String... commands) { - LOG.info("Running '{}'", Arrays.asList(commands)); - final ProcessBuilder pb = new ProcessBuilder(commands); - try { - final Process process = pb.start(); - final InputStream is = process.getInputStream(); - - byte[] data = ByteStreams.toByteArray(is); - String dataAsString = new String(data); - - LOG.info("Completed native call: '{}'\nResponse: '" + dataAsString + "'", - Arrays.asList(commands)); - return dataAsString; - } catch (final IOException e) { - LOG.error("Error running commands: " + Arrays.asList(commands), e); - return ""; - } - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/CategorizedThreadFactory.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/CategorizedThreadFactory.java deleted file mode 100644 index dc0b87cf46..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/CategorizedThreadFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A ThreadFactory that adds LittleProxy-specific information to the threads' names. - */ -public class CategorizedThreadFactory implements ThreadFactory { - private static final Logger log = LoggerFactory.getLogger(CategorizedThreadFactory.class); - - private final String name; - private final String category; - private final int uniqueServerGroupId; - - private AtomicInteger threadCount = new AtomicInteger(0); - - /** - * Exception handler for proxy threads. Logs the name of the thread and the exception that was caught. - */ - private static final Thread.UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER = new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - log.error("Uncaught throwable in thread: {}", t.getName(), e); - } - }; - - - /** - * @param name the user-supplied name of this proxy - * @param category the type of threads this factory is creating (acceptor, client-to-proxy worker, proxy-to-server worker) - * @param uniqueServerGroupId a unique number for the server group creating this thread factory, to differentiate multiple proxy instances with the same name - */ - public CategorizedThreadFactory(String name, String category, int uniqueServerGroupId) { - this.category = category; - this.name = name; - this.uniqueServerGroupId = uniqueServerGroupId; - } - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, name + "-" + uniqueServerGroupId + "-" + category + "-" + threadCount.getAndIncrement()); - - t.setUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER); - - return t; - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ClientToProxyConnection.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ClientToProxyConnection.java deleted file mode 100644 index 25e44346c9..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ClientToProxyConnection.java +++ /dev/null @@ -1,1432 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import com.google.common.io.BaseEncoding; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.Channel; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.http.*; -import io.netty.handler.timeout.IdleStateHandler; -import io.netty.handler.traffic.GlobalTrafficShapingHandler; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.*; - -import javax.net.ssl.SSLSession; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.nio.charset.Charset; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Pattern; - -import static tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ConnectionState.*; -import static tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ProxyUtils.shouldRemoveHopByHopHeader; - -/** - *

- * Represents a connection from a client to our proxy. Each - * ClientToProxyConnection can have multiple {@link ProxyToServerConnection}s, - * at most one per outbound host:port. - *

- * - *

- * Once a ProxyToServerConnection has been created for a given server, it is - * continually reused. The ProxyToServerConnection goes through its own - * lifecycle of connects and disconnects, with different underlying - * {@link Channel}s, but only a single ProxyToServerConnection object is used - * per server. The one exception to this is CONNECT tunneling - if a connection - * has been used for CONNECT tunneling, that connection will never be reused. - *

- * - *

- * As the ProxyToServerConnections receive responses from their servers, they - * feed these back to the client by calling - * {@link #respond(ProxyToServerConnection, HttpFilters, HttpRequest, HttpResponse, HttpObject)} - * . - *

- */ -@Slf4j -public class ClientToProxyConnection extends ProxyConnection -{ - private static final HttpResponseStatus CONNECTION_ESTABLISHED = new HttpResponseStatus( - 200, "Connection established"); - /** - * Used for case-insensitive comparisons when parsing Connection header values. - */ - private static final String LOWERCASE_TRANSFER_ENCODING_HEADER = HttpHeaders.Names.TRANSFER_ENCODING.toLowerCase(Locale.US); - - /** - * Used for case-insensitive comparisons when checking direct proxy request. - */ - private static final Pattern HTTP_SCHEME = Pattern.compile("^http://.*", Pattern.CASE_INSENSITIVE); - - /** - * Keep track of all ProxyToServerConnections by host+port. - */ - private final Map serverConnectionsByHostAndPort = new ConcurrentHashMap(); - - /** - * Keep track of how many servers are currently in the process of - * connecting. - */ - private final AtomicInteger numberOfCurrentlyConnectingServers = new AtomicInteger( - 0); - - /** - * Keep track of how many servers are currently connected. - */ - private final AtomicInteger numberOfCurrentlyConnectedServers = new AtomicInteger( - 0); - - /** - * Keep track of how many times we were able to reuse a connection. - */ - private final AtomicInteger numberOfReusedServerConnections = new AtomicInteger( - 0); - - /** - * This is the current server connection that we're using while transferring - * chunked data. - */ - private volatile ProxyToServerConnection currentServerConnection; - - /** - * The current filters to apply to incoming requests/chunks. - */ - private volatile HttpFilters currentFilters = HttpFiltersAdapter.NOOP_FILTER; - - private volatile SSLSession clientSslSession; - - /** - * Tracks whether or not this ClientToProxyConnection is current doing MITM. - */ - private volatile boolean mitming = false; - - private AtomicBoolean authenticated = new AtomicBoolean(); - - private final GlobalTrafficShapingHandler globalTrafficShapingHandler; - - /** - * The current HTTP request that this connection is currently servicing. - */ - private volatile HttpRequest currentRequest; - - ClientToProxyConnection( - final DefaultHttpProxyServer proxyServer, - SslEngineSource sslEngineSource, - boolean authenticateClients, - ChannelPipeline pipeline, - GlobalTrafficShapingHandler globalTrafficShapingHandler) { - super(AWAITING_INITIAL, proxyServer, false); - - initChannelPipeline(pipeline); - - if (sslEngineSource != null) { - log.trace("Enabling encryption of traffic from client to proxy"); - encrypt(pipeline, sslEngineSource.newSslEngine(), - authenticateClients) - .addListener( - new GenericFutureListener>() { - @Override - public void operationComplete( - Future future) - throws Exception { - if (future.isSuccess()) { - clientSslSession = sslEngine - .getSession(); - recordClientSSLHandshakeSucceeded(); - } - } - }); - } - this.globalTrafficShapingHandler = globalTrafficShapingHandler; - - log.trace("Created ClientToProxyConnection"); - } - - /*************************************************************************** - * Reading - **************************************************************************/ - - @Override - protected ConnectionState readHTTPInitial(HttpRequest httpRequest) { - log.debug("Received raw request: {}", httpRequest); - - // if we cannot parse the request, immediately return a 400 and close the connection, since we do not know what state - // the client thinks the connection is in - if (httpRequest.getDecoderResult().isFailure()) { - log.trace("Could not parse request from client. Decoder result: {}", httpRequest.getDecoderResult().toString()); - - FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, - HttpResponseStatus.BAD_REQUEST, - "Unable to parse HTTP request"); - HttpHeaders.setKeepAlive(response, false); - - respondWithShortCircuitResponse(response); - - return DISCONNECT_REQUESTED; - } - - boolean authenticationRequired = authenticationRequired(httpRequest); - - if (authenticationRequired) { - log.trace("Not authenticated!!"); - return AWAITING_PROXY_AUTHENTICATION; - } else { - return doReadHTTPInitial(httpRequest); - } - } - - /** - *

- * Reads an {@link HttpRequest}. - *

- * - *

- * If we don't yet have a {@link ProxyToServerConnection} for the desired - * server, this takes care of creating it. - *

- * - *

- * Note - the "server" could be a chained proxy, not the final endpoint for - * the request. - *

- * - * @param httpRequest - * @return - */ - private ConnectionState doReadHTTPInitial(HttpRequest httpRequest) { - // Make a copy of the original request - this.currentRequest = copy(httpRequest); - - // Set up our filters based on the original request. If the HttpFiltersSource returns null (meaning the request/response - // should not be filtered), fall back to the default no-op filter source. - HttpFilters filterInstance = proxyServer.getFiltersSource().filterRequest(currentRequest, ctx); - if (filterInstance != null) { - currentFilters = filterInstance; - } else { - currentFilters = HttpFiltersAdapter.NOOP_FILTER; - } - - // Send the request through the clientToProxyRequest filter, and respond with the short-circuit response if required - HttpResponse clientToProxyFilterResponse = currentFilters.clientToProxyRequest(httpRequest); - - if (clientToProxyFilterResponse != null) { - log.trace("Responding to client with short-circuit response from filter: {}", clientToProxyFilterResponse); - - boolean keepAlive = respondWithShortCircuitResponse(clientToProxyFilterResponse); - if (keepAlive) { - return AWAITING_INITIAL; - } else { - return DISCONNECT_REQUESTED; - } - } - - // if origin-form requests are not explicitly enabled, short-circuit requests that treat the proxy as the - // origin server, to avoid infinite loops - if (!proxyServer.isAllowRequestsToOriginServer() && isRequestToOriginServer(httpRequest)) { - boolean keepAlive = writeBadRequest(httpRequest); - if (keepAlive) { - return AWAITING_INITIAL; - } else { - return DISCONNECT_REQUESTED; - } - } - - // Identify our server and chained proxy - String serverHostAndPort = identifyHostAndPort(httpRequest); - - log.trace("Ensuring that hostAndPort are available in {}", - httpRequest.getUri()); - if (serverHostAndPort == null || StringUtils.isBlank(serverHostAndPort)) { - log.warn("No host and port found in {}", httpRequest.getUri()); - boolean keepAlive = writeBadGateway(httpRequest); - if (keepAlive) { - return AWAITING_INITIAL; - } else { - return DISCONNECT_REQUESTED; - } - } - - log.trace("Finding ProxyToServerConnection for: {}", serverHostAndPort); - currentServerConnection = isMitming() || isTunneling() ? - this.currentServerConnection - : this.serverConnectionsByHostAndPort.get(serverHostAndPort); - - boolean newConnectionRequired = false; - if (ProxyUtils.isCONNECT(httpRequest)) { - log.trace( - "Not reusing existing ProxyToServerConnection because request is a CONNECT for: {}", - serverHostAndPort); - newConnectionRequired = true; - } else if (currentServerConnection == null) { - log.trace("Didn't find existing ProxyToServerConnection for: {}", - serverHostAndPort); - newConnectionRequired = true; - } - - if (newConnectionRequired) { - try { - currentServerConnection = ProxyToServerConnection.create( - proxyServer, - this, - serverHostAndPort, - currentFilters, - httpRequest, - globalTrafficShapingHandler); - if (currentServerConnection == null) { - log.trace("Unable to create server connection, probably no chained proxies available"); - boolean keepAlive = writeBadGateway(httpRequest); - resumeReading(); - if (keepAlive) { - return AWAITING_INITIAL; - } else { - return DISCONNECT_REQUESTED; - } - } - // Remember the connection for later - serverConnectionsByHostAndPort.put(serverHostAndPort, - currentServerConnection); - } catch (UnknownHostException uhe) { - log.info("Bad Host {}", httpRequest.getUri()); - boolean keepAlive = writeBadGateway(httpRequest); - resumeReading(); - if (keepAlive) { - return AWAITING_INITIAL; - } else { - return DISCONNECT_REQUESTED; - } - } - } else { - log.trace("Reusing existing server connection: {}", - currentServerConnection); - numberOfReusedServerConnections.incrementAndGet(); - } - - modifyRequestHeadersToReflectProxying(httpRequest); - - HttpResponse proxyToServerFilterResponse = currentFilters.proxyToServerRequest(httpRequest); - if (proxyToServerFilterResponse != null) { - log.trace("Responding to client with short-circuit response from filter: {}", proxyToServerFilterResponse); - - boolean keepAlive = respondWithShortCircuitResponse(proxyToServerFilterResponse); - if (keepAlive) { - return AWAITING_INITIAL; - } else { - return DISCONNECT_REQUESTED; - } - } - - log.trace("Writing request to ProxyToServerConnection"); - currentServerConnection.write(httpRequest, currentFilters); - - // Figure out our next state - if (ProxyUtils.isCONNECT(httpRequest)) { - return NEGOTIATING_CONNECT; - } else if (ProxyUtils.isChunked(httpRequest)) { - return AWAITING_CHUNK; - } else { - return AWAITING_INITIAL; - } - } - - /** - * Returns true if the specified request is a request to an origin server, rather than to a proxy server. If this - * request is being MITM'd, this method always returns false. The format of requests to a proxy server are defined - * in RFC 7230, section 5.3.2 (all other requests are considered requests to an origin server): -
-         When making a request to a proxy, other than a CONNECT or server-wide
-         OPTIONS request (as detailed below), a client MUST send the target
-         URI in absolute-form as the request-target.
-         [...]
-         An example absolute-form of request-line would be:
-         GET http://www.example.org/pub/WWW/TheProject.html HTTP/1.1
-         To allow for transition to the absolute-form for all requests in some
-         future version of HTTP, a server MUST accept the absolute-form in
-         requests, even though HTTP/1.1 clients will only send them in
-         requests to proxies.
-     
- * - * @param httpRequest the request to evaluate - * @return true if the specified request is a request to an origin server, otherwise false - */ - private boolean isRequestToOriginServer(HttpRequest httpRequest) { - // while MITMing, all HTTPS requests are requests to the origin server, since the client does not know - // the request is being MITM'd by the proxy - if (httpRequest.getMethod() == HttpMethod.CONNECT || isMitming()) { - return false; - } - - // direct requests to the proxy have the path only without a scheme - String uri = httpRequest.getUri(); - return !HTTP_SCHEME.matcher(uri).matches(); - } - - @Override - protected void readHTTPChunk(HttpContent chunk) { - currentFilters.clientToProxyRequest(chunk); - currentFilters.proxyToServerRequest(chunk); - - currentServerConnection.write(chunk); - } - - @Override - protected void readRaw(ByteBuf buf) { - currentServerConnection.write(buf); - } - - /*************************************************************************** - * Writing - **************************************************************************/ - - /** - * Send a response to the client. - * - * @param serverConnection - * the ProxyToServerConnection that's responding - * @param filters - * the filters to apply to the response - * @param currentHttpRequest - * the HttpRequest that prompted this response - * @param currentHttpResponse - * the HttpResponse corresponding to this data (when doing - * chunked transfers, this is the initial HttpResponse object - * that came in before the other chunks) - * @param httpObject - * the data with which to respond - */ - void respond(ProxyToServerConnection serverConnection, HttpFilters filters, - HttpRequest currentHttpRequest, HttpResponse currentHttpResponse, - HttpObject httpObject) { - // we are sending a response to the client, so we are done handling this request - this.currentRequest = null; - - httpObject = filters.serverToProxyResponse(httpObject); - if (httpObject == null) { - forceDisconnect(serverConnection); - return; - } - - if (httpObject instanceof HttpResponse) { - HttpResponse httpResponse = (HttpResponse) httpObject; - - // if this HttpResponse does not have any means of signaling the end of the message body other than closing - // the connection, convert the message to a "Transfer-Encoding: chunked" HTTP response. This avoids the need - // to close the client connection to indicate the end of the message. (Responses to HEAD requests "must be" empty.) - if (!ProxyUtils.isHEAD(currentHttpRequest) && !ProxyUtils.isResponseSelfTerminating(httpResponse)) { - // if this is not a FullHttpResponse, duplicate the HttpResponse from the server before sending it to - // the client. this allows us to set the Transfer-Encoding to chunked without interfering with netty's - // handling of the response from the server. if we modify the original HttpResponse from the server, - // netty will not generate the appropriate LastHttpContent when it detects the connection closure from - // the server (see HttpObjectDecoder#decodeLast). (This does not apply to FullHttpResponses, for which - // netty already generates the empty final chunk when Transfer-Encoding is chunked.) - if (!(httpResponse instanceof FullHttpResponse)) { - HttpResponse duplicateResponse = ProxyUtils.duplicateHttpResponse(httpResponse); - - // set the httpObject and httpResponse to the duplicated response, to allow all other standard processing - // (filtering, header modification for proxying, etc.) to be applied. - httpObject = httpResponse = duplicateResponse; - } - - HttpHeaders.setTransferEncodingChunked(httpResponse); - } - - fixHttpVersionHeaderIfNecessary(httpResponse); - modifyResponseHeadersToReflectProxying(httpResponse); - } - - httpObject = filters.proxyToClientResponse(httpObject); - if (httpObject == null) { - forceDisconnect(serverConnection); - return; - } - - write(httpObject); - - if (ProxyUtils.isLastChunk(httpObject)) { - writeEmptyBuffer(); - } - - closeConnectionsAfterWriteIfNecessary(serverConnection, - currentHttpRequest, currentHttpResponse, httpObject); - } - - /*************************************************************************** - * Connection Lifecycle - **************************************************************************/ - - /** - * Tells the Client that its HTTP CONNECT request was successful. - */ - ConnectionFlowStep RespondCONNECTSuccessful = new ConnectionFlowStep( - this, NEGOTIATING_CONNECT) { - @Override - boolean shouldSuppressInitialRequest() { - return true; - } - - protected Future execute() { - log.trace("Responding to proxy connect request with successful status code"); - HttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, - CONNECTION_ESTABLISHED); - response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); - ProxyUtils.addVia(response, proxyServer.getProxyAlias()); - return writeToChannel(response); - }; - }; - - /** - * On connect of the client, start waiting for an initial - * {@link HttpRequest}. - */ - @Override - protected void connected() { - super.connected(); - become(AWAITING_INITIAL); - recordClientConnected(); - } - - void timedOut(ProxyToServerConnection serverConnection) { - if (currentServerConnection == serverConnection && this.lastReadTime > currentServerConnection.lastReadTime) { - // the idle timeout fired on the active server connection. send a timeout response to the client. - log.warn("Server timed out: {}", currentServerConnection); - currentFilters.serverToProxyResponseTimedOut(); - writeGatewayTimeout(currentRequest); - } - } - - @Override - protected void timedOut() { - // idle timeout fired on the client channel. if we aren't waiting on a response from a server, hang up - if (currentServerConnection == null || this.lastReadTime <= currentServerConnection.lastReadTime) { - super.timedOut(); - } - } - - /** - * On disconnect of the client, disconnect all server connections. - */ - @Override - protected void disconnected() { - super.disconnected(); - for (ProxyToServerConnection serverConnection : serverConnectionsByHostAndPort - .values()) { - serverConnection.disconnect(); - } - recordClientDisconnected(); - } - - /** - * Called when {@link ProxyToServerConnection} starts its connection flow. - * - * @param serverConnection - */ - protected void serverConnectionFlowStarted( - ProxyToServerConnection serverConnection) { - stopReading(); - this.numberOfCurrentlyConnectingServers.incrementAndGet(); - } - - /** - * If the {@link ProxyToServerConnection} completes its connection lifecycle - * successfully, this method is called to let us know about it. - * - * @param serverConnection - * @param shouldForwardInitialRequest - */ - protected void serverConnectionSucceeded( - ProxyToServerConnection serverConnection, - boolean shouldForwardInitialRequest) { - log.debug("Connection to server succeeded: {}", - serverConnection.getRemoteAddress()); - resumeReadingIfNecessary(); - become(shouldForwardInitialRequest ? getCurrentState() - : AWAITING_INITIAL); - numberOfCurrentlyConnectedServers.incrementAndGet(); - } - - /** - * If the {@link ProxyToServerConnection} fails to complete its connection - * lifecycle successfully, this method is called to let us know about it. - * - *

- * After failing to connect to the server, one of two things can happen: - *

- * - *
    - *
  1. If the server was a chained proxy, we fall back to connecting to the - * ultimate endpoint directly.
  2. - *
  3. If the server was the ultimate endpoint, we return a 502 Bad Gateway - * to the client.
  4. - *
- * - * @param serverConnection - * @param lastStateBeforeFailure - * @param cause - * what caused the failure - * - * @return true if we're falling back to a another chained proxy (or direct - * connection) and trying again - */ - protected boolean serverConnectionFailed( - ProxyToServerConnection serverConnection, - ConnectionState lastStateBeforeFailure, - Throwable cause) { - resumeReadingIfNecessary(); - HttpRequest initialRequest = serverConnection.getInitialRequest(); - try { - boolean retrying = serverConnection.connectionFailed(cause); - if (retrying) { - log.warn("Failed to connect to upstream server or chained proxy. Retrying connection. Last state before failure: {}", - lastStateBeforeFailure, cause); - return true; - } else { - log.warn( - "Connection to upstream server or chained proxy failed: {}. Last state before failure: {}", - serverConnection.getRemoteAddress(), - lastStateBeforeFailure, - cause); - connectionFailedUnrecoverably(initialRequest, serverConnection); - return false; - } - } catch (UnknownHostException uhe) { - connectionFailedUnrecoverably(initialRequest, serverConnection); - return false; - } - } - - private void connectionFailedUnrecoverably(HttpRequest initialRequest, ProxyToServerConnection serverConnection) { - // the connection to the server failed, so disconnect the server and remove the ProxyToServerConnection from the - // map of open server connections - serverConnection.disconnect(); - this.serverConnectionsByHostAndPort.remove(serverConnection.getServerHostAndPort()); - - boolean keepAlive = writeBadGateway(initialRequest); - if (keepAlive) { - become(AWAITING_INITIAL); - } else { - become(DISCONNECT_REQUESTED); - } - } - - private void resumeReadingIfNecessary() { - if (this.numberOfCurrentlyConnectingServers.decrementAndGet() == 0) { - log.trace("All servers have finished attempting to connect, resuming reading from client."); - resumeReading(); - } - } - - /*************************************************************************** - * Other Lifecycle - **************************************************************************/ - - /** - * On disconnect of the server, track that we have one fewer connected - * servers and then disconnect the client if necessary. - * - * @param serverConnection - */ - protected void serverDisconnected(ProxyToServerConnection serverConnection) { - numberOfCurrentlyConnectedServers.decrementAndGet(); - - // for non-SSL connections, do not disconnect the client from the proxy, even if this was the last server connection. - // this allows clients to continue to use the open connection to the proxy to make future requests. for SSL - // connections, whether we are tunneling or MITMing, we need to disconnect the client because there is always - // exactly one ClientToProxyConnection per ProxyToServerConnection, and vice versa. - if (isTunneling() || isMitming()) { - disconnect(); - } - } - - /** - * When the ClientToProxyConnection becomes saturated, stop reading on all - * associated ProxyToServerConnections. - */ - @Override - synchronized protected void becameSaturated() { - super.becameSaturated(); - for (ProxyToServerConnection serverConnection : serverConnectionsByHostAndPort - .values()) { - synchronized (serverConnection) { - if (this.isSaturated()) { - serverConnection.stopReading(); - } - } - } - } - - /** - * When the ClientToProxyConnection becomes writable, resume reading on all - * associated ProxyToServerConnections. - */ - @Override - synchronized protected void becameWritable() { - super.becameWritable(); - for (ProxyToServerConnection serverConnection : serverConnectionsByHostAndPort - .values()) { - synchronized (serverConnection) { - if (!this.isSaturated()) { - serverConnection.resumeReading(); - } - } - } - } - - /** - * When a server becomes saturated, we stop reading from the client. - * - * @param serverConnection - */ - synchronized protected void serverBecameSaturated( - ProxyToServerConnection serverConnection) { - if (serverConnection.isSaturated()) { - log.info("Connection to server became saturated, stopping reading"); - stopReading(); - } - } - - /** - * When a server becomes writeable, we check to see if all servers are - * writeable and if they are, we resume reading. - * - * @param serverConnection - */ - synchronized protected void serverBecameWriteable( - ProxyToServerConnection serverConnection) { - boolean anyServersSaturated = false; - for (ProxyToServerConnection otherServerConnection : serverConnectionsByHostAndPort - .values()) { - if (otherServerConnection.isSaturated()) { - anyServersSaturated = true; - break; - } - } - if (!anyServersSaturated) { - log.info("All server connections writeable, resuming reading"); - resumeReading(); - } - } - - @Override - protected void exceptionCaught(Throwable cause) { - try { - if (cause instanceof IOException) { - // IOExceptions are expected errors, for example when a browser is killed and aborts a connection. - // rather than flood the logs with stack traces for these expected exceptions, we log the message at the - // INFO level and the stack trace at the DEBUG level. - log.debug("An IOException occurred on ClientToProxyConnection: " + cause.getMessage()); - log.warn("An IOException occurred on ClientToProxyConnection", cause); - } else if (cause instanceof RejectedExecutionException) { - log.debug("An executor rejected a read or write operation on the ClientToProxyConnection (this is normal if the proxy is shutting down). Message: " + cause.getMessage()); - log.warn("A RejectedExecutionException occurred on ClientToProxyConnection", cause); - } else { - log.error("Caught an exception on ClientToProxyConnection", cause); - } - } finally { - // always disconnect the client when an exception occurs on the channel - disconnect(); - } - } - - /*************************************************************************** - * Connection Management - **************************************************************************/ - - /** - * Initialize the {@link ChannelPipeline} for the client to proxy channel. - * LittleProxy acts like a server here. - * - * A {@link ChannelPipeline} invokes the read (Inbound) handlers in - * ascending ordering of the list and then the write (Outbound) handlers in - * descending ordering. - * - * Regarding the Javadoc of {@link HttpObjectAggregator} it's needed to have - * the {@link HttpResponseEncoder} or {@link io.netty.handler.codec.http.HttpRequestEncoder} before the - * {@link HttpObjectAggregator} in the {@link ChannelPipeline}. - * - * @param pipeline - */ - private void initChannelPipeline(ChannelPipeline pipeline) { - log.trace("Configuring ChannelPipeline"); - - pipeline.addLast("bytesReadMonitor", bytesReadMonitor); - pipeline.addLast("bytesWrittenMonitor", bytesWrittenMonitor); - - pipeline.addLast("encoder", new HttpResponseEncoder()); - // We want to allow longer request lines, headers, and chunks - // respectively. - pipeline.addLast("decoder", new HttpRequestDecoder( - proxyServer.getMaxInitialLineLength(), - proxyServer.getMaxHeaderSize(), - proxyServer.getMaxChunkSize())); - - // Enable aggregation for filtering if necessary - int numberOfBytesToBuffer = proxyServer.getFiltersSource() - .getMaximumRequestBufferSizeInBytes(); - if (numberOfBytesToBuffer > 0) { - aggregateContentForFiltering(pipeline, numberOfBytesToBuffer); - } - - pipeline.addLast("requestReadMonitor", requestReadMonitor); - pipeline.addLast("responseWrittenMonitor", responseWrittenMonitor); - - pipeline.addLast( - "idle", - new IdleStateHandler(0, 0, proxyServer - .getIdleConnectionTimeout())); - - pipeline.addLast("handler", this); - } - - /** - * This method takes care of closing client to proxy and/or proxy to server - * connections after finishing a write. - */ - private void closeConnectionsAfterWriteIfNecessary( - ProxyToServerConnection serverConnection, - HttpRequest currentHttpRequest, HttpResponse currentHttpResponse, - HttpObject httpObject) { - boolean closeServerConnection = shouldCloseServerConnection( - currentHttpRequest, currentHttpResponse, httpObject); - boolean closeClientConnection = shouldCloseClientConnection( - currentHttpRequest, currentHttpResponse, httpObject); - - if (closeServerConnection) { - log.trace("Closing remote connection after writing to client"); - serverConnection.disconnect(); - } - - if (closeClientConnection) { - log.trace("Closing connection to client after writes"); - disconnect(); - } - } - - private void forceDisconnect(ProxyToServerConnection serverConnection) { - log.trace("Forcing disconnect"); - serverConnection.disconnect(); - disconnect(); - } - - /** - * Determine whether or not the client connection should be closed. - * - * @param req - * @param res - * @param httpObject - * @return - */ - private boolean shouldCloseClientConnection(HttpRequest req, - HttpResponse res, HttpObject httpObject) { - if (ProxyUtils.isChunked(res)) { - // If the response is chunked, we want to return false unless it's - // the last chunk. If it is the last chunk, then we want to pass - // through to the same close semantics we'd otherwise use. - if (httpObject != null) { - if (!ProxyUtils.isLastChunk(httpObject)) { - String uri = null; - if (req != null) { - uri = req.getUri(); - } - log.trace("Not closing client connection on middle chunk for {}", uri); - return false; - } else { - log.trace("Handling last chunk. Using normal client connection closing rules."); - } - } - } - - if (!HttpHeaders.isKeepAlive(req)) { - log.trace("Closing client connection since request is not keep alive: {}", req); - // Here we simply want to close the connection because the - // client itself has requested it be closed in the request. - return true; - } - - // ignore the response's keep-alive; we can keep this client connection open as long as the client allows it. - - log.trace("Not closing client connection for request: {}", req); - return false; - } - - /** - * Determines if the remote connection should be closed based on the request - * and response pair. If the request is HTTP 1.0 with no keep-alive header, - * for example, the connection should be closed. - * - * This in part determines if we should close the connection. Here's the - * relevant section of RFC 2616: - * - * "HTTP/1.1 defines the "close" connection option for the sender to signal - * that the connection will be closed after completion of the response. For - * example, - * - * Connection: close - * - * in either the request or the response header fields indicates that the - * connection SHOULD NOT be considered `persistent' (section 8.1) after the - * current request/response is complete." - * - * @param req - * The request. - * @param res - * The response. - * @param msg - * The message. - * @return Returns true if the connection should close. - */ - private boolean shouldCloseServerConnection(HttpRequest req, - HttpResponse res, HttpObject msg) { - if (ProxyUtils.isChunked(res)) { - // If the response is chunked, we want to return false unless it's - // the last chunk. If it is the last chunk, then we want to pass - // through to the same close semantics we'd otherwise use. - if (msg != null) { - if (!ProxyUtils.isLastChunk(msg)) { - String uri = null; - if (req != null) { - uri = req.getUri(); - } - log.trace("Not closing server connection on middle chunk for {}", uri); - return false; - } else { - log.trace("Handling last chunk. Using normal server connection closing rules."); - } - } - } - - // ignore the request's keep-alive; we can keep this server connection open as long as the server allows it. - - if (!HttpHeaders.isKeepAlive(res)) { - log.trace("Closing server connection since response is not keep alive: {}", res); - // In this case, we want to honor the Connection: close header - // from the remote server and close that connection. We don't - // necessarily want to close the connection to the client, however - // as it's possible it has other connections open. - return true; - } - - log.trace("Not closing server connection for response: {}", res); - return false; - } - - /*************************************************************************** - * Authentication - **************************************************************************/ - - /** - *

- * Checks whether the given HttpRequest requires authentication. - *

- * - *

- * If the request contains credentials, these are checked. - *

- * - *

- * If authentication is still required, either because no credentials were - * provided or the credentials were wrong, this writes a 407 response to the - * client. - *

- * - * @param request - * @return - */ - private boolean authenticationRequired(HttpRequest request) { - - if (authenticated.get()) { - return false; - } - - final ProxyAuthenticator authenticator = proxyServer - .getProxyAuthenticator(); - - if (authenticator == null) - return false; - - if (!request.headers().contains(HttpHeaders.Names.PROXY_AUTHORIZATION)) { - writeAuthenticationRequired(authenticator.getRealm()); - return true; - } - - List values = request.headers().getAll( - HttpHeaders.Names.PROXY_AUTHORIZATION); - String fullValue = values.iterator().next(); - String value = StringUtils.substringAfter(fullValue, "Basic ").trim(); - - byte[] decodedValue = BaseEncoding.base64().decode(value); - - String decodedString = new String(decodedValue, Charset.forName("UTF-8")); - - String userName = StringUtils.substringBefore(decodedString, ":"); - String password = StringUtils.substringAfter(decodedString, ":"); - if (!authenticator.authenticate(userName, password)) { - writeAuthenticationRequired(authenticator.getRealm()); - return true; - } - - log.debug("Got proxy authorization!"); - // We need to remove the header before sending the request on. - String authentication = request.headers().get( - HttpHeaders.Names.PROXY_AUTHORIZATION); - log.trace(authentication); - request.headers().remove(HttpHeaders.Names.PROXY_AUTHORIZATION); - authenticated.set(true); - return false; - } - - private void writeAuthenticationRequired(String realm) { - String body = "\n" - + "\n" - + "407 Proxy Authentication Required\n" - + "\n" - + "

Proxy Authentication Required

\n" - + "

This server could not verify that you\n" - + "are authorized to access the document\n" - + "requested. Either you supplied the wrong\n" - + "credentials (e.g., bad password), or your\n" - + "browser doesn't understand how to supply\n" - + "the credentials required.

\n" + "\n"; - FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, - HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED, body); - HttpHeaders.setDate(response, new Date()); - response.headers().set("Proxy-Authenticate", - "Basic realm=\"" + (realm == null ? "Restricted Files" : realm) + "\""); - write(response); - } - - /*************************************************************************** - * Request/Response Rewriting - **************************************************************************/ - - /** - * Copy the given {@link HttpRequest} verbatim. - * - * @param original - * @return - */ - private HttpRequest copy(HttpRequest original) { - if (original instanceof FullHttpRequest) { - return ((FullHttpRequest) original).copy(); - } else { - HttpRequest request = new DefaultHttpRequest(original.getProtocolVersion(), - original.getMethod(), original.getUri()); - request.headers().set(original.headers()); - return request; - } - } - - /** - * Chunked encoding is an HTTP 1.1 feature, but sometimes we get a chunked - * response that reports its HTTP version as 1.0. In this case, we change it - * to 1.1. - * - * @param httpResponse - */ - private void fixHttpVersionHeaderIfNecessary(HttpResponse httpResponse) { - String te = httpResponse.headers().get( - HttpHeaders.Names.TRANSFER_ENCODING); - if (StringUtils.isNotBlank(te) - && te.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) { - if (httpResponse.getProtocolVersion() != HttpVersion.HTTP_1_1) { - log.trace("Fixing HTTP version."); - httpResponse.setProtocolVersion(HttpVersion.HTTP_1_1); - } - } - } - - /** - * If and only if our proxy is not running in transparent mode, modify the - * request headers to reflect that it was proxied. - * - * @param httpRequest - */ - private void modifyRequestHeadersToReflectProxying(HttpRequest httpRequest) { - if (!currentServerConnection.hasUpstreamChainedProxy()) { - /* - * We are making the request to the origin server, so must modify - * the 'absolute-URI' into the 'origin-form' as per RFC 7230 - * section 5.3.1. - * - * This must happen even for 'transparent' mode, otherwise the origin - * server could infer that the request came via a proxy server. - */ - log.trace("Modifying request for proxy chaining"); - // Strip host from uri - String uri = httpRequest.getUri(); - String adjustedUri = ProxyUtils.stripHost(uri); - log.trace("Stripped host from uri: {} yielding: {}", uri, - adjustedUri); - httpRequest.setUri(adjustedUri); - } - if (!proxyServer.isTransparent()) { - log.trace("Modifying request headers for proxying"); - - HttpHeaders headers = httpRequest.headers(); - - // Remove sdch from encodings we accept since we can't decode it. - ProxyUtils.removeSdchEncoding(headers); - switchProxyConnectionHeader(headers); - stripConnectionTokens(headers); - stripHopByHopHeaders(headers); - ProxyUtils.addVia(httpRequest, proxyServer.getProxyAlias()); - } - } - - /** - * If and only if our proxy is not running in transparent mode, modify the - * response headers to reflect that it was proxied. - * - * @param httpResponse - * @return - */ - private void modifyResponseHeadersToReflectProxying( - HttpResponse httpResponse) { - if (!proxyServer.isTransparent()) { - HttpHeaders headers = httpResponse.headers(); - - stripConnectionTokens(headers); - stripHopByHopHeaders(headers); - ProxyUtils.addVia(httpResponse, proxyServer.getProxyAlias()); - - /* - * RFC2616 Section 14.18 - * - * A received message that does not have a Date header field MUST be - * assigned one by the recipient if the message will be cached by - * that recipient or gatewayed via a protocol which requires a Date. - */ - if (!headers.contains(HttpHeaders.Names.DATE)) { - HttpHeaders.setDate(httpResponse, new Date()); - } - } - } - - /** - * Switch the de-facto standard "Proxy-Connection" header to "Connection" - * when we pass it along to the remote host. This is largely undocumented - * but seems to be what most browsers and servers expect. - * - * @param headers - * The headers to modify - */ - private void switchProxyConnectionHeader(HttpHeaders headers) { - String proxyConnectionKey = "Proxy-Connection"; - if (headers.contains(proxyConnectionKey)) { - String header = headers.get(proxyConnectionKey); - headers.remove(proxyConnectionKey); - headers.set(HttpHeaders.Names.CONNECTION, header); - } - } - - /** - * RFC2616 Section 14.10 - * - * HTTP/1.1 proxies MUST parse the Connection header field before a message - * is forwarded and, for each connection-token in this field, remove any - * header field(s) from the message with the same name as the - * connection-token. - * - * @param headers - * The headers to modify - */ - private void stripConnectionTokens(HttpHeaders headers) { - if (headers.contains(HttpHeaders.Names.CONNECTION)) { - for (String headerValue : headers.getAll(HttpHeaders.Names.CONNECTION)) { - for (String connectionToken : ProxyUtils.splitCommaSeparatedHeaderValues(headerValue)) { - // do not strip out the Transfer-Encoding header if it is specified in the Connection header, since LittleProxy does not - // normally modify the Transfer-Encoding of the message. - if (!LOWERCASE_TRANSFER_ENCODING_HEADER.equals(connectionToken.toLowerCase(Locale.US))) { - headers.remove(connectionToken); - } - } - } - } - } - - /** - * Removes all headers that should not be forwarded. See RFC 2616 13.5.1 - * End-to-end and Hop-by-hop Headers. - * - * @param headers - * The headers to modify - */ - private void stripHopByHopHeaders(HttpHeaders headers) { - Set headerNames = headers.names(); - for (String headerName : headerNames) { - if (shouldRemoveHopByHopHeader(headerName)) { - headers.remove(headerName); - } - } - } - - /*************************************************************************** - * Miscellaneous - **************************************************************************/ - - /** - * Tells the client that something went wrong trying to proxy its request. If the Bad Gateway is a response to - * an HTTP HEAD request, the response will contain no body, but the Content-Length header will be set to the - * value it would have been if this 502 Bad Gateway were in response to a GET. - * - * @param httpRequest the HttpRequest that is resulting in the Bad Gateway response - * @return true if the connection will be kept open, or false if it will be disconnected - */ - private boolean writeBadGateway(HttpRequest httpRequest) { - String body = "Bad Gateway: " + httpRequest.getUri(); - FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_GATEWAY, body); - - if (ProxyUtils.isHEAD(httpRequest)) { - // don't allow any body content in response to a HEAD request - response.content().clear(); - } - - return respondWithShortCircuitResponse(response); - } - - /** - * Tells the client that the request was malformed or erroneous. If the Bad Request is a response to - * an HTTP HEAD request, the response will contain no body, but the Content-Length header will be set to the - * value it would have been if this Bad Request were in response to a GET. - * - * @return true if the connection will be kept open, or false if it will be disconnected - */ - private boolean writeBadRequest(HttpRequest httpRequest) { - String body = "Bad Request to URI: " + httpRequest.getUri(); - FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST, body); - - if (ProxyUtils.isHEAD(httpRequest)) { - // don't allow any body content in response to a HEAD request - response.content().clear(); - } - - return respondWithShortCircuitResponse(response); - } - - /** - * Tells the client that the connection to the server, or possibly to some intermediary service (such as DNS), timed out. - * If the Gateway Timeout is a response to an HTTP HEAD request, the response will contain no body, but the - * Content-Length header will be set to the value it would have been if this 504 Gateway Timeout were in response to a GET. - * - * @param httpRequest the HttpRequest that is resulting in the Gateway Timeout response - * @return true if the connection will be kept open, or false if it will be disconnected - */ - private boolean writeGatewayTimeout(HttpRequest httpRequest) { - String body = "Gateway Timeout"; - FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, - HttpResponseStatus.GATEWAY_TIMEOUT, body); - - if (httpRequest != null && ProxyUtils.isHEAD(httpRequest)) { - // don't allow any body content in response to a HEAD request - response.content().clear(); - } - - return respondWithShortCircuitResponse(response); - } - - /** - * Responds to the client with the specified "short-circuit" response. The response will be sent through the - * {@link HttpFilters#proxyToClientResponse(HttpObject)} filter method before writing it to the client. The client - * will not be disconnected, unless the response includes a "Connection: close" header, or the filter returns - * a null HttpResponse (in which case no response will be written to the client and the connection will be - * disconnected immediately). If the response is not a Bad Gateway or Gateway Timeout response, the response's headers - * will be modified to reflect proxying, including adding a Via header, Date header, etc. - * - * @param httpResponse the response to return to the client - * @return true if the connection will be kept open, or false if it will be disconnected. - */ - private boolean respondWithShortCircuitResponse(HttpResponse httpResponse) { - // we are sending a response to the client, so we are done handling this request - this.currentRequest = null; - - HttpResponse filteredResponse = (HttpResponse) currentFilters.proxyToClientResponse(httpResponse); - if (filteredResponse == null) { - disconnect(); - return false; - } - - // allow short-circuit messages to close the connection. normally the Connection header would be stripped when modifying - // the message for proxying, so save the keep-alive status before the modifications are made. - boolean isKeepAlive = HttpHeaders.isKeepAlive(httpResponse); - - // if the response is not a Bad Gateway or Gateway Timeout, modify the headers "as if" the short-circuit response were proxied - int statusCode = httpResponse.getStatus().code(); - if (statusCode != HttpResponseStatus.BAD_GATEWAY.code() && statusCode != HttpResponseStatus.GATEWAY_TIMEOUT.code()) { - modifyResponseHeadersToReflectProxying(httpResponse); - } - - // restore the keep alive status, if it was overwritten when modifying headers for proxying - HttpHeaders.setKeepAlive(httpResponse, isKeepAlive); - - write(httpResponse); - - if (ProxyUtils.isLastChunk(httpResponse)) { - writeEmptyBuffer(); - } - - if (!HttpHeaders.isKeepAlive(httpResponse)) { - disconnect(); - return false; - } - - return true; - } - - /** - * Identify the host and port for a request. - * - * @param httpRequest - * @return - */ - private String identifyHostAndPort(HttpRequest httpRequest) { - String hostAndPort = ProxyUtils.parseHostAndPort(httpRequest); - if (StringUtils.isBlank(hostAndPort)) { - List hosts = httpRequest.headers().getAll( - HttpHeaders.Names.HOST); - if (hosts != null && !hosts.isEmpty()) { - hostAndPort = hosts.get(0); - } - } - - return hostAndPort; - } - - /** - * Write an empty buffer at the end of a chunked transfer. We need to do - * this to handle the way Netty creates HttpChunks from responses that - * aren't in fact chunked from the remote server using Transfer-Encoding: - * chunked. Netty turns these into pseudo-chunked responses in cases where - * the response would otherwise fill up too much memory or where the length - * of the response body is unknown. This is handy because it means we can - * start streaming response bodies back to the client without reading the - * entire response. The problem is that in these pseudo-cases the last chunk - * is encoded to null, and this thwarts normal ChannelFutures from - * propagating operationComplete events on writes to appropriate channel - * listeners. We work around this by writing an empty buffer in those cases - * and using the empty buffer's future instead to handle any operations we - * need to when responses are fully written back to clients. - */ - private void writeEmptyBuffer() { - write(Unpooled.EMPTY_BUFFER); - } - - public boolean isMitming() { - return mitming; - } - - protected void setMitming(boolean isMitming) { - this.mitming = isMitming; - } - - /*************************************************************************** - * Activity Tracking/Statistics - * - * We track statistics on bytes, requests and responses by adding handlers - * at the appropriate parts of the pipeline (see initChannelPipeline()). - **************************************************************************/ - private final BytesReadMonitor bytesReadMonitor = new BytesReadMonitor() { - @Override - protected void bytesRead(int numberOfBytes) { - FlowContext flowContext = flowContext(); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.bytesReceivedFromClient(flowContext, numberOfBytes); - } - } - }; - - private RequestReadMonitor requestReadMonitor = new RequestReadMonitor() { - @Override - protected void requestRead(HttpRequest httpRequest) { - FlowContext flowContext = flowContext(); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.requestReceivedFromClient(flowContext, httpRequest); - } - } - }; - - private BytesWrittenMonitor bytesWrittenMonitor = new BytesWrittenMonitor() { - @Override - protected void bytesWritten(int numberOfBytes) { - FlowContext flowContext = flowContext(); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.bytesSentToClient(flowContext, numberOfBytes); - } - } - }; - - private ResponseWrittenMonitor responseWrittenMonitor = new ResponseWrittenMonitor() { - @Override - protected void responseWritten(HttpResponse httpResponse) { - FlowContext flowContext = flowContext(); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.responseSentToClient(flowContext, - httpResponse); - } - } - }; - - private void recordClientConnected() { - try { - InetSocketAddress clientAddress = getClientAddress(); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.clientConnected(clientAddress); - } - } catch (Exception e) { - log.error("Unable to recordClientConnected", e); - } - } - - private void recordClientSSLHandshakeSucceeded() { - try { - InetSocketAddress clientAddress = getClientAddress(); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.clientSSLHandshakeSucceeded( - clientAddress, clientSslSession); - } - } catch (Exception e) { - log.error("Unable to recorClientSSLHandshakeSucceeded", e); - } - } - - private void recordClientDisconnected() { - try { - InetSocketAddress clientAddress = getClientAddress(); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.clientDisconnected( - clientAddress, clientSslSession); - } - } catch (Exception e) { - log.error("Unable to recordClientDisconnected", e); - } - } - - public InetSocketAddress getClientAddress() { - if (channel == null) { - return null; - } - return (InetSocketAddress) channel.remoteAddress(); - } - - private FlowContext flowContext() { - if (currentServerConnection != null) { - return new FullFlowContext(this, currentServerConnection); - } else { - return new FlowContext(this); - } - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlow.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlow.java deleted file mode 100644 index 10273ee9fe..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlow.java +++ /dev/null @@ -1,219 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; -import lombok.extern.slf4j.Slf4j; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * Coordinates the various steps involved in establishing a connection, such as - * establishing a socket connection, SSL handshaking, HTTP CONNECT request - * processing, and so on. - */ -@Slf4j -class ConnectionFlow { - private Queue steps = new ConcurrentLinkedQueue(); - - private final ClientToProxyConnection clientConnection; - private final ProxyToServerConnection serverConnection; - private volatile ConnectionFlowStep currentStep; - private volatile boolean suppressInitialRequest = false; - private final Object connectLock; - - /** - * Construct a new {@link ConnectionFlow} for the given client and server - * connections. - * - * @param clientConnection - * @param serverConnection - * @param connectLock - * an object that's shared by {@link ConnectionFlow} and - * {@link ProxyToServerConnection} and that is used for - * synchronizing the reader and writer threads that are both - * involved during the establishing of a connection. - */ - ConnectionFlow( - ClientToProxyConnection clientConnection, - ProxyToServerConnection serverConnection, - Object connectLock) { - super(); - this.clientConnection = clientConnection; - this.serverConnection = serverConnection; - this.connectLock = connectLock; - } - - /** - * Add a {@link ConnectionFlowStep} to this flow. - * - * @param step - * @return - */ - ConnectionFlow then(ConnectionFlowStep step) { - steps.add(step); - return this; - } - - /** - * While we're in the process of connecting, any messages read by the - * {@link ProxyToServerConnection} are passed to this method, which passes - * it on to {@link ConnectionFlowStep#read(ConnectionFlow, Object)} for the - * current {@link ConnectionFlowStep}. - * - * @param msg - */ - void read(Object msg) { - if (this.currentStep != null) { - this.currentStep.read(this, msg); - } - } - - /** - * Starts the connection flow, notifying the {@link ClientToProxyConnection} - * that we've started. - */ - void start() { - clientConnection.serverConnectionFlowStarted(serverConnection); - advance(); - } - - /** - *

- * Advances the flow. {@link #advance()} will be called until we're either - * out of steps, or a step has failed. - *

- */ - void advance() { - currentStep = steps.poll(); - if (currentStep == null) { - succeed(); - } else { - processCurrentStep(); - } - } - - /** - *

- * Process the current {@link ConnectionFlowStep}. With each step, we: - *

- * - *
    - *
  1. Change the state of the associated {@link ProxyConnection} to the - * value of {@link ConnectionFlowStep#getState()}
  2. - *
  3. Call {@link ConnectionFlowStep#execute()}
  4. - *
  5. On completion of the {@link Future} returned by - * {@link ConnectionFlowStep#execute()}, check the success.
  6. - *
  7. If successful, we call back into - * {@link ConnectionFlowStep#onSuccess(ConnectionFlow)}.
  8. - *
  9. If unsuccessful, we call {@link #fail()}, stopping the connection - * flow
  10. - *
- */ - private void processCurrentStep() { - final ProxyConnection connection = currentStep.getConnection(); - - log.debug("Processing connection flow step: {}", currentStep); - connection.become(currentStep.getState()); - suppressInitialRequest = suppressInitialRequest - || currentStep.shouldSuppressInitialRequest(); - - if (currentStep.shouldExecuteOnEventLoop()) { - connection.ctx.executor().submit(new Runnable() { - @Override - public void run() { - doProcessCurrentStep(); - } - }); - } else { - doProcessCurrentStep(); - } - } - - /** - * Does the work of processing the current step, checking the result and - * handling success/failure. - */ - @SuppressWarnings("unchecked") - private void doProcessCurrentStep() { - currentStep.execute().addListener( - new GenericFutureListener>() { - public void operationComplete( - Future future) - throws Exception { - synchronized (connectLock) { - if (future.isSuccess()) { - log.trace("ConnectionFlowStep succeeded"); - currentStep - .onSuccess(ConnectionFlow.this); - } else { - log.error("ConnectionFlowStep failed", - future.cause()); - fail(future.cause()); - } - } - }; - }); - } - - /** - * Called when the flow is complete and successful. Notifies the - * {@link ProxyToServerConnection} that we succeeded. - */ - void succeed() { - synchronized (connectLock) { - log.trace( - "Connection flow completed successfully: {}", currentStep); - serverConnection.connectionSucceeded(!suppressInitialRequest); - notifyThreadsWaitingForConnection(); - } - } - - /** - * Called when the flow fails at some {@link ConnectionFlowStep}. - * Disconnects the {@link ProxyToServerConnection} and informs the - * {@link ClientToProxyConnection} that our connection failed. - */ - @SuppressWarnings("unchecked") - void fail(final Throwable cause) { - final ConnectionState lastStateBeforeFailure = serverConnection - .getCurrentState(); - serverConnection.disconnect().addListener( - new GenericFutureListener() { - @Override - public void operationComplete(Future future) - throws Exception { - synchronized (connectLock) { - if (!clientConnection.serverConnectionFailed( - serverConnection, - lastStateBeforeFailure, - cause)) { - // the connection to the server failed and we are not retrying, so transition to the - // DISCONNECTED state - serverConnection.become(ConnectionState.DISCONNECTED); - - // We are not retrying our connection, let anyone waiting for a connection know that we're done - notifyThreadsWaitingForConnection(); - } - } - } - }); - } - - /** - * Like {@link #fail(Throwable)} but with no cause. - */ - void fail() { - fail(null); - } - - /** - * Once we've finished recording our connection and written our initial - * request, we can notify anyone who is waiting on the connection that it's - * okay to proceed. - */ - private void notifyThreadsWaitingForConnection() { - connectLock.notifyAll(); - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlowStep.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlowStep.java deleted file mode 100644 index 3203aa0c69..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionFlowStep.java +++ /dev/null @@ -1,116 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import io.netty.util.concurrent.Future; -import lombok.extern.slf4j.Slf4j; - -/** - * Represents a phase in a {@link ConnectionFlow}. - */ -@Slf4j -abstract class ConnectionFlowStep { - private final ProxyConnection connection; - private final ConnectionState state; - - /** - * Construct a new step in a connection flow. - * - * @param connection - * the connection that we're working on - * @param state - * the state that the connection will show while we're processing - * this step - */ - ConnectionFlowStep(ProxyConnection connection, - ConnectionState state) { - super(); - this.connection = connection; - this.state = state; - } - - ProxyConnection getConnection() { - return connection; - } - - ConnectionState getState() { - return state; - } - - /** - * Indicates whether or not to suppress the initial request. Defaults to - * false, can be overridden. - * - * @return - */ - boolean shouldSuppressInitialRequest() { - return false; - } - - /** - *

- * Indicates whether or not this step should be executed on the channel's - * event loop. Defaults to true, can be overridden. - *

- * - *

- * If this step modifies the pipeline, for example by adding/removing - * handlers, it's best to make it execute on the event loop. - *

- * - * - * @return - */ - boolean shouldExecuteOnEventLoop() { - return true; - } - - /** - * Implement this method to actually do the work involved in this step of - * the flow. - * - * @return - */ - protected abstract Future execute(); - - /** - * When the flow determines that this step was successful, it calls into - * this method. The default implementation simply continues with the flow. - * Other implementations may choose to not continue and instead wait for a - * message or something like that. - * - * @param flow - */ - void onSuccess(ConnectionFlow flow) { - flow.advance(); - } - - /** - *

- * Any messages that are read from the underlying connection while we're at - * this step of the connection flow are passed to this method. - *

- * - *

- * The default implementation ignores the message and logs this, since we - * weren't really expecting a message here. - *

- * - *

- * Some {@link ConnectionFlowStep}s do need to read the messages, so they - * override this method as appropriate. - *

- * - * @param flow - * our {@link ConnectionFlow} - * @param msg - * the message read from the underlying connection - */ - void read(ConnectionFlow flow, Object msg) { - log.trace("Received message while in the middle of connecting: {}", msg); - } - - @Override - public String toString() { - return state.toString(); - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionState.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionState.java deleted file mode 100644 index 55a0a534d0..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ConnectionState.java +++ /dev/null @@ -1,81 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -enum ConnectionState { - /** - * Connection attempting to connect. - */ - CONNECTING(true), - - /** - * In the middle of doing an SSL handshake. - */ - HANDSHAKING(true), - - /** - * In the process of negotiating an HTTP CONNECT from the client. - */ - NEGOTIATING_CONNECT(true), - - /** - * When forwarding a CONNECT to a chained proxy, we await the CONNECTION_OK - * message from the proxy. - */ - AWAITING_CONNECT_OK(true), - - /** - * Connected but waiting for proxy authentication. - */ - AWAITING_PROXY_AUTHENTICATION, - - /** - * Connected and awaiting initial message (e.g. HttpRequest or - * HttpResponse). - */ - AWAITING_INITIAL, - - /** - * Connected and awaiting HttpContent chunk. - */ - AWAITING_CHUNK, - - /** - * We've asked the client to disconnect, but it hasn't yet. - */ - DISCONNECT_REQUESTED(), - - /** - * Disconnected - */ - DISCONNECTED(); - - private final boolean partOfConnectionFlow; - - ConnectionState(boolean partOfConnectionFlow) { - this.partOfConnectionFlow = partOfConnectionFlow; - } - - ConnectionState() { - this(false); - } - - /** - * Indicates whether this ConnectionState corresponds to a step in a - * {@link ConnectionFlow}. This is useful to distinguish so that we know - * whether or not we're in the process of establishing a connection. - * - * @return true if part of connection flow, otherwise false - */ - public boolean isPartOfConnectionFlow() { - return partOfConnectionFlow; - } - - /** - * Indicates whether this ConnectionState is no longer waiting for messages and is either in the process of disconnecting - * or is already disconnected. - * - * @return true if the connection state is {@link #DISCONNECT_REQUESTED} or {@link #DISCONNECTED}, otherwise false - */ - public boolean isDisconnectingOrDisconnected() { - return this == DISCONNECT_REQUESTED || this == DISCONNECTED; - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/DefaultHttpProxyServer.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/DefaultHttpProxyServer.java deleted file mode 100644 index 2edc6429a9..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/DefaultHttpProxyServer.java +++ /dev/null @@ -1,905 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import io.netty.bootstrap.ChannelFactory; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.*; -import io.netty.channel.group.ChannelGroup; -import io.netty.channel.group.ChannelGroupFuture; -import io.netty.channel.group.DefaultChannelGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.channel.udt.nio.NioUdtProvider; -import io.netty.handler.traffic.GlobalTrafficShapingHandler; -import io.netty.util.concurrent.GlobalEventExecutor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.*; - -import javax.net.ssl.SSLEngine; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.Properties; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - *

- * Primary implementation of an {@link HttpProxyServer}. - *

- * - *

- * {@link DefaultHttpProxyServer} is bootstrapped by calling - * {@link #bootstrap()} or {@link #bootstrapFromFile(String)}, and then calling - * {@link DefaultHttpProxyServerBootstrap#start()}. For example: - *

- * - *
- * DefaultHttpProxyServer server =
- *         DefaultHttpProxyServer
- *                 .bootstrap()
- *                 .withPort(8090)
- *                 .start();
- * 
- * - */ -public class DefaultHttpProxyServer implements HttpProxyServer { - private static final Logger LOG = LoggerFactory.getLogger(DefaultHttpProxyServer.class); - - /** - * The interval in ms at which the GlobalTrafficShapingHandler will run to compute and throttle the - * proxy-to-server bandwidth. - */ - private static final long TRAFFIC_SHAPING_CHECK_INTERVAL_MS = 250L; - - private static final int MAX_INITIAL_LINE_LENGTH_DEFAULT = 8192; - private static final int MAX_HEADER_SIZE_DEFAULT = 8192*2; - private static final int MAX_CHUNK_SIZE_DEFAULT = 8192*2; - - /** - * The proxy alias to use in the Via header if no explicit proxy alias is specified and the hostname of the local - * machine cannot be resolved. - */ - private static final String FALLBACK_PROXY_ALIAS = "littleproxy"; - - /** - * Our {@link ServerGroup}. Multiple proxy servers can share the same - * ServerGroup in order to reuse threads and other such resources. - */ - private final ServerGroup serverGroup; - - private final TransportProtocol transportProtocol; - /* - * The address that the server will attempt to bind to. - */ - private final InetSocketAddress requestedAddress; - /* - * The actual address to which the server is bound. May be different from the requestedAddress in some circumstances, - * for example when the requested port is 0. - */ - private volatile InetSocketAddress localAddress; - private volatile InetSocketAddress boundAddress; - private final SslEngineSource sslEngineSource; - private final boolean authenticateSslClients; - private final ProxyAuthenticator proxyAuthenticator; - private final ChainedProxyManager chainProxyManager; - private final MitmManager mitmManager; - private final HttpFiltersSource filtersSource; - private final boolean transparent; - private volatile int connectTimeout; - private volatile int idleConnectionTimeout; - private final HostResolver serverResolver; - private volatile GlobalTrafficShapingHandler globalTrafficShapingHandler; - private final int maxInitialLineLength; - private final int maxHeaderSize; - private final int maxChunkSize; - private final boolean allowRequestsToOriginServer; - - /** - * The alias or pseudonym for this proxy, used when adding the Via header. - */ - private final String proxyAlias; - - /** - * True when the proxy has already been stopped by calling {@link #stop()} or {@link #abort()}. - */ - private final AtomicBoolean stopped = new AtomicBoolean(false); - - /** - * Track all ActivityTrackers for tracking proxying activity. - */ - private final Collection activityTrackers = new ConcurrentLinkedQueue(); - - /** - * Keep track of all channels created by this proxy server for later shutdown when the proxy is stopped. - */ - private final ChannelGroup allChannels = new DefaultChannelGroup("HTTP-Proxy-Server", GlobalEventExecutor.INSTANCE); - - /** - * JVM shutdown hook to shutdown this proxy server. Declared as a class-level variable to allow removing the shutdown hook when the - * proxy server is stopped normally. - */ - private final Thread jvmShutdownHook = new Thread(new Runnable() { - @Override - public void run() { - abort(); - } - }, "LittleProxy-JVM-shutdown-hook"); - - /** - * Bootstrap a new {@link DefaultHttpProxyServer} starting from scratch. - * - * @return - */ - public static HttpProxyServerBootstrap bootstrap() { - return new DefaultHttpProxyServerBootstrap(); - } - - /** - * Bootstrap a new {@link DefaultHttpProxyServer} using defaults from the - * given file. - * - * @param path - * @return - */ - public static HttpProxyServerBootstrap bootstrapFromFile(String path) { - final File propsFile = new File(path); - Properties props = new Properties(); - - if (propsFile.isFile()) { - try (InputStream is = new FileInputStream(propsFile)) { - props.load(is); - } catch (final IOException e) { - LOG.warn("Could not load props file?", e); - } - } - - return new DefaultHttpProxyServerBootstrap(props); - } - - /** - * Creates a new proxy server. - * - * @param serverGroup - * our ServerGroup for shared thread pools and such - * @param transportProtocol - * The protocol to use for data transport - * @param requestedAddress - * The address on which this server will listen - * @param sslEngineSource - * (optional) if specified, this Proxy will encrypt inbound - * connections from clients using an {@link SSLEngine} obtained - * from this {@link SslEngineSource}. - * @param authenticateSslClients - * Indicate whether or not to authenticate clients when using SSL - * @param proxyAuthenticator - * (optional) If specified, requests to the proxy will be - * authenticated using HTTP BASIC authentication per the provided - * {@link ProxyAuthenticator} - * @param chainProxyManager - * The proxy to send requests to if chaining proxies. Typically - * null. - * @param mitmManager - * The {@link MitmManager} to use for man in the middle'ing - * CONNECT requests - * @param filtersSource - * Source for {@link HttpFilters} - * @param transparent - * If true, this proxy will run as a transparent proxy. This will - * not modify the response, and will only modify the request to - * amend the URI if the target is the origin server (to comply - * with RFC 7230 section 5.3.1). - * @param idleConnectionTimeout - * The timeout (in seconds) for auto-closing idle connections. - * @param activityTrackers - * for tracking activity on this proxy - * @param connectTimeout - * number of milliseconds to wait to connect to the upstream - * server - * @param serverResolver - * the {@link HostResolver} to use for resolving server addresses - * @param readThrottleBytesPerSecond - * read throttle bandwidth - * @param writeThrottleBytesPerSecond - * write throttle bandwidth - * @param maxInitialLineLength - * @param maxHeaderSize - * @param maxChunkSize - * @param allowRequestsToOriginServer - * when true, allow the proxy to handle requests that contain an origin-form URI, as defined in RFC 7230 5.3.1 - */ - private DefaultHttpProxyServer(ServerGroup serverGroup, - TransportProtocol transportProtocol, - InetSocketAddress requestedAddress, - SslEngineSource sslEngineSource, - boolean authenticateSslClients, - ProxyAuthenticator proxyAuthenticator, - ChainedProxyManager chainProxyManager, - MitmManager mitmManager, - HttpFiltersSource filtersSource, - boolean transparent, - int idleConnectionTimeout, - Collection activityTrackers, - int connectTimeout, - HostResolver serverResolver, - long readThrottleBytesPerSecond, - long writeThrottleBytesPerSecond, - InetSocketAddress localAddress, - String proxyAlias, - int maxInitialLineLength, - int maxHeaderSize, - int maxChunkSize, - boolean allowRequestsToOriginServer) { - this.serverGroup = serverGroup; - this.transportProtocol = transportProtocol; - this.requestedAddress = requestedAddress; - this.sslEngineSource = sslEngineSource; - this.authenticateSslClients = authenticateSslClients; - this.proxyAuthenticator = proxyAuthenticator; - this.chainProxyManager = chainProxyManager; - this.mitmManager = mitmManager; - this.filtersSource = filtersSource; - this.transparent = transparent; - this.idleConnectionTimeout = idleConnectionTimeout; - if (activityTrackers != null) { - this.activityTrackers.addAll(activityTrackers); - } - this.connectTimeout = connectTimeout; - this.serverResolver = serverResolver; - - if (writeThrottleBytesPerSecond > 0 || readThrottleBytesPerSecond > 0) { - this.globalTrafficShapingHandler = createGlobalTrafficShapingHandler(transportProtocol, readThrottleBytesPerSecond, writeThrottleBytesPerSecond); - } else { - this.globalTrafficShapingHandler = null; - } - this.localAddress = localAddress; - - if (proxyAlias == null) { - // attempt to resolve the name of the local machine. if it cannot be resolved, use the fallback name. - String hostname = ProxyUtils.getHostName(); - if (hostname == null) { - hostname = FALLBACK_PROXY_ALIAS; - } - this.proxyAlias = hostname; - } else { - this.proxyAlias = proxyAlias; - } - this.maxInitialLineLength = maxInitialLineLength; - this.maxHeaderSize = maxHeaderSize; - this.maxChunkSize = maxChunkSize; - this.allowRequestsToOriginServer = allowRequestsToOriginServer; - } - - /** - * Creates a new GlobalTrafficShapingHandler for this HttpProxyServer, using this proxy's proxyToServerEventLoop. - * - * @param transportProtocol - * @param readThrottleBytesPerSecond - * @param writeThrottleBytesPerSecond - * - * @return - */ - private GlobalTrafficShapingHandler createGlobalTrafficShapingHandler(TransportProtocol transportProtocol, long readThrottleBytesPerSecond, long writeThrottleBytesPerSecond) { - EventLoopGroup proxyToServerEventLoop = this.getProxyToServerWorkerFor(transportProtocol); - return new GlobalTrafficShapingHandler(proxyToServerEventLoop, - writeThrottleBytesPerSecond, - readThrottleBytesPerSecond, - TRAFFIC_SHAPING_CHECK_INTERVAL_MS, - Long.MAX_VALUE); - } - - boolean isTransparent() { - return transparent; - } - - @Override - public int getIdleConnectionTimeout() { - return idleConnectionTimeout; - } - - @Override - public void setIdleConnectionTimeout(int idleConnectionTimeout) { - this.idleConnectionTimeout = idleConnectionTimeout; - } - - @Override - public int getConnectTimeout() { - return connectTimeout; - } - - @Override - public void setConnectTimeout(int connectTimeoutMs) { - this.connectTimeout = connectTimeoutMs; - } - - public HostResolver getServerResolver() { - return serverResolver; - } - - public InetSocketAddress getLocalAddress() { - return localAddress; - } - - @Override - public InetSocketAddress getListenAddress() { - return boundAddress; - } - - @Override - public void setThrottle(long readThrottleBytesPerSecond, long writeThrottleBytesPerSecond) { - if (globalTrafficShapingHandler != null) { - globalTrafficShapingHandler.configure(writeThrottleBytesPerSecond, readThrottleBytesPerSecond); - } else { - // don't create a GlobalTrafficShapingHandler if throttling was not enabled and is still not enabled - if (readThrottleBytesPerSecond > 0 || writeThrottleBytesPerSecond > 0) { - globalTrafficShapingHandler = createGlobalTrafficShapingHandler(transportProtocol, readThrottleBytesPerSecond, writeThrottleBytesPerSecond); - } - } - } - - public long getReadThrottle() { - return globalTrafficShapingHandler.getReadLimit(); - } - - public long getWriteThrottle() { - return globalTrafficShapingHandler.getWriteLimit(); - } - - public int getMaxInitialLineLength() { - return maxInitialLineLength; - } - - public int getMaxHeaderSize() { - return maxHeaderSize; - } - - public int getMaxChunkSize() { - return maxChunkSize; - } - - public boolean isAllowRequestsToOriginServer() { - return allowRequestsToOriginServer; - } - - @Override - public HttpProxyServerBootstrap clone() { - return new DefaultHttpProxyServerBootstrap(serverGroup, - transportProtocol, - new InetSocketAddress(requestedAddress.getAddress(), - requestedAddress.getPort() == 0 ? 0 : requestedAddress.getPort() + 1), - sslEngineSource, - authenticateSslClients, - proxyAuthenticator, - chainProxyManager, - mitmManager, - filtersSource, - transparent, - idleConnectionTimeout, - activityTrackers, - connectTimeout, - serverResolver, - globalTrafficShapingHandler != null ? globalTrafficShapingHandler.getReadLimit() : 0, - globalTrafficShapingHandler != null ? globalTrafficShapingHandler.getWriteLimit() : 0, - localAddress, - proxyAlias, - maxInitialLineLength, - maxHeaderSize, - maxChunkSize, - allowRequestsToOriginServer); - } - - @Override - public void stop() { - doStop(true); - } - - @Override - public void abort() { - doStop(false); - } - - /** - * Performs cleanup necessary to stop the server. Closes all channels opened by the server and unregisters this - * server from the server group. - * - * @param graceful when true, waits for requests to terminate before stopping the server - */ - protected void doStop(boolean graceful) { - // only stop the server if it hasn't already been stopped - if (stopped.compareAndSet(false, true)) { - if (graceful) { - LOG.info("Shutting down proxy server gracefully"); - } else { - LOG.info("Shutting down proxy server immediately (non-graceful)"); - } - - closeAllChannels(graceful); - - serverGroup.unregisterProxyServer(this, graceful); - - // remove the shutdown hook that was added when the proxy was started, since it has now been stopped - try { - Runtime.getRuntime().removeShutdownHook(jvmShutdownHook); - } catch (IllegalStateException e) { - // ignore -- IllegalStateException means the VM is already shutting down - } - - LOG.info("Done shutting down proxy server"); - } - } - - /** - * Register a new {@link Channel} with this server, for later closing. - * - * @param channel - */ - protected void registerChannel(Channel channel) { - allChannels.add(channel); - } - - /** - * Closes all channels opened by this proxy server. - * - * @param graceful when false, attempts to shutdown all channels immediately and ignores any channel-closing exceptions - */ - protected void closeAllChannels(boolean graceful) { - LOG.info("Closing all channels " + (graceful ? "(graceful)" : "(non-graceful)")); - - ChannelGroupFuture future = allChannels.close(); - - // if this is a graceful shutdown, log any channel closing failures. if this isn't a graceful shutdown, ignore them. - if (graceful) { - try { - future.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - - LOG.warn("Interrupted while waiting for channels to shut down gracefully."); - } - - if (!future.isSuccess()) { - for (ChannelFuture cf : future) { - if (!cf.isSuccess()) { - LOG.info("Unable to close channel. Cause of failure for {} is {}", cf.channel(), cf.cause()); - } - } - } - } - } - - private HttpProxyServer start() { - if (!serverGroup.isStopped()) { - LOG.info("Starting proxy at address: " + this.requestedAddress); - - serverGroup.registerProxyServer(this); - - doStart(); - } else { - throw new IllegalStateException("Attempted to start proxy, but proxy's server group is already stopped"); - } - - return this; - } - - private void doStart() { - ServerBootstrap serverBootstrap = new ServerBootstrap().group( - serverGroup.getClientToProxyAcceptorPoolForTransport(transportProtocol), - serverGroup.getClientToProxyWorkerPoolForTransport(transportProtocol)); - - ChannelInitializer initializer = new ChannelInitializer() { - protected void initChannel(Channel ch) throws Exception { - new ClientToProxyConnection( - DefaultHttpProxyServer.this, - sslEngineSource, - authenticateSslClients, - ch.pipeline(), - globalTrafficShapingHandler); - }; - }; - switch (transportProtocol) { - case TCP: - LOG.info("Proxy listening with TCP transport"); - serverBootstrap.channelFactory(new ChannelFactory() { - @Override - public ServerChannel newChannel() { - return new NioServerSocketChannel(); - } - }); - break; - case UDT: - LOG.info("Proxy listening with UDT transport"); - serverBootstrap.channelFactory(NioUdtProvider.BYTE_ACCEPTOR) - .option(ChannelOption.SO_BACKLOG, 10) - .option(ChannelOption.SO_REUSEADDR, true); - break; - default: - throw new UnknownTransportProtocolException(transportProtocol); - } - serverBootstrap.childHandler(initializer); - ChannelFuture future = serverBootstrap.bind(requestedAddress) - .addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) - throws Exception { - if (future.isSuccess()) { - registerChannel(future.channel()); - } - } - }).awaitUninterruptibly(); - - Throwable cause = future.cause(); - if (cause != null) { - throw new RuntimeException(cause); - } - - this.boundAddress = ((InetSocketAddress) future.channel().localAddress()); - LOG.info("Proxy started at address: " + this.boundAddress); - - Runtime.getRuntime().addShutdownHook(jvmShutdownHook); - } - - protected ChainedProxyManager getChainProxyManager() { - return chainProxyManager; - } - - protected MitmManager getMitmManager() { - return mitmManager; - } - - protected SslEngineSource getSslEngineSource() { - return sslEngineSource; - } - - protected ProxyAuthenticator getProxyAuthenticator() { - return proxyAuthenticator; - } - - public HttpFiltersSource getFiltersSource() { - return filtersSource; - } - - protected Collection getActivityTrackers() { - return activityTrackers; - } - - public String getProxyAlias() { - return proxyAlias; - } - - - protected EventLoopGroup getProxyToServerWorkerFor(TransportProtocol transportProtocol) { - return serverGroup.getProxyToServerWorkerPoolForTransport(transportProtocol); - } - - // TODO: refactor bootstrap into a separate class - private static class DefaultHttpProxyServerBootstrap implements HttpProxyServerBootstrap - { - private String name = "LittleProxy"; - private ServerGroup serverGroup = null; - private TransportProtocol transportProtocol = TransportProtocol.TCP; - private InetSocketAddress requestedAddress; - private int port = 8080; - private boolean allowLocalOnly = true; - private SslEngineSource sslEngineSource = null; - private boolean authenticateSslClients = true; - private ProxyAuthenticator proxyAuthenticator = null; - private ChainedProxyManager chainProxyManager = null; - private MitmManager mitmManager = null; - private HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter(); - private boolean transparent = false; - private int idleConnectionTimeout = 70; - private Collection activityTrackers = new ConcurrentLinkedQueue(); - private int connectTimeout = 40000; - private HostResolver serverResolver = new DefaultHostResolver(); - private long readThrottleBytesPerSecond; - private long writeThrottleBytesPerSecond; - private InetSocketAddress localAddress; - private String proxyAlias; - private int clientToProxyAcceptorThreads = ServerGroup.DEFAULT_INCOMING_ACCEPTOR_THREADS; - private int clientToProxyWorkerThreads = ServerGroup.DEFAULT_INCOMING_WORKER_THREADS; - private int proxyToServerWorkerThreads = ServerGroup.DEFAULT_OUTGOING_WORKER_THREADS; - private int maxInitialLineLength = MAX_INITIAL_LINE_LENGTH_DEFAULT; - private int maxHeaderSize = MAX_HEADER_SIZE_DEFAULT; - private int maxChunkSize = MAX_CHUNK_SIZE_DEFAULT; - private boolean allowRequestToOriginServer = false; - - private DefaultHttpProxyServerBootstrap() { - } - - private DefaultHttpProxyServerBootstrap( - ServerGroup serverGroup, - TransportProtocol transportProtocol, - InetSocketAddress requestedAddress, - SslEngineSource sslEngineSource, - boolean authenticateSslClients, - ProxyAuthenticator proxyAuthenticator, - ChainedProxyManager chainProxyManager, - MitmManager mitmManager, - HttpFiltersSource filtersSource, - boolean transparent, int idleConnectionTimeout, - Collection activityTrackers, - int connectTimeout, HostResolver serverResolver, - long readThrottleBytesPerSecond, - long writeThrottleBytesPerSecond, - InetSocketAddress localAddress, - String proxyAlias, - int maxInitialLineLength, - int maxHeaderSize, - int maxChunkSize, - boolean allowRequestToOriginServer) { - this.serverGroup = serverGroup; - this.transportProtocol = transportProtocol; - this.requestedAddress = requestedAddress; - this.port = requestedAddress.getPort(); - this.sslEngineSource = sslEngineSource; - this.authenticateSslClients = authenticateSslClients; - this.proxyAuthenticator = proxyAuthenticator; - this.chainProxyManager = chainProxyManager; - this.mitmManager = mitmManager; - this.filtersSource = filtersSource; - this.transparent = transparent; - this.idleConnectionTimeout = idleConnectionTimeout; - if (activityTrackers != null) { - this.activityTrackers.addAll(activityTrackers); - } - this.connectTimeout = connectTimeout; - this.serverResolver = serverResolver; - this.readThrottleBytesPerSecond = readThrottleBytesPerSecond; - this.writeThrottleBytesPerSecond = writeThrottleBytesPerSecond; - this.localAddress = localAddress; - this.proxyAlias = proxyAlias; - this.maxInitialLineLength = maxInitialLineLength; - this.maxHeaderSize = maxHeaderSize; - this.maxChunkSize = maxChunkSize; - this.allowRequestToOriginServer = allowRequestToOriginServer; - } - - private DefaultHttpProxyServerBootstrap(Properties props) { - this.withUseDnsSec(ProxyUtils.extractBooleanDefaultFalse( - props, "dnssec")); - this.transparent = ProxyUtils.extractBooleanDefaultFalse( - props, "transparent"); - this.idleConnectionTimeout = ProxyUtils.extractInt(props, - "idle_connection_timeout"); - this.connectTimeout = ProxyUtils.extractInt(props, - "connect_timeout", 0); - this.maxInitialLineLength = ProxyUtils.extractInt(props, - "max_initial_line_length", MAX_INITIAL_LINE_LENGTH_DEFAULT); - this.maxHeaderSize = ProxyUtils.extractInt(props, - "max_header_size", MAX_HEADER_SIZE_DEFAULT); - this.maxChunkSize = ProxyUtils.extractInt(props, - "max_chunk_size", MAX_CHUNK_SIZE_DEFAULT); - } - - @Override - public HttpProxyServerBootstrap withName(String name) { - this.name = name; - return this; - } - - @Override - public HttpProxyServerBootstrap withTransportProtocol( - TransportProtocol transportProtocol) { - this.transportProtocol = transportProtocol; - return this; - } - - @Override - public HttpProxyServerBootstrap withAddress(InetSocketAddress address) { - this.requestedAddress = address; - return this; - } - - @Override - public HttpProxyServerBootstrap withPort(int port) { - this.requestedAddress = null; - this.port = port; - return this; - } - - @Override - public HttpProxyServerBootstrap withNetworkInterface(InetSocketAddress inetSocketAddress) { - this.localAddress = inetSocketAddress; - return this; - } - - @Override - public HttpProxyServerBootstrap withProxyAlias(String alias) { - this.proxyAlias = alias; - return this; - } - - @Override - public HttpProxyServerBootstrap withAllowLocalOnly( - boolean allowLocalOnly) { - this.allowLocalOnly = allowLocalOnly; - return this; - } - - @Override - @Deprecated - public HttpProxyServerBootstrap withListenOnAllAddresses(boolean listenOnAllAddresses) { - LOG.warn("withListenOnAllAddresses() is deprecated and will be removed in a future release. Use withNetworkInterface()."); - return this; - } - - @Override - public HttpProxyServerBootstrap withSslEngineSource( - SslEngineSource sslEngineSource) { - this.sslEngineSource = sslEngineSource; - if (this.mitmManager != null) { - LOG.warn("Enabled encrypted inbound connections with man in the middle. " - + "These are mutually exclusive - man in the middle will be disabled."); - this.mitmManager = null; - } - return this; - } - - @Override - public HttpProxyServerBootstrap withAuthenticateSslClients( - boolean authenticateSslClients) { - this.authenticateSslClients = authenticateSslClients; - return this; - } - - @Override - public HttpProxyServerBootstrap withProxyAuthenticator( - ProxyAuthenticator proxyAuthenticator) { - this.proxyAuthenticator = proxyAuthenticator; - return this; - } - - @Override - public HttpProxyServerBootstrap withChainProxyManager( - ChainedProxyManager chainProxyManager) { - this.chainProxyManager = chainProxyManager; - return this; - } - - @Override - public HttpProxyServerBootstrap withManInTheMiddle( - MitmManager mitmManager) { - this.mitmManager = mitmManager; - if (this.sslEngineSource != null) { - LOG.warn("Enabled man in the middle with encrypted inbound connections. " - + "These are mutually exclusive - encrypted inbound connections will be disabled."); - this.sslEngineSource = null; - } - return this; - } - - @Override - public HttpProxyServerBootstrap withFiltersSource( - HttpFiltersSource filtersSource) { - this.filtersSource = filtersSource; - return this; - } - - @Override - public HttpProxyServerBootstrap withUseDnsSec(boolean useDnsSec) { - if (useDnsSec) { - throw new UnsupportedOperationException(); - } else { - this.serverResolver = new DefaultHostResolver(); - } - return this; - } - - @Override - public HttpProxyServerBootstrap withTransparent( - boolean transparent) { - this.transparent = transparent; - return this; - } - - @Override - public HttpProxyServerBootstrap withIdleConnectionTimeout( - int idleConnectionTimeout) { - this.idleConnectionTimeout = idleConnectionTimeout; - return this; - } - - @Override - public HttpProxyServerBootstrap withConnectTimeout( - int connectTimeout) { - this.connectTimeout = connectTimeout; - return this; - } - - @Override - public HttpProxyServerBootstrap withServerResolver( - HostResolver serverResolver) { - this.serverResolver = serverResolver; - return this; - } - - @Override - public HttpProxyServerBootstrap plusActivityTracker( - ActivityTracker activityTracker) { - activityTrackers.add(activityTracker); - return this; - } - - @Override - public HttpProxyServerBootstrap withThrottling(long readThrottleBytesPerSecond, long writeThrottleBytesPerSecond) { - this.readThrottleBytesPerSecond = readThrottleBytesPerSecond; - this.writeThrottleBytesPerSecond = writeThrottleBytesPerSecond; - return this; - } - - @Override - public HttpProxyServerBootstrap withMaxInitialLineLength(int maxInitialLineLength){ - this.maxInitialLineLength = maxInitialLineLength; - return this; - } - - @Override - public HttpProxyServerBootstrap withMaxHeaderSize(int maxHeaderSize){ - this.maxHeaderSize = maxHeaderSize; - return this; - } - - @Override - public HttpProxyServerBootstrap withMaxChunkSize(int maxChunkSize){ - this.maxChunkSize = maxChunkSize; - return this; - } - - @Override - public HttpProxyServerBootstrap withAllowRequestToOriginServer(boolean allowRequestToOriginServer) { - this.allowRequestToOriginServer = allowRequestToOriginServer; - return this; - } - - @Override - public HttpProxyServer start() { - return build().start(); - } - - @Override - public HttpProxyServerBootstrap withThreadPoolConfiguration(ThreadPoolConfiguration configuration) { - this.clientToProxyAcceptorThreads = configuration.getAcceptorThreads(); - this.clientToProxyWorkerThreads = configuration.getClientToProxyWorkerThreads(); - this.proxyToServerWorkerThreads = configuration.getProxyToServerWorkerThreads(); - return this; - } - - private DefaultHttpProxyServer build() { - final ServerGroup serverGroup; - - if (this.serverGroup != null) { - serverGroup = this.serverGroup; - } - else { - serverGroup = new ServerGroup(name, clientToProxyAcceptorThreads, clientToProxyWorkerThreads, proxyToServerWorkerThreads); - } - - return new DefaultHttpProxyServer(serverGroup, - transportProtocol, determineListenAddress(), - sslEngineSource, authenticateSslClients, - proxyAuthenticator, chainProxyManager, mitmManager, - filtersSource, transparent, - idleConnectionTimeout, activityTrackers, connectTimeout, - serverResolver, readThrottleBytesPerSecond, writeThrottleBytesPerSecond, - localAddress, proxyAlias, maxInitialLineLength, maxHeaderSize, maxChunkSize, - allowRequestToOriginServer); - } - - private InetSocketAddress determineListenAddress() { - if (requestedAddress != null) { - return requestedAddress; - } else { - // Binding only to localhost can significantly improve the - // security of the proxy. - if (allowLocalOnly) { - return new InetSocketAddress("127.0.0.1", port); - } else { - return new InetSocketAddress(port); - } - } - } - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/NetworkUtils.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/NetworkUtils.java deleted file mode 100644 index 8ab51b9f28..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/NetworkUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import java.net.*; -import java.util.Enumeration; - -/** - * @deprecated This class is no longer used by LittleProxy and may be removed in a future release. - */ -@Deprecated -public class NetworkUtils { - /** - * @deprecated This method is no longer used by LittleProxy and may be removed in a future release. - */ - @Deprecated - public static InetAddress getLocalHost() throws UnknownHostException { - return InetAddress.getLocalHost(); - } - - /** - * @deprecated This method is no longer used by LittleProxy and may be removed in a future release. - */ - @Deprecated - public static InetAddress firstLocalNonLoopbackIpv4Address() { - try { - Enumeration networkInterfaces = NetworkInterface - .getNetworkInterfaces(); - while (networkInterfaces.hasMoreElements()) { - NetworkInterface networkInterface = networkInterfaces - .nextElement(); - if (networkInterface.isUp()) { - for (InterfaceAddress ifAddress : networkInterface - .getInterfaceAddresses()) { - if (ifAddress.getNetworkPrefixLength() > 0 - && ifAddress.getNetworkPrefixLength() <= 32 - && !ifAddress.getAddress().isLoopbackAddress()) { - return ifAddress.getAddress(); - } - } - } - } - return null; - } catch (SocketException se) { - return null; - } - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyConnection.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyConnection.java deleted file mode 100644 index 5c4370cbb3..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyConnection.java +++ /dev/null @@ -1,834 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.*; -import io.netty.handler.codec.http.*; -import io.netty.handler.ssl.SslHandler; -import io.netty.handler.timeout.IdleStateEvent; -import io.netty.util.ReferenceCounted; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; -import io.netty.util.concurrent.Promise; -import lombok.extern.slf4j.Slf4j; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpFilters; - -import javax.net.ssl.SSLEngine; - -import static tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ConnectionState.*; - -/** - *

- * Base class for objects that represent a connection to/from our proxy. - *

- *

- * A ProxyConnection models a bidirectional message flow on top of a Netty - * {@link Channel}. - *

- *

- * The {@link #read(Object)} method is called whenever a new message arrives on - * the underlying socket. - *

- *

- * The {@link #write(Object)} method can be called by anyone wanting to write - * data out of the connection. - *

- *

- * ProxyConnection has a lifecycle and its current state within that lifecycle - * is recorded as a {@link ConnectionState}. The allowed states and transitions - * vary a little depending on the concrete implementation of ProxyConnection. - * However, all ProxyConnections share the following lifecycle events: - *

- * - *
    - *
  • {@link #connected()} - Once the underlying channel is active, the - * ProxyConnection is considered connected and moves into - * {@link ConnectionState#AWAITING_INITIAL}. The Channel is recorded at this - * time for later referencing.
  • - *
  • {@link #disconnected()} - When the underlying channel goes inactive, the - * ProxyConnection moves into {@link ConnectionState#DISCONNECTED}
  • - *
  • {@link #becameWritable()} - When the underlying channel becomes - * writeable, this callback is invoked.
  • - *
- * - *

- * By default, incoming data on the underlying channel is automatically read and - * passed to the {@link #read(Object)} method. Reading can be stopped and - * resumed using {@link #stopReading()} and {@link #resumeReading()}. - *

- * - * @param - * the type of "initial" message. This will be either - * {@link HttpResponse} or {@link HttpRequest}. - */ -@Slf4j -abstract class ProxyConnection extends - SimpleChannelInboundHandler { - - protected final DefaultHttpProxyServer proxyServer; - protected final boolean runsAsSslClient; - - protected volatile ChannelHandlerContext ctx; - protected volatile Channel channel; - - private volatile ConnectionState currentState; - private volatile boolean tunneling = false; - protected volatile long lastReadTime = 0; - - /** - * If using encryption, this holds our {@link SSLEngine}. - */ - protected volatile SSLEngine sslEngine; - - /** - * Construct a new ProxyConnection. - * - * @param initialState - * the state in which this connection starts out - * @param proxyServer - * the {@link DefaultHttpProxyServer} in which we're running - * @param runsAsSslClient - * determines whether this connection acts as an SSL client or - * server (determines who does the handshake) - */ - protected ProxyConnection(ConnectionState initialState, - DefaultHttpProxyServer proxyServer, - boolean runsAsSslClient) { - become(initialState); - this.proxyServer = proxyServer; - this.runsAsSslClient = runsAsSslClient; - } - - /*************************************************************************** - * Reading - **************************************************************************/ - - /** - * Read is invoked automatically by Netty as messages arrive on the socket. - * - * @param msg - */ - protected void read(Object msg) { - log.trace("Reading: {}", msg); - - lastReadTime = System.currentTimeMillis(); - - if (tunneling) { - // In tunneling mode, this connection is simply shoveling bytes - readRaw((ByteBuf) msg); - } else { - // If not tunneling, then we are always dealing with HttpObjects. - readHTTP((HttpObject) msg); - } - } - - /** - * Handles reading {@link HttpObject}s. - * - * @param httpObject - */ - @SuppressWarnings("unchecked") - private void readHTTP(HttpObject httpObject) { - ConnectionState nextState = getCurrentState(); - switch (getCurrentState()) { - case AWAITING_INITIAL: - if (httpObject instanceof HttpMessage) { - nextState = readHTTPInitial((I) httpObject); - } else { - // Similar to the AWAITING_PROXY_AUTHENTICATION case below, we may enter an AWAITING_INITIAL - // state if the proxy responded to an earlier request with a 502 or 504 response, or a short-circuit - // response from a filter. The client may have sent some chunked HttpContent associated with the request - // after the short-circuit response was sent. We can safely drop them. - log.warn("Dropping message because HTTP object was not an HttpMessage. HTTP object may be orphaned content from a short-circuited response. Message: {}", httpObject); - } - break; - case AWAITING_CHUNK: - HttpContent chunk = (HttpContent) httpObject; - readHTTPChunk(chunk); - nextState = ProxyUtils.isLastChunk(chunk) ? AWAITING_INITIAL - : AWAITING_CHUNK; - break; - case AWAITING_PROXY_AUTHENTICATION: - if (httpObject instanceof HttpRequest) { - // Once we get an HttpRequest, try to process it as usual - nextState = readHTTPInitial((I) httpObject); - } else { - // Anything that's not an HttpRequest that came in while - // we're pending authentication gets dropped on the floor. This - // can happen if the connected host already sent us some chunks - // (e.g. from a POST) after an initial request that turned out - // to require authentication. - } - break; - case CONNECTING: - log.warn("Attempted to read from connection that's in the process of connecting. This shouldn't happen."); - break; - case NEGOTIATING_CONNECT: - log.trace("Attempted to read from connection that's in the process of negotiating an HTTP CONNECT. This is probably the LastHttpContent of a chunked CONNECT."); - break; - case AWAITING_CONNECT_OK: - log.warn("AWAITING_CONNECT_OK should have been handled by ProxyToServerConnection.read()"); - break; - case HANDSHAKING: - log.warn("Attempted to read from connection that's in the process of handshaking. This shouldn't happen."); - break; - case DISCONNECT_REQUESTED: - case DISCONNECTED: - log.info("Ignoring message since the connection is closed or about to close"); - break; - } - become(nextState); - } - - /** - * Implement this to handle reading the initial object (e.g. - * {@link HttpRequest} or {@link HttpResponse}). - * - * @param httpObject - * @return - */ - protected abstract ConnectionState readHTTPInitial(I httpObject); - - /** - * Implement this to handle reading a chunk in a chunked transfer. - * - * @param chunk - */ - protected abstract void readHTTPChunk(HttpContent chunk); - - /** - * Implement this to handle reading a raw buffer as they are used in HTTP - * tunneling. - * - * @param buf - */ - protected abstract void readRaw(ByteBuf buf); - - /*************************************************************************** - * Writing - **************************************************************************/ - - /** - * This method is called by users of the ProxyConnection to send stuff out - * over the socket. - * - * @param msg - */ - void write(Object msg) { - if (msg instanceof ReferenceCounted) { - log.trace("Retaining reference counted message"); - ((ReferenceCounted) msg).retain(); - } - - doWrite(msg); - } - - void doWrite(Object msg) { - log.debug("Writing: {}", msg); - - try { - if (msg instanceof HttpObject) { - writeHttp((HttpObject) msg); - } else { - writeRaw((ByteBuf) msg); - } - } finally { - log.trace("Wrote: {}", msg); - } - } - - /** - * Writes HttpObjects to the connection asynchronously. - * - * @param httpObject - */ - protected void writeHttp(HttpObject httpObject) { - if (ProxyUtils.isLastChunk(httpObject)) { - channel.write(httpObject); - log.trace("Writing an empty buffer to signal the end of our chunked transfer"); - writeToChannel(Unpooled.EMPTY_BUFFER); - } else { - writeToChannel(httpObject); - } - } - - /** - * Writes raw buffers to the connection. - * - * @param buf - */ - protected void writeRaw(ByteBuf buf) { - writeToChannel(buf); - } - - protected ChannelFuture writeToChannel(final Object msg) { - return channel.writeAndFlush(msg); - } - - /*************************************************************************** - * Lifecycle - **************************************************************************/ - - /** - * This method is called as soon as the underlying {@link Channel} is - * connected. Note that for proxies with complex {@link ConnectionFlow}s - * that include SSL handshaking and other such things, just because the - * {@link Channel} is connected doesn't mean that our connection is fully - * established. - */ - protected void connected() { - log.trace("Connected"); - } - - /** - * This method is called as soon as the underlying {@link Channel} becomes - * disconnected. - */ - protected void disconnected() { - become(DISCONNECTED); - log.trace("Disconnected"); - } - - /** - * This method is called when the underlying {@link Channel} times out due - * to an idle timeout. - */ - protected void timedOut() { - disconnect(); - } - - /** - *

- * Enables tunneling on this connection by dropping the HTTP related - * encoders and decoders, as well as idle timers. - *

- * - *

- * Note - the work is done on the {@link ChannelHandlerContext}'s executor - * because {@link ChannelPipeline#remove(String)} can deadlock if called - * directly. - *

- */ - protected ConnectionFlowStep StartTunneling = new ConnectionFlowStep( - this, NEGOTIATING_CONNECT) { - @Override - boolean shouldSuppressInitialRequest() { - return true; - } - - protected Future execute() { - try { - ChannelPipeline pipeline = ctx.pipeline(); - if (pipeline.get("encoder") != null) { - pipeline.remove("encoder"); - } - if (pipeline.get("responseWrittenMonitor") != null) { - pipeline.remove("responseWrittenMonitor"); - } - if (pipeline.get("decoder") != null) { - pipeline.remove("decoder"); - } - if (pipeline.get("requestReadMonitor") != null) { - pipeline.remove("requestReadMonitor"); - } - tunneling = true; - return channel.newSucceededFuture(); - } catch (Throwable t) { - return channel.newFailedFuture(t); - } - } - }; - - /** - * Encrypts traffic on this connection with SSL/TLS. - * - * @param sslEngine - * the {@link SSLEngine} for doing the encryption - * @param authenticateClients - * determines whether to authenticate clients or not - * @return a Future for when the SSL handshake has completed - */ - protected Future encrypt(SSLEngine sslEngine, - boolean authenticateClients) { - return encrypt(ctx.pipeline(), sslEngine, authenticateClients); - } - - /** - * Encrypts traffic on this connection with SSL/TLS. - * - * @param pipeline - * the ChannelPipeline on which to enable encryption - * @param sslEngine - * the {@link SSLEngine} for doing the encryption - * @param authenticateClients - * determines whether to authenticate clients or not - * @return a Future for when the SSL handshake has completed - */ - protected Future encrypt(ChannelPipeline pipeline, - SSLEngine sslEngine, - boolean authenticateClients) { - log.trace("Enabling encryption with SSLEngine: {}", - sslEngine); - this.sslEngine = sslEngine; - sslEngine.setUseClientMode(runsAsSslClient); - sslEngine.setNeedClientAuth(authenticateClients); - if (null != channel) { - channel.config().setAutoRead(true); - } - SslHandler handler = new SslHandler(sslEngine); - if(pipeline.get("ssl") == null) { - pipeline.addFirst("ssl", handler); - } else { - // The second SSL handler is added to handle the case - // where the proxy (running as MITM) has to chain with - // another SSL enabled proxy. The second SSL handler - // is to perform SSL with the server. - pipeline.addAfter("ssl", "sslWithServer", handler); - } - return handler.handshakeFuture(); - } - - /** - * Encrypts the channel using the provided {@link SSLEngine}. - * - * @param sslEngine - * the {@link SSLEngine} for doing the encryption - */ - protected ConnectionFlowStep EncryptChannel( - final SSLEngine sslEngine) { - - return new ConnectionFlowStep(this, HANDSHAKING) { - @Override - boolean shouldExecuteOnEventLoop() { - return false; - } - - @Override - protected Future execute() { - return encrypt(sslEngine, !runsAsSslClient); - } - }; - }; - - /** - * Enables decompression and aggregation of content, which is useful for - * certain types of filtering activity. - * - * @param pipeline - * @param numberOfBytesToBuffer - */ - protected void aggregateContentForFiltering(ChannelPipeline pipeline, - int numberOfBytesToBuffer) { - pipeline.addLast("inflater", new HttpContentDecompressor()); - pipeline.addLast("aggregator", new HttpObjectAggregator( - numberOfBytesToBuffer)); - } - - /** - * Callback that's invoked if this connection becomes saturated. - */ - protected void becameSaturated() { - log.trace("Became saturated"); - } - - /** - * Callback that's invoked when this connection becomes writeable again. - */ - protected void becameWritable() { - log.trace("Became writeable"); - } - - /** - * Override this to handle exceptions that occurred during asynchronous - * processing on the {@link Channel}. - * - * @param cause - */ - protected void exceptionCaught(Throwable cause) { - } - - /*************************************************************************** - * State/Management - **************************************************************************/ - /** - * Disconnects. This will wait for pending writes to be flushed before - * disconnecting. - * - * @return Future for when we're done disconnecting. If we weren't - * connected, this returns null. - */ - Future disconnect() { - if (channel == null) { - return null; - } else { - final Promise promise = channel.newPromise(); - writeToChannel(Unpooled.EMPTY_BUFFER).addListener( - new GenericFutureListener>() { - @Override - public void operationComplete( - Future future) - throws Exception { - closeChannel(promise); - } - }); - return promise; - } - } - - private void closeChannel(final Promise promise) { - channel.close().addListener( - new GenericFutureListener>() { - public void operationComplete( - Future future) - throws Exception { - if (future - .isSuccess()) { - promise.setSuccess(null); - } else { - promise.setFailure(future - .cause()); - } - }; - }); - } - - /** - * Indicates whether or not this connection is saturated (i.e. not - * writeable). - * - * @return - */ - protected boolean isSaturated() { - return !this.channel.isWritable(); - } - - /** - * Utility for checking current state. - * - * @param state - * @return - */ - protected boolean is(ConnectionState state) { - return currentState == state; - } - - /** - * If this connection is currently in the process of going through a - * {@link ConnectionFlow}, this will return true. - * - * @return - */ - protected boolean isConnecting() { - return currentState.isPartOfConnectionFlow(); - } - - /** - * Udpates the current state to the given value. - * - * @param state - */ - protected void become(ConnectionState state) { - this.currentState = state; - } - - protected ConnectionState getCurrentState() { - return currentState; - } - - public boolean isTunneling() { - return tunneling; - } - - public SSLEngine getSslEngine() { - return sslEngine; - } - - /** - * Call this to stop reading. - */ - protected void stopReading() { - log.trace("Stopped reading"); - this.channel.config().setAutoRead(false); - } - - /** - * Call this to resume reading. - */ - protected void resumeReading() { - log.trace("Resumed reading"); - this.channel.config().setAutoRead(true); - } - - /** - * Request the ProxyServer for Filters. - * - * By default, no-op filters are returned by DefaultHttpProxyServer. - * Subclasses of ProxyConnection can change this behaviour. - * - * @param httpRequest - * Filter attached to the give HttpRequest (if any) - * @return - */ - protected HttpFilters getHttpFiltersFromProxyServer(HttpRequest httpRequest) { - return proxyServer.getFiltersSource().filterRequest(httpRequest, ctx); - } - - /*************************************************************************** - * Adapting the Netty API - **************************************************************************/ - @Override - protected final void channelRead0(ChannelHandlerContext ctx, Object msg) - throws Exception { - read(msg); - } - - @Override - public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - try { - this.ctx = ctx; - this.channel = ctx.channel(); - this.proxyServer.registerChannel(ctx.channel()); - } finally { - super.channelRegistered(ctx); - } - } - - /** - * Only once the Netty Channel is active to we recognize the ProxyConnection - * as connected. - */ - @Override - public final void channelActive(ChannelHandlerContext ctx) throws Exception { - try { - connected(); - } finally { - super.channelActive(ctx); - } - } - - /** - * As soon as the Netty Channel is inactive, we recognize the - * ProxyConnection as disconnected. - */ - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - try { - disconnected(); - } finally { - super.channelInactive(ctx); - } - } - - @Override - public final void channelWritabilityChanged(ChannelHandlerContext ctx) - throws Exception { - log.trace("Writability changed. Is writable: {}", channel.isWritable()); - try { - if (this.channel.isWritable()) { - becameWritable(); - } else { - becameSaturated(); - } - } finally { - super.channelWritabilityChanged(ctx); - } - } - - @Override - public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) - throws Exception { - exceptionCaught(cause); - } - - /** - *

- * We're looking for {@link IdleStateEvent}s to see if we need to - * disconnect. - *

- * - *

- * Note - we don't care what kind of IdleState we got. Thanks to qbast for pointing this out. - *

- */ - @Override - public final void userEventTriggered(ChannelHandlerContext ctx, Object evt) - throws Exception { - try { - if (evt instanceof IdleStateEvent) { - log.trace("Got idle"); - timedOut(); - } - } finally { - super.userEventTriggered(ctx, evt); - } - } - - /*************************************************************************** - * Activity Tracking/Statistics - **************************************************************************/ - - /** - * Utility handler for monitoring bytes read on this connection. - */ - @Sharable - protected abstract static class BytesReadMonitor extends - ChannelInboundHandlerAdapter { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) - throws Exception { - try { - if (msg instanceof ByteBuf) { - bytesRead(((ByteBuf) msg).readableBytes()); - } - } catch (Throwable t) { - log.warn("Unable to record bytesRead", t); - } finally { - super.channelRead(ctx, msg); - } - } - - protected abstract void bytesRead(int numberOfBytes); - } - - /** - * Utility handler for monitoring requests read on this connection. - */ - @Sharable - protected abstract static class RequestReadMonitor extends - ChannelInboundHandlerAdapter { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) - throws Exception { - try { - if (msg instanceof HttpRequest) { - requestRead((HttpRequest) msg); - } - } catch (Throwable t) { - log.warn("Unable to record bytesRead", t); - } finally { - super.channelRead(ctx, msg); - } - } - - protected abstract void requestRead(HttpRequest httpRequest); - } - - /** - * Utility handler for monitoring responses read on this connection. - */ - @Sharable - protected abstract static class ResponseReadMonitor extends - ChannelInboundHandlerAdapter { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) - throws Exception { - try { - if (msg instanceof HttpResponse) { - responseRead((HttpResponse) msg); - } - } catch (Throwable t) { - log.warn("Unable to record bytesRead", t); - } finally { - super.channelRead(ctx, msg); - } - } - - protected abstract void responseRead(HttpResponse httpResponse); - } - - /** - * Utility handler for monitoring bytes written on this connection. - */ - @Sharable - protected abstract static class BytesWrittenMonitor extends - ChannelOutboundHandlerAdapter { - @Override - public void write(ChannelHandlerContext ctx, - Object msg, ChannelPromise promise) - throws Exception { - try { - if (msg instanceof ByteBuf) { - bytesWritten(((ByteBuf) msg).readableBytes()); - } - } catch (Throwable t) { - log.warn("Unable to record bytesRead", t); - } finally { - super.write(ctx, msg, promise); - } - } - - protected abstract void bytesWritten(int numberOfBytes); - } - - /** - * Utility handler for monitoring requests written on this connection. - */ - @Sharable - protected abstract static class RequestWrittenMonitor extends - ChannelOutboundHandlerAdapter { - @Override - public void write(ChannelHandlerContext ctx, - Object msg, ChannelPromise promise) - throws Exception { - HttpRequest originalRequest = null; - if (msg instanceof HttpRequest) { - originalRequest = (HttpRequest) msg; - } - - if (null != originalRequest) { - requestWriting(originalRequest); - } - - super.write(ctx, msg, promise); - - if (null != originalRequest) { - requestWritten(originalRequest); - } - - if (msg instanceof HttpContent) { - contentWritten((HttpContent) msg); - } - } - - /** - * Invoked immediately before an HttpRequest is written. - */ - protected abstract void requestWriting(HttpRequest httpRequest); - - /** - * Invoked immediately after an HttpRequest has been sent. - */ - protected abstract void requestWritten(HttpRequest httpRequest); - - /** - * Invoked immediately after an HttpContent has been sent. - */ - protected abstract void contentWritten(HttpContent httpContent); - } - - /** - * Utility handler for monitoring responses written on this connection. - */ - @Sharable - protected abstract static class ResponseWrittenMonitor extends - ChannelOutboundHandlerAdapter { - @Override - public void write(ChannelHandlerContext ctx, - Object msg, ChannelPromise promise) - throws Exception { - try { - if (msg instanceof HttpResponse) { - responseWritten(((HttpResponse) msg)); - } - } catch (Throwable t) { - log.warn("Error while invoking responseWritten callback", t); - } finally { - super.write(ctx, msg, promise); - } - } - - protected abstract void responseWritten(HttpResponse httpResponse); - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyThreadPools.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyThreadPools.java deleted file mode 100644 index 7a39ebc47e..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyThreadPools.java +++ /dev/null @@ -1,64 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import com.google.common.collect.ImmutableList; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; - -import java.nio.channels.spi.SelectorProvider; -import java.util.List; - -/** - * Encapsulates the thread pools used by the proxy. Contains the acceptor thread pool as well as the client-to-proxy and - * proxy-to-server thread pools. - */ -public class ProxyThreadPools { - /** - * These {@link EventLoopGroup}s accept incoming connections to the - * proxies. A different EventLoopGroup is used for each - * TransportProtocol, since these have to be configured differently. - */ - private final NioEventLoopGroup clientToProxyAcceptorPool; - - /** - * These {@link EventLoopGroup}s process incoming requests to the - * proxies. A different EventLoopGroup is used for each - * TransportProtocol, since these have to be configured differently. - */ - private final NioEventLoopGroup clientToProxyWorkerPool; - - /** - * These {@link EventLoopGroup}s are used for making outgoing - * connections to servers. A different EventLoopGroup is used for each - * TransportProtocol, since these have to be configured differently. - */ - private final NioEventLoopGroup proxyToServerWorkerPool; - - public ProxyThreadPools(SelectorProvider selectorProvider, int incomingAcceptorThreads, int incomingWorkerThreads, int outgoingWorkerThreads, String serverGroupName, int serverGroupId) { - clientToProxyAcceptorPool = new NioEventLoopGroup(incomingAcceptorThreads, new CategorizedThreadFactory(serverGroupName, "ClientToProxyAcceptor", serverGroupId), selectorProvider); - - clientToProxyWorkerPool = new NioEventLoopGroup(incomingWorkerThreads, new CategorizedThreadFactory(serverGroupName, "ClientToProxyWorker", serverGroupId), selectorProvider); - clientToProxyWorkerPool.setIoRatio(90); - - proxyToServerWorkerPool = new NioEventLoopGroup(outgoingWorkerThreads, new CategorizedThreadFactory(serverGroupName, "ProxyToServerWorker", serverGroupId), selectorProvider); - proxyToServerWorkerPool.setIoRatio(90); - } - - /** - * Returns all event loops (acceptor and worker thread pools) in this pool. - */ - public List getAllEventLoops() { - return ImmutableList.of(clientToProxyAcceptorPool, clientToProxyWorkerPool, proxyToServerWorkerPool); - } - - public NioEventLoopGroup getClientToProxyAcceptorPool() { - return clientToProxyAcceptorPool; - } - - public NioEventLoopGroup getClientToProxyWorkerPool() { - return clientToProxyWorkerPool; - } - - public NioEventLoopGroup getProxyToServerWorkerPool() { - return proxyToServerWorkerPool; - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyToServerConnection.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyToServerConnection.java deleted file mode 100644 index 8ab55f41c3..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyToServerConnection.java +++ /dev/null @@ -1,1009 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import com.google.common.net.HostAndPort; -import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ChannelFactory; -import io.netty.buffer.ByteBuf; -import io.netty.channel.*; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.channel.udt.nio.NioUdtProvider; -import io.netty.handler.codec.http.*; -import io.netty.handler.timeout.IdleStateHandler; -import io.netty.handler.traffic.GlobalTrafficShapingHandler; -import io.netty.util.ReferenceCounted; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; -import lombok.extern.slf4j.Slf4j; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.*; - -import javax.net.ssl.SSLProtocolException; -import javax.net.ssl.SSLSession; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.RejectedExecutionException; - -import static tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.ConnectionState.*; - -/** - *

- * Represents a connection from our proxy to a server on the web. - * ProxyConnections are reused fairly liberally, and can go from disconnected to - * connected, back to disconnected and so on. - *

- * - *

- * Connecting a {@link ProxyToServerConnection} can involve more than just - * connecting the underlying {@link Channel}. In particular, the connection may - * use encryption (i.e. TLS) and it may also establish an HTTP CONNECT tunnel. - * The various steps involved in fully establishing a connection are - * encapsulated in the property {@link #connectionFlow}, which is initialized in - * {@link #initializeConnectionFlow()}. - *

- */ -@Sharable -@Slf4j -public class ProxyToServerConnection extends ProxyConnection -{ - private final ClientToProxyConnection clientConnection; - private final ProxyToServerConnection serverConnection = this; - private volatile TransportProtocol transportProtocol; - private volatile InetSocketAddress remoteAddress; - private volatile InetSocketAddress localAddress; - private final String serverHostAndPort; - private volatile ChainedProxy chainedProxy; - private final Queue availableChainedProxies; - - /** - * The filters to apply to response/chunks received from server. - */ - private volatile HttpFilters currentFilters; - - /** - * Encapsulates the flow for establishing a connection, which can vary - * depending on how things are configured. - */ - private volatile ConnectionFlow connectionFlow; - - /** - * Disables SNI when initializing connection flow in {@link #initializeConnectionFlow()}. This value is set to true - * when retrying a connection without SNI to work around Java's SNI handling issue (see - * {@link #connectionFailed(Throwable)}). - */ - private volatile boolean disableSni = false; - - /** - * While we're in the process of connecting, it's possible that we'll - * receive a new message to write. This lock helps us synchronize and wait - * for the connection to be established before writing the next message. - */ - private final Object connectLock = new Object(); - - /** - * This is the initial request received prior to connecting. We keep track - * of it so that we can process it after connection finishes. - */ - private volatile HttpRequest initialRequest; - - /** - * Keeps track of HttpRequests that have been issued so that we can - * associate them with responses that we get back - */ - private volatile HttpRequest currentHttpRequest; - - /** - * While we're doing a chunked transfer, this keeps track of the initial - * HttpResponse object for our transfer (which is useful for its headers). - */ - private volatile HttpResponse currentHttpResponse; - - /** - * Limits bandwidth when throttling is enabled. - */ - private volatile GlobalTrafficShapingHandler trafficHandler; - - /** - * Minimum size of the adaptive recv buffer when throttling is enabled. - */ - private static final int MINIMUM_RECV_BUFFER_SIZE_BYTES = 64; - - /** - * Create a new ProxyToServerConnection. - * - * @param proxyServer - * @param clientConnection - * @param serverHostAndPort - * @param initialFilters - * @param initialHttpRequest - * @return - * @throws UnknownHostException - */ - static ProxyToServerConnection create(DefaultHttpProxyServer proxyServer, - ClientToProxyConnection clientConnection, - String serverHostAndPort, - HttpFilters initialFilters, - HttpRequest initialHttpRequest, - GlobalTrafficShapingHandler globalTrafficShapingHandler) - throws UnknownHostException { - Queue chainedProxies = new ConcurrentLinkedQueue(); - ChainedProxyManager chainedProxyManager = proxyServer - .getChainProxyManager(); - if (chainedProxyManager != null) { - chainedProxyManager.lookupChainedProxies(initialHttpRequest, - chainedProxies); - if (chainedProxies.size() == 0) { - // ChainedProxyManager returned no proxies, can't connect - return null; - } - } - return new ProxyToServerConnection(proxyServer, - clientConnection, - serverHostAndPort, - chainedProxies.poll(), - chainedProxies, - initialFilters, - globalTrafficShapingHandler); - } - - private ProxyToServerConnection( - DefaultHttpProxyServer proxyServer, - ClientToProxyConnection clientConnection, - String serverHostAndPort, - ChainedProxy chainedProxy, - Queue availableChainedProxies, - HttpFilters initialFilters, - GlobalTrafficShapingHandler globalTrafficShapingHandler) - throws UnknownHostException { - super(DISCONNECTED, proxyServer, true); - this.clientConnection = clientConnection; - this.serverHostAndPort = serverHostAndPort; - this.chainedProxy = chainedProxy; - this.availableChainedProxies = availableChainedProxies; - this.trafficHandler = globalTrafficShapingHandler; - this.currentFilters = initialFilters; - - // Report connection status to HttpFilters - currentFilters.proxyToServerConnectionQueued(); - - setupConnectionParameters(); - } - - /*************************************************************************** - * Reading - **************************************************************************/ - - @Override - protected void read(Object msg) { - if (isConnecting()) { - log.trace( - "In the middle of connecting, forwarding message to connection flow: {}", - msg); - this.connectionFlow.read(msg); - } else { - super.read(msg); - } - } - - @Override - protected ConnectionState readHTTPInitial(HttpResponse httpResponse) { - log.trace("Received raw response: {}", httpResponse); - - if (httpResponse.getDecoderResult().isFailure()) { - log.warn("Could not parse response from server. Decoder result: {}", httpResponse.getDecoderResult().toString()); - - // create a "substitute" Bad Gateway response from the server, since we couldn't understand what the actual - // response from the server was. set the keep-alive on the substitute response to false so the proxy closes - // the connection to the server, since we don't know what state the server thinks the connection is in. - FullHttpResponse substituteResponse = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, - HttpResponseStatus.BAD_GATEWAY, - "Unable to parse response from server"); - HttpHeaders.setKeepAlive(substituteResponse, false); - httpResponse = substituteResponse; - } - - currentFilters.serverToProxyResponseReceiving(); - - rememberCurrentResponse(httpResponse); - respondWith(httpResponse); - - if (ProxyUtils.isChunked(httpResponse)) { - return AWAITING_CHUNK; - } else { - currentFilters.serverToProxyResponseReceived(); - - return AWAITING_INITIAL; - } - } - - @Override - protected void readHTTPChunk(HttpContent chunk) { - respondWith(chunk); - } - - @Override - protected void readRaw(ByteBuf buf) { - clientConnection.write(buf); - } - - /** - *

- * Responses to HEAD requests aren't supposed to have content, but Netty - * doesn't know that any given response is to a HEAD request, so it needs to - * be told that there's no content so that it doesn't hang waiting for it. - *

- * - *

- * See the documentation for {@link HttpResponseDecoder} for information - * about why HEAD requests need special handling. - *

- * - *

- * Thanks to nataliakoval for - * pointing out that with connections being reused as they are, this needs - * to be sensitive to the current request. - *

- */ - private class HeadAwareHttpResponseDecoder extends HttpResponseDecoder { - - public HeadAwareHttpResponseDecoder(int maxInitialLineLength, - int maxHeaderSize, int maxChunkSize) { - super(maxInitialLineLength, maxHeaderSize, maxChunkSize); - } - - @Override - protected boolean isContentAlwaysEmpty(HttpMessage httpMessage) { - // The current HTTP Request can be null when this proxy is - // negotiating a CONNECT request with a chained proxy - // while it is running as a MITM. Since the response to a - // CONNECT request does not have any content, we return true. - if(currentHttpRequest == null) { - return true; - } else { - return ProxyUtils.isHEAD(currentHttpRequest) || super.isContentAlwaysEmpty(httpMessage); - } - } - }; - - /*************************************************************************** - * Writing - **************************************************************************/ - - /** - * Like {@link #write(Object)} and also sets the current filters to the - * given value. - * - * @param msg - * @param filters - */ - void write(Object msg, HttpFilters filters) { - this.currentFilters = filters; - write(msg); - } - - @Override - void write(Object msg) { - log.debug("Requested write of {}", msg); - - if (msg instanceof ReferenceCounted) { - log.trace("Retaining reference counted message"); - ((ReferenceCounted) msg).retain(); - } - - if (is(DISCONNECTED) && msg instanceof HttpRequest) { - log.trace("Currently disconnected, connect and then write the message"); - connectAndWrite((HttpRequest) msg); - } else { - if (isConnecting()) { - synchronized (connectLock) { - if (isConnecting()) { - log.trace("Attempted to write while still in the process of connecting, waiting for connection."); - clientConnection.stopReading(); - try { - connectLock.wait(30000); - } catch (InterruptedException ie) { - log.warn("Interrupted while waiting for connect monitor"); - } - } - } - } - - // only write this message if a connection was established and is not in the process of disconnecting or - // already disconnected - if (isConnecting() || getCurrentState().isDisconnectingOrDisconnected()) { - log.trace("Connection failed or timed out while waiting to write message to server. Message will be discarded: {}", msg); - return; - } - - log.trace("Using existing connection to: {}", remoteAddress); - doWrite(msg); - } - }; - - @Override - protected void writeHttp(HttpObject httpObject) { - if (chainedProxy != null) { - chainedProxy.filterRequest(httpObject); - } - if (httpObject instanceof HttpRequest) { - // Remember that we issued this HttpRequest for later - currentHttpRequest = (HttpRequest) httpObject; - } - super.writeHttp(httpObject); - } - - /*************************************************************************** - * Lifecycle - **************************************************************************/ - - @Override - protected void become(ConnectionState newState) { - // Report connection status to HttpFilters - if (getCurrentState() == DISCONNECTED && newState == CONNECTING) { - currentFilters.proxyToServerConnectionStarted(); - } else if (getCurrentState() == CONNECTING) { - if (newState == HANDSHAKING) { - currentFilters.proxyToServerConnectionSSLHandshakeStarted(); - } else if (newState == AWAITING_INITIAL) { - currentFilters.proxyToServerConnectionSucceeded(ctx); - } else if (newState == DISCONNECTED) { - currentFilters.proxyToServerConnectionFailed(); - } - } else if (getCurrentState() == HANDSHAKING) { - if (newState == AWAITING_INITIAL) { - currentFilters.proxyToServerConnectionSucceeded(ctx); - } else if (newState == DISCONNECTED) { - currentFilters.proxyToServerConnectionFailed(); - } - } else if (getCurrentState() == AWAITING_CHUNK - && newState != AWAITING_CHUNK) { - currentFilters.serverToProxyResponseReceived(); - } - - super.become(newState); - } - - @Override - protected void becameSaturated() { - super.becameSaturated(); - this.clientConnection.serverBecameSaturated(this); - } - - @Override - protected void becameWritable() { - super.becameWritable(); - this.clientConnection.serverBecameWriteable(this); - } - - @Override - protected void timedOut() { - super.timedOut(); - clientConnection.timedOut(this); - } - - @Override - protected void disconnected() { - super.disconnected(); - if (this.chainedProxy != null) { - // Let the ChainedProxy know that we disconnected - try { - this.chainedProxy.disconnected(); - } catch (Exception e) { - log.error("Unable to record connectionFailed", e); - } - } - clientConnection.serverDisconnected(this); - } - - @Override - protected void exceptionCaught(Throwable cause) { - try { - if (cause instanceof IOException) { - // IOExceptions are expected errors, for example when a server drops the connection. rather than flood - // the logs with stack traces for these expected exceptions, log the message at the INFO level and the - // stack trace at the DEBUG level. - log.debug("An IOException occurred on ProxyToServerConnection: " + cause.getMessage()); - log.error("An IOException occurred on ProxyToServerConnection", cause); - } else if (cause instanceof RejectedExecutionException) { - log.debug("An executor rejected a read or write operation on the ProxyToServerConnection (this is normal if the proxy is shutting down). Message: " + cause.getMessage()); - log.error("A RejectedExecutionException occurred on ProxyToServerConnection", cause); - } else { - log.error("Caught an exception on ProxyToServerConnection", cause); - } - } finally { - if (!is(DISCONNECTED)) { - log.info("Disconnecting open connection to server"); - disconnect(); - } - } - // This can happen if we couldn't make the initial connection due - // to something like an unresolved address, for example, or a timeout. - // There will not have been be any requests written on an unopened - // connection, so there should not be any further action to take here. - } - - /*************************************************************************** - * State Management - **************************************************************************/ - public TransportProtocol getTransportProtocol() { - return transportProtocol; - } - - public InetSocketAddress getRemoteAddress() { - return remoteAddress; - } - - public String getServerHostAndPort() { - return serverHostAndPort; - } - - public boolean hasUpstreamChainedProxy() { - return getChainedProxyAddress() != null; - } - - public InetSocketAddress getChainedProxyAddress() { - return chainedProxy == null ? null : chainedProxy - .getChainedProxyAddress(); - } - - public ChainedProxy getChainedProxy() { - return chainedProxy; - } - - public HttpRequest getInitialRequest() { - return initialRequest; - } - - @Override - protected HttpFilters getHttpFiltersFromProxyServer(HttpRequest httpRequest) { - return currentFilters; - } - - /*************************************************************************** - * Private Implementation - **************************************************************************/ - - /** - * Keeps track of the current HttpResponse so that we can associate its - * headers with future related chunks for this same transfer. - * - * @param response - */ - private void rememberCurrentResponse(HttpResponse response) { - log.trace("Remembering the current response."); - // We need to make a copy here because the response will be - // modified in various ways before we need to do things like - // analyze response headers for whether or not to close the - // connection (which may not happen for a while for large, chunked - // responses, for example). - currentHttpResponse = ProxyUtils.copyMutableResponseFields(response); - } - - /** - * Respond to the client with the given {@link HttpObject}. - * - * @param httpObject - */ - private void respondWith(HttpObject httpObject) { - clientConnection.respond(this, currentFilters, currentHttpRequest, - currentHttpResponse, httpObject); - } - - /** - * Configures the connection to the upstream server and begins the {@link ConnectionFlow}. - * - * @param initialRequest the current HTTP request being handled - */ - private void connectAndWrite(HttpRequest initialRequest) { - log.debug("Starting new connection to: {}", remoteAddress); - - // Remember our initial request so that we can write it after connecting - this.initialRequest = initialRequest; - initializeConnectionFlow(); - connectionFlow.start(); - } - - /** - * This method initializes our {@link ConnectionFlow} based on however this connection has been configured. If - * the {@link #disableSni} value is true, this method will not pass peer information to the MitmManager when - * handling CONNECTs. - */ - private void initializeConnectionFlow() { - this.connectionFlow = new ConnectionFlow(clientConnection, this, - connectLock) - .then(ConnectChannel); - - if (chainedProxy != null && chainedProxy.requiresEncryption()) { - connectionFlow.then(serverConnection.EncryptChannel(chainedProxy - .newSslEngine())); - } - - if (ProxyUtils.isCONNECT(initialRequest)) { - // If we're chaining, forward the CONNECT request - if (hasUpstreamChainedProxy()) { - connectionFlow.then( - serverConnection.HTTPCONNECTWithChainedProxy); - } - - MitmManager mitmManager = proxyServer.getMitmManager(); - boolean isMitmEnabled = mitmManager != null; - - if (isMitmEnabled) { - // When MITM is enabled and when chained proxy is set up, remoteAddress - // will be the chained proxy's address. So we use serverHostAndPort - // which is the end server's address. - HostAndPort parsedHostAndPort = HostAndPort.fromString(serverHostAndPort); - - // SNI may be disabled for this request due to a previous failed attempt to connect to the server - // with SNI enabled. - if (disableSni) { - connectionFlow.then(serverConnection.EncryptChannel(proxyServer.getMitmManager() - .serverSslEngine())); - } else { - connectionFlow.then(serverConnection.EncryptChannel(proxyServer.getMitmManager() - .serverSslEngine(parsedHostAndPort.getHost(), parsedHostAndPort.getPort()))); - } - - connectionFlow - .then(clientConnection.RespondCONNECTSuccessful) - .then(serverConnection.MitmEncryptClientChannel); - } else { - connectionFlow.then(serverConnection.StartTunneling) - .then(clientConnection.RespondCONNECTSuccessful) - .then(clientConnection.StartTunneling); - } - } - } - - /** - * Opens the socket connection. - */ - private ConnectionFlowStep ConnectChannel = new ConnectionFlowStep(this, - CONNECTING) { - @Override - boolean shouldExecuteOnEventLoop() { - return false; - } - - @Override - protected Future execute() { - Bootstrap cb = new Bootstrap().group(proxyServer.getProxyToServerWorkerFor(transportProtocol)); - - switch (transportProtocol) { - case TCP: - log.trace("Connecting to server with TCP"); - cb.channelFactory(new ChannelFactory() { - @Override - public Channel newChannel() { - return new NioSocketChannel(); - } - }); - break; - case UDT: - log.trace("Connecting to server with UDT"); - cb.channelFactory(NioUdtProvider.BYTE_CONNECTOR) - .option(ChannelOption.SO_REUSEADDR, true); - break; - default: - throw new UnknownTransportProtocolException(transportProtocol); - } - - cb.handler(new ChannelInitializer() { - protected void initChannel(Channel ch) throws Exception { - initChannelPipeline(ch.pipeline(), initialRequest); - }; - }); - cb.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, - proxyServer.getConnectTimeout()); - - if (localAddress != null) { - return cb.connect(remoteAddress, localAddress); - } else { - return cb.connect(remoteAddress); - } - } - }; - - /** - * Writes the HTTP CONNECT to the server and waits for a 200 response. - */ - private ConnectionFlowStep HTTPCONNECTWithChainedProxy = new ConnectionFlowStep( - this, AWAITING_CONNECT_OK) { - protected Future execute() { - log.trace("Handling CONNECT request through Chained Proxy"); - chainedProxy.filterRequest(initialRequest); - MitmManager mitmManager = proxyServer.getMitmManager(); - boolean isMitmEnabled = mitmManager != null; - /* - * We ignore the LastHttpContent which we read from the client - * connection when we are negotiating connect (see readHttp() - * in ProxyConnection). This cannot be ignored while we are - * doing MITM + Chained Proxy because the HttpRequestEncoder - * of the ProxyToServerConnection will be in an invalid state - * when the next request is written. Writing the EmptyLastContent - * resets its state. - */ - if(isMitmEnabled){ - ChannelFuture future = writeToChannel(initialRequest); - future.addListener(new ChannelFutureListener() { - - @Override - public void operationComplete(ChannelFuture arg0) throws Exception { - if(arg0.isSuccess()){ - writeToChannel(LastHttpContent.EMPTY_LAST_CONTENT); - } - } - }); - return future; - } else { - return writeToChannel(initialRequest); - } - } - - void onSuccess(ConnectionFlow flow) { - // Do nothing, since we want to wait for the CONNECT response to - // come back - } - - void read(ConnectionFlow flow, Object msg) { - // Here we're handling the response from a chained proxy to our - // earlier CONNECT request - boolean connectOk = false; - if (msg instanceof HttpResponse) { - HttpResponse httpResponse = (HttpResponse) msg; - int statusCode = httpResponse.getStatus().code(); - if (statusCode >= 200 && statusCode <= 299) { - connectOk = true; - } - } - if (connectOk) { - flow.advance(); - } else { - flow.fail(); - } - } - }; - - /** - *

- * Encrypts the client channel based on our server {@link SSLSession}. - *

- * - *

- * This does not wait for the handshake to finish so that we can go on and - * respond to the CONNECT request. - *

- */ - private ConnectionFlowStep MitmEncryptClientChannel = new ConnectionFlowStep( - this, HANDSHAKING) { - @Override - boolean shouldExecuteOnEventLoop() { - return false; - } - - @Override - boolean shouldSuppressInitialRequest() { - return true; - } - - @Override - protected Future execute() { - return clientConnection - .encrypt(proxyServer.getMitmManager() - .clientSslEngineFor(initialRequest, sslEngine.getSession()), false) - .addListener( - new GenericFutureListener>() { - @Override - public void operationComplete( - Future future) - throws Exception { - if (future.isSuccess()) { - clientConnection.setMitming(true); - } - } - }); - } - }; - - /** - * Called when the connection to the server or upstream chained proxy fails. This method may return true to indicate - * that the connection should be retried. If returning true, this method must set up the connection itself. - * - * @param cause the reason that our attempt to connect failed (can be null) - * @return true if we are trying to fall back to another connection - */ - protected boolean connectionFailed(Throwable cause) - throws UnknownHostException { - // unlike a browser, java throws an exception when receiving an unrecognized_name TLS warning, even if the server - // sends back a valid certificate for the expected host. we can retry the connection without SNI to allow the proxy - // to connect to these misconfigured hosts. we should only retry the connection without SNI if the connection - // failure happened when SNI was enabled, to prevent never-ending connection attempts due to SNI warnings. - if (!disableSni && cause instanceof SSLProtocolException) { - // unfortunately java does not expose the specific TLS alert number (112), so we have to look for the - // unrecognized_name string in the exception's message - if (cause.getMessage() != null && cause.getMessage().contains("unrecognized_name")) { - log.trace("Failed to connect to server due to an unrecognized_name SSL warning. Retrying connection without SNI."); - - // disable SNI, re-setup the connection, and restart the connection flow - disableSni = true; - resetConnectionForRetry(); - connectAndWrite(initialRequest); - - return true; - } - } - - // the connection issue wasn't due to an unrecognized_name error, or the connection attempt failed even after - // disabling SNI. before falling back to a chained proxy, re-enable SNI. - disableSni = false; - - if (chainedProxy != null) { - log.info("Connection to upstream server via chained proxy failed", cause); - // Let the ChainedProxy know that we were unable to connect - chainedProxy.connectionFailed(cause); - } else { - log.info("Connection to upstream server failed", cause); - } - - // attempt to connect using a chained proxy, if available - chainedProxy = availableChainedProxies.poll(); - if (chainedProxy != null) { - log.info("Retrying connecting using the next available chained proxy"); - - resetConnectionForRetry(); - - connectAndWrite(initialRequest); - return true; - } - - // no chained proxy fallback or other retry mechanism available - return false; - } - - /** - * Convenience method to prepare to retry this connection. Closes the connection's channel and sets up - * the connection again using {@link #setupConnectionParameters()}. - * - * @throws UnknownHostException when {@link #setupConnectionParameters()} is unable to resolve the hostname - */ - private void resetConnectionForRetry() throws UnknownHostException { - // Remove ourselves as handler on the old context - this.ctx.pipeline().remove(this); - this.ctx.close(); - this.ctx = null; - - this.setupConnectionParameters(); - } - - /** - * Set up our connection parameters based on server address and chained - * proxies. - * - * @throws UnknownHostException when unable to resolve the hostname to an IP address - */ - private void setupConnectionParameters() throws UnknownHostException { - if (chainedProxy != null - && chainedProxy != ChainedProxyAdapter.FALLBACK_TO_DIRECT_CONNECTION) { - this.transportProtocol = chainedProxy.getTransportProtocol(); - this.remoteAddress = chainedProxy.getChainedProxyAddress(); - this.localAddress = chainedProxy.getLocalAddress(); - } else { - this.transportProtocol = TransportProtocol.TCP; - - // Report DNS resolution to HttpFilters - this.remoteAddress = this.currentFilters.proxyToServerResolutionStarted(serverHostAndPort); - - // save the hostname and port of the unresolved address in hostAndPort, in case name resolution fails - String hostAndPort = null; - try { - if (this.remoteAddress == null) { - hostAndPort = serverHostAndPort; - this.remoteAddress = addressFor(serverHostAndPort, proxyServer); - } else if (this.remoteAddress.isUnresolved()) { - // filter returned an unresolved address, so resolve it using the proxy server's resolver - hostAndPort = HostAndPort.fromParts(this.remoteAddress.getHostName(), this.remoteAddress.getPort()).toString(); - this.remoteAddress = proxyServer.getServerResolver().resolve(this.remoteAddress.getHostName(), - this.remoteAddress.getPort()); - } - } catch (UnknownHostException e) { - // unable to resolve the hostname to an IP address. notify the filters of the failure before allowing the - // exception to bubble up. - this.currentFilters.proxyToServerResolutionFailed(hostAndPort); - - throw e; - } - - this.currentFilters.proxyToServerResolutionSucceeded(serverHostAndPort, this.remoteAddress); - - - this.localAddress = proxyServer.getLocalAddress(); - } - } - - /** - * Initialize our {@link ChannelPipeline} to connect the upstream server. - * LittleProxy acts as a client here. - * - * A {@link ChannelPipeline} invokes the read (Inbound) handlers in - * ascending ordering of the list and then the write (Outbound) handlers in - * descending ordering. - * - * Regarding the Javadoc of {@link HttpObjectAggregator} it's needed to have - * the {@link HttpResponseEncoder} or {@link HttpRequestEncoder} before the - * {@link HttpObjectAggregator} in the {@link ChannelPipeline}. - * - * @param pipeline - * @param httpRequest - */ - private void initChannelPipeline(ChannelPipeline pipeline, - HttpRequest httpRequest) { - - if (trafficHandler != null) { - pipeline.addLast("global-traffic-shaping", trafficHandler); - } - - pipeline.addLast("bytesReadMonitor", bytesReadMonitor); - pipeline.addLast("bytesWrittenMonitor", bytesWrittenMonitor); - - pipeline.addLast("encoder", new HttpRequestEncoder()); - pipeline.addLast("decoder", new HeadAwareHttpResponseDecoder( - proxyServer.getMaxInitialLineLength(), - proxyServer.getMaxHeaderSize(), - proxyServer.getMaxChunkSize())); - - // Enable aggregation for filtering if necessary - int numberOfBytesToBuffer = proxyServer.getFiltersSource() - .getMaximumResponseBufferSizeInBytes(); - if (numberOfBytesToBuffer > 0) { - aggregateContentForFiltering(pipeline, numberOfBytesToBuffer); - } - - pipeline.addLast("responseReadMonitor", responseReadMonitor); - pipeline.addLast("requestWrittenMonitor", requestWrittenMonitor); - - // Set idle timeout - pipeline.addLast( - "idle", - new IdleStateHandler(0, 0, proxyServer - .getIdleConnectionTimeout())); - - pipeline.addLast("handler", this); - } - - /** - *

- * Do all the stuff that needs to be done after our {@link ConnectionFlow} - * has succeeded. - *

- * - * @param shouldForwardInitialRequest - * whether or not we should forward the initial HttpRequest to - * the server after the connection has been established. - */ - void connectionSucceeded(boolean shouldForwardInitialRequest) { - become(AWAITING_INITIAL); - if (this.chainedProxy != null) { - // Notify the ChainedProxy that we successfully connected - try { - this.chainedProxy.connectionSucceeded(); - } catch (Exception e) { - log.error("Unable to record connectionSucceeded", e); - } - } - clientConnection.serverConnectionSucceeded(this, - shouldForwardInitialRequest); - - if (shouldForwardInitialRequest) { - log.trace("Writing initial request: {}", initialRequest); - write(initialRequest); - } else { - log.trace("Dropping initial request: {}", initialRequest); - } - - // we're now done with the initialRequest: it's either been forwarded to the upstream server (HTTP requests), or - // completely dropped (HTTPS CONNECTs). if the initialRequest is reference counted (typically because the HttpObjectAggregator is in - // the pipeline to generate FullHttpRequests), we need to manually release it to avoid a memory leak. - if (initialRequest instanceof ReferenceCounted) { - ((ReferenceCounted)initialRequest).release(); - } - } - - /** - * Build an {@link InetSocketAddress} for the given hostAndPort. - * - * @param hostAndPort String representation of the host and port - * @param proxyServer the current {@link DefaultHttpProxyServer} - * @return a resolved InetSocketAddress for the specified hostAndPort - * @throws UnknownHostException if hostAndPort could not be resolved, or if the input string could not be parsed into - * a host and port. - */ - public static InetSocketAddress addressFor(String hostAndPort, DefaultHttpProxyServer proxyServer) - throws UnknownHostException { - HostAndPort parsedHostAndPort; - try { - parsedHostAndPort = HostAndPort.fromString(hostAndPort); - } catch (IllegalArgumentException e) { - // we couldn't understand the hostAndPort string, so there is no way we can resolve it. - throw new UnknownHostException(hostAndPort); - } - - String host = parsedHostAndPort.getHost(); - int port = parsedHostAndPort.getPortOrDefault(80); - - return proxyServer.getServerResolver().resolve(host, port); - } - - /*************************************************************************** - * Activity Tracking/Statistics - * - * We track statistics on bytes, requests and responses by adding handlers - * at the appropriate parts of the pipeline (see initChannelPipeline()). - **************************************************************************/ - private final BytesReadMonitor bytesReadMonitor = new BytesReadMonitor() { - @Override - protected void bytesRead(int numberOfBytes) { - FullFlowContext flowContext = new FullFlowContext(clientConnection, - ProxyToServerConnection.this); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.bytesReceivedFromServer(flowContext, numberOfBytes); - } - } - }; - - private ResponseReadMonitor responseReadMonitor = new ResponseReadMonitor() { - @Override - protected void responseRead(HttpResponse httpResponse) { - FullFlowContext flowContext = new FullFlowContext(clientConnection, - ProxyToServerConnection.this); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.responseReceivedFromServer(flowContext, httpResponse); - } - } - }; - - private BytesWrittenMonitor bytesWrittenMonitor = new BytesWrittenMonitor() { - @Override - protected void bytesWritten(int numberOfBytes) { - FullFlowContext flowContext = new FullFlowContext(clientConnection, - ProxyToServerConnection.this); - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.bytesSentToServer(flowContext, numberOfBytes); - } - } - }; - - private RequestWrittenMonitor requestWrittenMonitor = new RequestWrittenMonitor() { - @Override - protected void requestWriting(HttpRequest httpRequest) { - FullFlowContext flowContext = new FullFlowContext(clientConnection, - ProxyToServerConnection.this); - try { - for (ActivityTracker tracker : proxyServer - .getActivityTrackers()) { - tracker.requestSentToServer(flowContext, httpRequest); - } - } catch (Throwable t) { - log.warn("Error while invoking ActivityTracker on request", t); - } - - currentFilters.proxyToServerRequestSending(); - } - - @Override - protected void requestWritten(HttpRequest httpRequest) { - } - - @Override - protected void contentWritten(HttpContent httpContent) { - if (httpContent instanceof LastHttpContent) { - currentFilters.proxyToServerRequestSent(); - } - } - }; - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyUtils.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyUtils.java deleted file mode 100644 index faa1722ddf..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ProxyUtils.java +++ /dev/null @@ -1,640 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.udt.nio.NioUdtProvider; -import io.netty.handler.codec.http.*; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.math.NumberUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.InetAddress; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.regex.Pattern; - -/** - * Utilities for the proxy. - */ -public class ProxyUtils { - /** - * Hop-by-hop headers that should be removed when proxying, as defined by the HTTP 1.1 spec, section 13.5.1 - * (http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1). Transfer-Encoding is NOT included in this list, since LittleProxy - * does not typically modify the transfer encoding. See also {@link #shouldRemoveHopByHopHeader(String)}. - * - * Header names are stored as lowercase to make case-insensitive comparisons easier. - */ - private static final Set SHOULD_NOT_PROXY_HOP_BY_HOP_HEADERS = ImmutableSet.of( - HttpHeaders.Names.CONNECTION.toLowerCase(Locale.US), - HttpHeaders.Names.PROXY_AUTHENTICATE.toLowerCase(Locale.US), - HttpHeaders.Names.PROXY_AUTHORIZATION.toLowerCase(Locale.US), - HttpHeaders.Names.TE.toLowerCase(Locale.US), - HttpHeaders.Names.TRAILER.toLowerCase(Locale.US), - /* Note: Not removing Transfer-Encoding since LittleProxy does not normally re-chunk content. - HttpHeaders.Names.TRANSFER_ENCODING.toLowerCase(Locale.US), */ - HttpHeaders.Names.UPGRADE.toLowerCase(Locale.US), - "Keep-Alive".toLowerCase(Locale.US) - ); - - private static final Logger LOG = LoggerFactory.getLogger(ProxyUtils.class); - - private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); - - /** - * Splits comma-separated header values (such as Connection) into their individual tokens. - */ - private static final Splitter COMMA_SEPARATED_HEADER_VALUE_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); - - /** - * Date format pattern used to parse HTTP date headers in RFC 1123 format. - */ - private static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; - - // Schemes are case-insensitive: - // http://tools.ietf.org/html/rfc3986#section-3.1 - private static Pattern HTTP_PREFIX = Pattern.compile("^https?://.*", - Pattern.CASE_INSENSITIVE); - - /** - * Strips the host from a URI string. This will turn "http://host.com/path" - * into "/path". - * - * @param uri - * The URI to transform. - * @return A string with the URI stripped. - */ - public static String stripHost(final String uri) { - if (!HTTP_PREFIX.matcher(uri).matches()) { - // It's likely a URI path, not the full URI (i.e. the host is - // already stripped). - return uri; - } - final String noHttpUri = StringUtils.substringAfter(uri, "://"); - final int slashIndex = noHttpUri.indexOf("/"); - if (slashIndex == -1) { - return "/"; - } - return noHttpUri.substring(slashIndex); - } - - /** - * Formats the given date according to the RFC 1123 pattern. - * - * @param date - * The date to format. - * @return An RFC 1123 formatted date string. - * - * @see #PATTERN_RFC1123 - */ - public static String formatDate(final Date date) { - return formatDate(date, PATTERN_RFC1123); - } - - /** - * Formats the given date according to the specified pattern. The pattern - * must conform to that used by the {@link SimpleDateFormat simple date - * format} class. - * - * @param date - * The date to format. - * @param pattern - * The pattern to use for formatting the date. - * @return A formatted date string. - * - * @throws IllegalArgumentException - * If the given date pattern is invalid. - * - * @see SimpleDateFormat - */ - public static String formatDate(final Date date, final String pattern) { - if (date == null) - throw new IllegalArgumentException("date is null"); - if (pattern == null) - throw new IllegalArgumentException("pattern is null"); - - final SimpleDateFormat formatter = new SimpleDateFormat(pattern, - Locale.US); - formatter.setTimeZone(GMT); - return formatter.format(date); - } - - /** - * If an HttpObject implements the market interface LastHttpContent, it - * represents the last chunk of a transfer. - * - * @see LastHttpContent - * - * @param httpObject - * @return - * - */ - public static boolean isLastChunk(final HttpObject httpObject) { - return httpObject instanceof LastHttpContent; - } - - /** - * If an HttpObject is not the last chunk, then that means there are other - * chunks that will follow. - * - * @see io.netty.handler.codec.http.FullHttpMessage - * - * @param httpObject - * @return - */ - public static boolean isChunked(final HttpObject httpObject) { - return !isLastChunk(httpObject); - } - - /** - * Parses the host and port an HTTP request is being sent to. - * - * @param httpRequest - * The request. - * @return The host and port string. - */ - public static String parseHostAndPort(final HttpRequest httpRequest) { - return parseHostAndPort(httpRequest.getUri()); - } - - /** - * Parses the host and port an HTTP request is being sent to. - * - * @param uri - * The URI. - * @return The host and port string. - */ - public static String parseHostAndPort(final String uri) { - final String tempUri; - if (!HTTP_PREFIX.matcher(uri).matches()) { - // Browsers particularly seem to send requests in this form when - // they use CONNECT. - tempUri = uri; - } else { - // We can't just take a substring from a hard-coded index because it - // could be either http or https. - tempUri = StringUtils.substringAfter(uri, "://"); - } - final String hostAndPort; - if (tempUri.contains("/")) { - hostAndPort = tempUri.substring(0, tempUri.indexOf("/")); - } else { - hostAndPort = tempUri; - } - return hostAndPort; - } - - /** - * Make a copy of the response including all mutable fields. - * - * @param original - * The original response to copy from. - * @return The copy with all mutable fields from the original. - */ - public static HttpResponse copyMutableResponseFields( - final HttpResponse original) { - - HttpResponse copy = null; - if (original instanceof DefaultFullHttpResponse) { - ByteBuf content = ((DefaultFullHttpResponse) original).content(); - copy = new DefaultFullHttpResponse(original.getProtocolVersion(), - original.getStatus(), content); - } else { - copy = new DefaultHttpResponse(original.getProtocolVersion(), - original.getStatus()); - } - final Collection headerNames = original.headers().names(); - for (final String name : headerNames) { - final List values = original.headers().getAll(name); - copy.headers().set(name, values); - } - return copy; - } - - /** - * Adds the Via header to specify that the message has passed through the proxy. The specified alias will be - * appended to the Via header line. The alias may be the hostname of the machine proxying the request, or a - * pseudonym. From RFC 7230, section 5.7.1: - *
-         The received-by portion of the field value is normally the host and
-         optional port number of a recipient server or client that
-         subsequently forwarded the message.  However, if the real host is
-         considered to be sensitive information, a sender MAY replace it with
-         a pseudonym.
-     * 
- * - * - * @param httpMessage HTTP message to add the Via header to - * @param alias the alias to provide in the Via header for this proxy - */ - public static void addVia(HttpMessage httpMessage, String alias) { - String newViaHeader = String.valueOf(httpMessage.getProtocolVersion().majorVersion()) + - '.' + - httpMessage.getProtocolVersion().minorVersion() + - ' ' + - alias; - - final List vias; - if (httpMessage.headers().contains(HttpHeaders.Names.VIA)) { - List existingViaHeaders = httpMessage.headers().getAll(HttpHeaders.Names.VIA); - vias = new ArrayList(existingViaHeaders); - vias.add(newViaHeader); - } else { - vias = Collections.singletonList(newViaHeader); - } - - httpMessage.headers().set(HttpHeaders.Names.VIA, vias); - } - - /** - * Returns true if the specified string is either "true" or - * "on" ignoring case. - * - * @param val - * The string in question. - * @return true if the specified string is either "true" or - * "on" ignoring case, otherwise false. - */ - public static boolean isTrue(final String val) { - return checkTrueOrFalse(val, "true", "on"); - } - - /** - * Returns true if the specified string is either "false" or - * "off" ignoring case. - * - * @param val - * The string in question. - * @return true if the specified string is either "false" or - * "off" ignoring case, otherwise false. - */ - public static boolean isFalse(final String val) { - return checkTrueOrFalse(val, "false", "off"); - } - - public static boolean extractBooleanDefaultFalse(final Properties props, - final String key) { - final String throttle = props.getProperty(key); - if (StringUtils.isNotBlank(throttle)) { - return throttle.trim().equalsIgnoreCase("true"); - } - return false; - } - - public static boolean extractBooleanDefaultTrue(final Properties props, - final String key) { - final String throttle = props.getProperty(key); - if (StringUtils.isNotBlank(throttle)) { - return throttle.trim().equalsIgnoreCase("true"); - } - return true; - } - - public static int extractInt(final Properties props, final String key) { - return extractInt(props, key, -1); - } - - public static int extractInt(final Properties props, final String key, int defaultValue) { - final String readThrottleString = props.getProperty(key); - if (StringUtils.isNotBlank(readThrottleString) && - NumberUtils.isNumber(readThrottleString)) { - return Integer.parseInt(readThrottleString); - } - return defaultValue; - } - - public static boolean isCONNECT(HttpObject httpObject) { - return httpObject instanceof HttpRequest - && HttpMethod.CONNECT.equals(((HttpRequest) httpObject) - .getMethod()); - } - - /** - * Returns true if the specified HttpRequest is a HEAD request. - * - * @param httpRequest http request - * @return true if request is a HEAD, otherwise false - */ - public static boolean isHEAD(HttpRequest httpRequest) { - return HttpMethod.HEAD.equals(httpRequest.getMethod()); - } - - private static boolean checkTrueOrFalse(final String val, - final String str1, final String str2) { - final String str = val.trim(); - return StringUtils.isNotBlank(str) - && (str.equalsIgnoreCase(str1) || str.equalsIgnoreCase(str2)); - } - - /** - * Returns true if the HTTP message cannot contain an entity body, according to the HTTP spec. This code is taken directly - * from {@link io.netty.handler.codec.http.HttpObjectDecoder#isContentAlwaysEmpty(HttpMessage)}. - * - * @param msg HTTP message - * @return true if the HTTP message is always empty, false if the message may have entity content. - */ - public static boolean isContentAlwaysEmpty(HttpMessage msg) { - if (msg instanceof HttpResponse) { - HttpResponse res = (HttpResponse) msg; - int code = res.getStatus().code(); - - // Correctly handle return codes of 1xx. - // - // See: - // - http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html Section 4.4 - // - https://github.com/netty/netty/issues/222 - if (code >= 100 && code < 200) { - // According to RFC 7231, section 6.1, 1xx responses have no content (https://tools.ietf.org/html/rfc7231#section-6.2): - // 1xx responses are terminated by the first empty line after - // the status-line (the empty line signaling the end of the header - // section). - - // Hixie 76 websocket handshake responses contain a 16-byte body, so their content is not empty; but Hixie 76 - // was a draft specification that was superceded by RFC 6455. Since it is rarely used and doesn't conform to - // RFC 7231, we do not support or make special allowance for Hixie 76 responses. - return true; - } - - switch (code) { - case 204: case 205: case 304: - return true; - } - } - return false; - } - - /** - * Returns true if the HTTP response from the server is expected to indicate its own message length/end-of-message. Returns false - * if the server is expected to indicate the end of the HTTP entity by closing the connection. - *

- * This method is based on the allowed message length indicators in the HTTP specification, section 4.4: - *

-         4.4 Message Length
-         The transfer-length of a message is the length of the message-body as it appears in the message; that is, after any transfer-codings have been applied. When a message-body is included with a message, the transfer-length of that body is determined by one of the following (in order of precedence):
-
-         1.Any response message which "MUST NOT" include a message-body (such as the 1xx, 204, and 304 responses and any response to a HEAD request) is always terminated by the first empty line after the header fields, regardless of the entity-header fields present in the message.
-         2.If a Transfer-Encoding header field (section 14.41) is present and has any value other than "identity", then the transfer-length is defined by use of the "chunked" transfer-coding (section 3.6), unless the message is terminated by closing the connection.
-         3.If a Content-Length header field (section 14.13) is present, its decimal value in OCTETs represents both the entity-length and the transfer-length. The Content-Length header field MUST NOT be sent if these two lengths are different (i.e., if a Transfer-Encoding
-         header field is present). If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.
-         [LP note: multipart/byteranges support has been removed from the HTTP 1.1 spec by RFC 7230, section A.2. Since it is seldom used, LittleProxy does not check for it.]
-         5.By the server closing the connection. (Closing the connection cannot be used to indicate the end of a request body, since that would leave no possibility for the server to send back a response.)
-     * 
- * - * The rules for Transfer-Encoding are clarified in RFC 7230, section 3.3.1 and 3.3.3 (3): - *
-         If any transfer coding other than
-         chunked is applied to a response payload body, the sender MUST either
-         apply chunked as the final transfer coding or terminate the message
-         by closing the connection.
-     * 
- * - * - * @param response the HTTP response object - * @return true if the message will indicate its own message length, or false if the server is expected to indicate the message length by closing the connection - */ - public static boolean isResponseSelfTerminating(HttpResponse response) { - if (isContentAlwaysEmpty(response)) { - return true; - } - - // if there is a Transfer-Encoding value, determine whether the final encoding is "chunked", which makes the message self-terminating - List allTransferEncodingHeaders = getAllCommaSeparatedHeaderValues(HttpHeaders.Names.TRANSFER_ENCODING, response); - if (!allTransferEncodingHeaders.isEmpty()) { - String finalEncoding = allTransferEncodingHeaders.get(allTransferEncodingHeaders.size() - 1); - - // per #3 above: "If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored." - // since the Transfer-Encoding field is present, the message is self-terminating if and only if the final Transfer-Encoding value is "chunked" - return HttpHeaders.Values.CHUNKED.equals(finalEncoding); - } - - String contentLengthHeader = HttpHeaders.getHeader(response, HttpHeaders.Names.CONTENT_LENGTH); - return contentLengthHeader != null && !contentLengthHeader.isEmpty(); - - // not checking for multipart/byteranges, since it is seldom used and its use as a message length indicator was removed in RFC 7230 - - // none of the other message length indicators are present, so the only way the server can indicate the end - // of this message is to close the connection - } - - /** - * Retrieves all comma-separated values for headers with the specified name on the HttpMessage. Any whitespace (spaces - * or tabs) surrounding the values will be removed. Empty values (e.g. two consecutive commas, or a value followed - * by a comma and no other value) will be removed; they will not appear as empty elements in the returned list. - * If the message contains repeated headers, their values will be added to the returned list in the order in which - * the headers appear. For example, if a message has headers like: - *
-     *     Transfer-Encoding: gzip,deflate
-     *     Transfer-Encoding: chunked
-     * 
- * This method will return a list of three values: "gzip", "deflate", "chunked". - *

- * Placing values on multiple header lines is allowed under certain circumstances - * in RFC 2616 section 4.2, and in RFC 7230 section 3.2.2 quoted here: - *

-     A sender MUST NOT generate multiple header fields with the same field
-     name in a message unless either the entire field value for that
-     header field is defined as a comma-separated list [i.e., #(values)]
-     or the header field is a well-known exception (as noted below).
-
-     A recipient MAY combine multiple header fields with the same field
-     name into one "field-name: field-value" pair, without changing the
-     semantics of the message, by appending each subsequent field value to
-     the combined field value in order, separated by a comma.  The order
-     in which header fields with the same field name are received is
-     therefore significant to the interpretation of the combined field
-     value; a proxy MUST NOT change the order of these field values when
-     forwarding a message.
-     * 
- * @param headerName the name of the header for which values will be retrieved - * @param httpMessage the HTTP message whose header values will be retrieved - * @return a list of single header values, or an empty list if the header was not present in the message or contained no values - */ - public static List getAllCommaSeparatedHeaderValues(String headerName, HttpMessage httpMessage) { - List allHeaders = httpMessage.headers().getAll(headerName); - if (allHeaders.isEmpty()) { - return Collections.emptyList(); - } - - ImmutableList.Builder headerValues = ImmutableList.builder(); - for (String header : allHeaders) { - List commaSeparatedValues = splitCommaSeparatedHeaderValues(header); - headerValues.addAll(commaSeparatedValues); - } - - return headerValues.build(); - } - - /** - * Duplicates the status line and headers of an HttpResponse object. Does not duplicate any content associated with that response. - * - * @param originalResponse HttpResponse to be duplicated - * @return a new HttpResponse with the same status line and headers - */ - public static HttpResponse duplicateHttpResponse(HttpResponse originalResponse) { - DefaultHttpResponse newResponse = new DefaultHttpResponse(originalResponse.getProtocolVersion(), originalResponse.getStatus()); - newResponse.headers().add(originalResponse.headers()); - - return newResponse; - } - - /** - * Attempts to resolve the local machine's hostname. - * - * @return the local machine's hostname, or null if a hostname cannot be determined - */ - public static String getHostName() { - try { - return InetAddress.getLocalHost().getHostName(); - } catch (IOException e) { - LOG.debug("Ignored exception", e); - } catch (RuntimeException e) { - // An exception here must not stop the proxy. Android could throw a - // runtime exception, since it not allows network access in the main - // process. - LOG.debug("Ignored exception", e); - } - LOG.info("Could not lookup localhost"); - return null; - } - - /** - * Determines if the specified header should be removed from the proxied response because it is a hop-by-hop header, as defined by the - * HTTP 1.1 spec in section 13.5.1. The comparison is case-insensitive, so "Connection" will be treated the same as "connection" or "CONNECTION". - * From http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1 : - *
-       The following HTTP/1.1 headers are hop-by-hop headers:
-        - Connection
-        - Keep-Alive
-        - Proxy-Authenticate
-        - Proxy-Authorization
-        - TE
-        - Trailers [LittleProxy note: actual header name is Trailer]
-        - Transfer-Encoding [LittleProxy note: this header is not normally removed when proxying, since the proxy does not re-chunk
-                            responses. The exception is when an HttpObjectAggregator is enabled, which aggregates chunked content and removes
-                            the 'Transfer-Encoding: chunked' header itself.]
-        - Upgrade
-
-       All other headers defined by HTTP/1.1 are end-to-end headers.
-     * 
- * - * @param headerName the header name - * @return true if this header is a hop-by-hop header and should be removed when proxying, otherwise false - */ - public static boolean shouldRemoveHopByHopHeader(String headerName) { - return SHOULD_NOT_PROXY_HOP_BY_HOP_HEADERS.contains(headerName.toLowerCase(Locale.US)); - } - - /** - * Splits comma-separated header values into tokens. For example, if the value of the Connection header is "Transfer-Encoding, close", - * this method will return "Transfer-Encoding" and "close". This method strips trims any optional whitespace from - * the tokens. Unlike {@link #getAllCommaSeparatedHeaderValues(String, HttpMessage)}, this method only operates on - * a single header value, rather than all instances of the header in a message. - * - * @param headerValue the un-tokenized header value (must not be null) - * @return all tokens within the header value, or an empty list if there are no values - */ - public static List splitCommaSeparatedHeaderValues(String headerValue) { - return ImmutableList.copyOf(COMMA_SEPARATED_HEADER_VALUE_SPLITTER.split(headerValue)); - } - - /** - * Determines if UDT is available on the classpath. - * - * @return true if UDT is available - */ - public static boolean isUdtAvailable() { - try { - return NioUdtProvider.BYTE_PROVIDER != null; - } catch (NoClassDefFoundError e) { - return false; - } - } - - /** - * Creates a new {@link FullHttpResponse} with the specified String as the body contents (encoded using UTF-8). - * - * @param httpVersion HTTP version of the response - * @param status HTTP status code - * @param body body to include in the FullHttpResponse; will be UTF-8 encoded - * @return new http response object - */ - public static FullHttpResponse createFullHttpResponse(HttpVersion httpVersion, - HttpResponseStatus status, - String body) { - byte[] bytes = body.getBytes(StandardCharsets.UTF_8); - ByteBuf content = Unpooled.copiedBuffer(bytes); - - return createFullHttpResponse(httpVersion, status, "text/html; charset=utf-8", content, bytes.length); - } - - /** - * Creates a new {@link FullHttpResponse} with no body content - * - * @param httpVersion HTTP version of the response - * @param status HTTP status code - * @return new http response object - */ - public static FullHttpResponse createFullHttpResponse(HttpVersion httpVersion, - HttpResponseStatus status) { - return createFullHttpResponse(httpVersion, status, null, null, 0); - } - - /** - * Creates a new {@link FullHttpResponse} with the specified body. - * - * @param httpVersion HTTP version of the response - * @param status HTTP status code - * @param contentType the Content-Type of the body - * @param body body to include in the FullHttpResponse; if null - * @param contentLength number of bytes to send in the Content-Length header; should equal the number of bytes in the ByteBuf - * @return new http response object - */ - public static FullHttpResponse createFullHttpResponse(HttpVersion httpVersion, - HttpResponseStatus status, - String contentType, - ByteBuf body, - int contentLength) { - DefaultFullHttpResponse response; - - if (body != null) { - response = new DefaultFullHttpResponse(httpVersion, status, body); - response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, contentLength); - response.headers().set(HttpHeaders.Names.CONTENT_TYPE, contentType); - } else { - response = new DefaultFullHttpResponse(httpVersion, status); - } - - return response; - } - - /** - * Given an HttpHeaders instance, removes 'sdch' from the 'Accept-Encoding' - * header list (if it exists) and returns the modified instance. - * - * Removes all occurrences of 'sdch' from the 'Accept-Encoding' header. - * @param headers The headers to modify. - */ - public static void removeSdchEncoding(HttpHeaders headers) { - List encodings = headers.getAll(HttpHeaders.Names.ACCEPT_ENCODING); - headers.remove(HttpHeaders.Names.ACCEPT_ENCODING); - - for (String encoding : encodings) { - if (encoding != null) { - // The former regex should remove occurrences of 'sdch' while the - // latter regex should take care of the dangling comma case when - // 'sdch' was the first element in the list and there are other - // encodings. - encoding = encoding.replaceAll(",? *(sdch|SDCH)", "").replaceFirst("^ *, *", ""); - - if (StringUtils.isNotBlank(encoding)) { - headers.add(HttpHeaders.Names.ACCEPT_ENCODING, encoding); - } - } - } - } -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ServerGroup.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ServerGroup.java deleted file mode 100644 index 7342c336cd..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ServerGroup.java +++ /dev/null @@ -1,291 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -import io.netty.channel.EventLoopGroup; -import io.netty.channel.udt.nio.NioUdtProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.TransportProtocol; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.UnknownTransportProtocolException; - -import java.nio.channels.spi.SelectorProvider; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Manages thread pools for one or more proxy server instances. When servers are created, they must register with the - * ServerGroup using {@link #registerProxyServer(HttpProxyServer)}, and when they shut down, must unregister with the - * ServerGroup using {@link #unregisterProxyServer(HttpProxyServer, boolean)}. - */ -public class ServerGroup { - private static final Logger log = LoggerFactory.getLogger(ServerGroup.class); - - /** - * The default number of threads to accept incoming requests from clients. (Requests are serviced by worker threads, - * not acceptor threads.) - */ - public static final int DEFAULT_INCOMING_ACCEPTOR_THREADS = 2; - - /** - * The default number of threads to service incoming requests from clients. - */ - public static final int DEFAULT_INCOMING_WORKER_THREADS = 8; - - /** - * The default number of threads to service outgoing requests to servers. - */ - public static final int DEFAULT_OUTGOING_WORKER_THREADS = 8; - - /** - * Global counter for the {@link #serverGroupId}. - */ - private static final AtomicInteger serverGroupCount = new AtomicInteger(0); - - /** - * A name for this ServerGroup to use in naming threads. - */ - private final String name; - - /** - * The ID of this server group. Forms part of the name of each thread created for this server group. Useful for - * differentiating threads when multiple proxy instances are running. - */ - private final int serverGroupId; - - private final int incomingAcceptorThreads; - private final int incomingWorkerThreads; - private final int outgoingWorkerThreads; - - /** - * List of all servers registered to use this ServerGroup. Any access to this list should be synchronized using the - * {@link #SERVER_REGISTRATION_LOCK}. - */ - public final List registeredServers = new ArrayList(1); - - /** - * A mapping of {@link TransportProtocol}s to their initialized {@link ProxyThreadPools}. Each transport uses a - * different thread pool, since the initialization parameters are different. - */ - private final EnumMap protocolThreadPools = new EnumMap(TransportProtocol.class); - - /** - * A mapping of selector providers to transport protocols. Avoids special-casing each transport protocol during - * transport protocol initialization. - */ - private static final EnumMap TRANSPORT_PROTOCOL_SELECTOR_PROVIDERS = new EnumMap(TransportProtocol.class); - static { - TRANSPORT_PROTOCOL_SELECTOR_PROVIDERS.put(TransportProtocol.TCP, SelectorProvider.provider()); - - // allow the proxy to operate without UDT support. this allows clients that do not use UDT to exclude the barchart - // dependency completely. - if (ProxyUtils.isUdtAvailable()) { - TRANSPORT_PROTOCOL_SELECTOR_PROVIDERS.put(TransportProtocol.UDT, NioUdtProvider.BYTE_PROVIDER); - } else { - log.trace("UDT provider not found on classpath. UDT transport will not be available."); - } - } - - /** - * True when this ServerGroup is stopped. - */ - private final AtomicBoolean stopped = new AtomicBoolean(false); - - /** - * Creates a new ServerGroup instance for a proxy. Threads created for this ServerGroup will have the specified - * ServerGroup name in the Thread name. This constructor does not actually initialize any thread pools; instead, - * thread pools for specific transport protocols are lazily initialized as needed. - * - * @param name ServerGroup name to include in thread names - * @param incomingAcceptorThreads number of acceptor threads per protocol - * @param incomingWorkerThreads number of client-to-proxy worker threads per protocol - * @param outgoingWorkerThreads number of proxy-to-server worker threads per protocol - */ - public ServerGroup(String name, int incomingAcceptorThreads, int incomingWorkerThreads, int outgoingWorkerThreads) { - this.name = name; - this.serverGroupId = serverGroupCount.getAndIncrement(); - this.incomingAcceptorThreads = incomingAcceptorThreads; - this.incomingWorkerThreads = incomingWorkerThreads; - this.outgoingWorkerThreads = outgoingWorkerThreads; - } - - /** - * Lock for initializing any transport protocols. - */ - private final Object THREAD_POOL_INIT_LOCK = new Object(); - - /** - * Retrieves the {@link ProxyThreadPools} for the specified transport protocol. Lazily initializes the thread pools - * for the transport protocol if they have not yet been initialized. If the protocol has already been initialized, - * this method returns immediately, without synchronization. If initialization is necessary, the initialization - * process creates the acceptor and worker threads necessary to service requests to/from the proxy. - *

- * This method is thread-safe; no external locking is necessary. - * - * @param protocol transport protocol to retrieve thread pools for - * @return thread pools for the specified transport protocol - */ - private ProxyThreadPools getThreadPoolsForProtocol(TransportProtocol protocol) { - // if the thread pools have not been initialized for this protocol, initialize them - if (protocolThreadPools.get(protocol) == null) { - synchronized (THREAD_POOL_INIT_LOCK) { - if (protocolThreadPools.get(protocol) == null) { - log.trace("Initializing thread pools for {} with {} acceptor threads, {} incoming worker threads, and {} outgoing worker threads", - protocol, incomingAcceptorThreads, incomingWorkerThreads, outgoingWorkerThreads); - - SelectorProvider selectorProvider = TRANSPORT_PROTOCOL_SELECTOR_PROVIDERS.get(protocol); - if (selectorProvider == null) { - throw new UnknownTransportProtocolException(protocol); - } - - ProxyThreadPools threadPools = new ProxyThreadPools(selectorProvider, - incomingAcceptorThreads, - incomingWorkerThreads, - outgoingWorkerThreads, - name, - serverGroupId); - protocolThreadPools.put(protocol, threadPools); - } - } - } - - return protocolThreadPools.get(protocol); - } - - /** - * Lock controlling access to the {@link #registerProxyServer(HttpProxyServer)} and {@link #unregisterProxyServer(HttpProxyServer, boolean)} - * methods. - */ - private final Object SERVER_REGISTRATION_LOCK = new Object(); - - /** - * Registers the specified proxy server as a consumer of this server group. The server group will not be shut down - * until the proxy unregisters itself. - * - * @param proxyServer proxy server instance to register - */ - public void registerProxyServer(HttpProxyServer proxyServer) { - synchronized (SERVER_REGISTRATION_LOCK) { - registeredServers.add(proxyServer); - } - } - - /** - * Unregisters the specified proxy server from this server group. If this was the last registered proxy server, the - * server group will be shut down. - * - * @param proxyServer proxy server instance to unregister - * @param graceful when true, the server group shutdown (if necessary) will be graceful - */ - public void unregisterProxyServer(HttpProxyServer proxyServer, boolean graceful) { - synchronized (SERVER_REGISTRATION_LOCK) { - boolean wasRegistered = registeredServers.remove(proxyServer); - if (!wasRegistered) { - log.warn("Attempted to unregister proxy server from ServerGroup that it was not registered with. Was the proxy unregistered twice?"); - } - - if (registeredServers.isEmpty()) { - log.trace("Proxy server unregistered from ServerGroup. No proxy servers remain registered, so shutting down ServerGroup."); - - shutdown(graceful); - } else { - log.trace("Proxy server unregistered from ServerGroup. Not shutting down ServerGroup ({} proxy servers remain registered).", registeredServers.size()); - } - } - } - - /** - * Shuts down all event loops owned by this server group. - * - * @param graceful when true, event loops will "gracefully" terminate, waiting for submitted tasks to finish - */ - private void shutdown(boolean graceful) { - if (!stopped.compareAndSet(false, true)) { - log.trace("Shutdown requested, but ServerGroup is already stopped. Doing nothing."); - - return; - } - - log.trace("Shutting down server group event loops " + (graceful ? "(graceful)" : "(non-graceful)")); - - // loop through all event loops managed by this server group. this includes acceptor and worker event loops - // for both TCP and UDP transport protocols. - List allEventLoopGroups = new ArrayList(); - - for (ProxyThreadPools threadPools : protocolThreadPools.values()) { - allEventLoopGroups.addAll(threadPools.getAllEventLoops()); - } - - for (EventLoopGroup group : allEventLoopGroups) { - if (graceful) { - group.shutdownGracefully(); - } else { - group.shutdownGracefully(0, 0, TimeUnit.SECONDS); - } - } - - if (graceful) { - for (EventLoopGroup group : allEventLoopGroups) { - try { - group.awaitTermination(60, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - - log.warn("Interrupted while shutting down event loop"); - } - } - } - - log.trace("Done shutting down server group"); - } - - /** - * Retrieves the client-to-proxy acceptor thread pool for the specified protocol. Initializes the pool if it has not - * yet been initialized. - *

- * This method is thread-safe; no external locking is necessary. - * - * @param protocol transport protocol to retrieve the thread pool for - * @return the client-to-proxy acceptor thread pool - */ - public EventLoopGroup getClientToProxyAcceptorPoolForTransport(TransportProtocol protocol) { - return getThreadPoolsForProtocol(protocol).getClientToProxyAcceptorPool(); - } - - /** - * Retrieves the client-to-proxy acceptor worker pool for the specified protocol. Initializes the pool if it has not - * yet been initialized. - *

- * This method is thread-safe; no external locking is necessary. - * - * @param protocol transport protocol to retrieve the thread pool for - * @return the client-to-proxy worker thread pool - */ - public EventLoopGroup getClientToProxyWorkerPoolForTransport(TransportProtocol protocol) { - return getThreadPoolsForProtocol(protocol).getClientToProxyWorkerPool(); - } - - /** - * Retrieves the proxy-to-server worker thread pool for the specified protocol. Initializes the pool if it has not - * yet been initialized. - *

- * This method is thread-safe; no external locking is necessary. - * - * @param protocol transport protocol to retrieve the thread pool for - * @return the proxy-to-server worker thread pool - */ - public EventLoopGroup getProxyToServerWorkerPoolForTransport(TransportProtocol protocol) { - return getThreadPoolsForProtocol(protocol).getProxyToServerWorkerPool(); - } - - /** - * @return true if this ServerGroup has already been stopped - */ - public boolean isStopped() { - return stopped.get(); - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ThreadPoolConfiguration.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ThreadPoolConfiguration.java deleted file mode 100644 index 783fe82e2c..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/impl/ThreadPoolConfiguration.java +++ /dev/null @@ -1,62 +0,0 @@ -package tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl; - -/** - * Configuration object for the proxy's thread pools. Controls the number of acceptor and worker threads in the Netty - * {@link io.netty.channel.EventLoopGroup} used by the proxy. - */ -public class ThreadPoolConfiguration { - private int acceptorThreads = ServerGroup.DEFAULT_INCOMING_ACCEPTOR_THREADS; - private int clientToProxyWorkerThreads = ServerGroup.DEFAULT_INCOMING_WORKER_THREADS; - private int proxyToServerWorkerThreads = ServerGroup.DEFAULT_OUTGOING_WORKER_THREADS; - - public int getClientToProxyWorkerThreads() { - return clientToProxyWorkerThreads; - } - - /** - * Set the number of client-to-proxy worker threads to create. Worker threads perform the actual processing of - * client requests. The default value is {@link ServerGroup#DEFAULT_INCOMING_WORKER_THREADS}. - * - * @param clientToProxyWorkerThreads number of client-to-proxy worker threads to create - * @return this thread pool configuration instance, for chaining - */ - public ThreadPoolConfiguration withClientToProxyWorkerThreads(int clientToProxyWorkerThreads) { - this.clientToProxyWorkerThreads = clientToProxyWorkerThreads; - return this; - } - - public int getAcceptorThreads() { - return acceptorThreads; - } - - /** - * Set the number of acceptor threads to create. Acceptor threads accept HTTP connections from the client and queue - * them for processing by client-to-proxy worker threads. The default value is - * {@link ServerGroup#DEFAULT_INCOMING_ACCEPTOR_THREADS}. - * - * @param acceptorThreads number of acceptor threads to create - * @return this thread pool configuration instance, for chaining - */ - public ThreadPoolConfiguration withAcceptorThreads(int acceptorThreads) { - this.acceptorThreads = acceptorThreads; - return this; - } - - public int getProxyToServerWorkerThreads() { - return proxyToServerWorkerThreads; - } - - /** - * Set the number of proxy-to-server worker threads to create. Proxy-to-server worker threads make requests to - * upstream servers and process responses from the server. The default value is - * {@link ServerGroup#DEFAULT_OUTGOING_WORKER_THREADS}. - * - * @param proxyToServerWorkerThreads number of proxy-to-server worker threads to create - * @return this thread pool configuration instance, for chaining - */ - public ThreadPoolConfiguration withProxyToServerWorkerThreads(int proxyToServerWorkerThreads) { - this.proxyToServerWorkerThreads = proxyToServerWorkerThreads; - return this; - } - -} diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/readme.md b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/readme.md deleted file mode 100644 index b2be1e842b..0000000000 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/proxy/readme.md +++ /dev/null @@ -1,5 +0,0 @@ -The code within this directory is a copy of the [LittleProxy](https://github.com/adamfisk/LittleProxy) -library that has fallen out of maintenence. Some small modifications made to accomodate more -recent dependency versions of Guava since this library has security vulenerabilities otherwise. - -The code within this directory will not be published in any manner and is only used for test purposes. \ No newline at end of file diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/FileUploadTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/FileUploadTests.java index 0936c62914..7da9169729 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/FileUploadTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/FileUploadTests.java @@ -6,6 +6,7 @@ package tests.integration.com.microsoft.azure.sdk.iot.iothub; +import com.github.monkeywie.proxyee.server.HttpProxyServer; import com.microsoft.azure.sdk.iot.device.ClientOptions; import com.microsoft.azure.sdk.iot.device.DeviceClient; import com.microsoft.azure.sdk.iot.device.FileUploadCompletionNotification; @@ -31,8 +32,6 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.FlakeyTest; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.DefaultHttpProxyServer; import tests.integration.com.microsoft.azure.sdk.iot.helpers.IntegrationTest; import tests.integration.com.microsoft.azure.sdk.iot.helpers.TestConstants; import tests.integration.com.microsoft.azure.sdk.iot.helpers.TestDeviceIdentity; @@ -147,15 +146,14 @@ public FileUploadState() @BeforeClass public static void startProxy() { - proxyServer = DefaultHttpProxyServer.bootstrap() - .withPort(testProxyPort) - .start(); + proxyServer = new HttpProxyServer(); + proxyServer.start(testProxyPort); } @AfterClass public static void stopProxy() { - proxyServer.stop(); + proxyServer.close(); } private DeviceClient setUpDeviceClient(IotHubClientProtocol protocol) throws URISyntaxException, InterruptedException, IOException, IotHubException, GeneralSecurityException, IotHubClientException diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java index 4b75a35c0f..05e72a6fa9 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java @@ -6,6 +6,7 @@ package tests.integration.com.microsoft.azure.sdk.iot.iothub; +import com.github.monkeywie.proxyee.server.HttpProxyServer; import com.microsoft.azure.sdk.iot.device.auth.IotHubSSLContext; import com.microsoft.azure.sdk.iot.device.ClientOptions; import com.microsoft.azure.sdk.iot.device.DeviceClient; @@ -50,9 +51,6 @@ import org.junit.rules.Timeout; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.DefaultHttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.BasicProxyAuthenticator; import tests.integration.com.microsoft.azure.sdk.iot.helpers.ErrorInjectionHelper; import tests.integration.com.microsoft.azure.sdk.iot.helpers.EventCallback; import tests.integration.com.microsoft.azure.sdk.iot.helpers.IntegrationTest; @@ -216,16 +214,14 @@ public void tearDownTest() @BeforeClass public static void startProxy() { - proxyServer = DefaultHttpProxyServer.bootstrap() - .withPort(testProxyPort) - .withProxyAuthenticator(new BasicProxyAuthenticator(testProxyUser, testProxyPass)) - .start(); + proxyServer = new HttpProxyServer(); + proxyServer.start(testProxyPort); } @AfterClass public static void stopProxy() { - proxyServer.stop(); + proxyServer.close(); } @Test diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java index f3c99da36c..ea77d1bc63 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java @@ -6,6 +6,7 @@ package tests.integration.com.microsoft.azure.sdk.iot.iothub; +import com.github.monkeywie.proxyee.server.HttpProxyServer; import com.microsoft.azure.sdk.iot.device.*; import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException; import com.microsoft.azure.sdk.iot.device.transport.IotHubConnectionStatus; @@ -22,8 +23,6 @@ import org.junit.Test; import org.junit.rules.RuleChain; import org.junit.rules.Timeout; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.DefaultHttpProxyServer; import tests.integration.com.microsoft.azure.sdk.iot.helpers.*; import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.IotHubTest; import tests.integration.com.microsoft.azure.sdk.iot.helpers.rules.RerunFailedTestRule; @@ -91,16 +90,14 @@ public static void setUp() @BeforeClass public static void startProxy() { - proxyServer = DefaultHttpProxyServer.bootstrap() - .withPort(testProxyPort) - .withProxyAuthenticator(new BasicProxyAuthenticator(testProxyUser, testProxyPass)) - .start(); + proxyServer = new HttpProxyServer(); + proxyServer.start(testProxyPort); } @AfterClass public static void stopProxy() { - proxyServer.stop(); + proxyServer.close(); } /** diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index 254eab6c82..280d930937 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -1,5 +1,6 @@ package tests.integration.com.microsoft.azure.sdk.iot.iothub.connection; +import com.github.monkeywie.proxyee.server.HttpProxyServer; import com.microsoft.azure.sdk.iot.device.*; import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; import com.microsoft.azure.sdk.iot.service.auth.IotHubConnectionStringBuilder; @@ -16,8 +17,6 @@ import tests.integration.com.microsoft.azure.sdk.iot.helpers.*; import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.IotHubTest; import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.StandardTierHubOnlyTest; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.DefaultHttpProxyServer; import javax.net.ssl.SSLContext; import java.io.IOException; @@ -187,16 +186,14 @@ public void dispose() @BeforeClass public static void startProxy() { - proxyServer = DefaultHttpProxyServer.bootstrap() - .withPort(testProxyPort) - .withProxyAuthenticator(new BasicProxyAuthenticator(testProxyUser, testProxyPass)) - .start(); + proxyServer = new HttpProxyServer(); + proxyServer.start(testProxyPort); } @AfterClass public static void stopProxy() { - proxyServer.stop(); + proxyServer.close(); } @Test(timeout = 60000) // 1 minute diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/setup/SendMessagesCommon.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/setup/SendMessagesCommon.java index d124b9ad10..cf6ac0f14a 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/setup/SendMessagesCommon.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/setup/SendMessagesCommon.java @@ -26,8 +26,6 @@ import org.junit.BeforeClass; import org.junit.runners.Parameterized; import tests.integration.com.microsoft.azure.sdk.iot.helpers.*; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.HttpProxyServer; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.proxy.impl.DefaultHttpProxyServer; import javax.net.ssl.SSLContext; import java.io.IOException; diff --git a/iot-e2e-tests/pom.xml b/iot-e2e-tests/pom.xml index 90aac5d0fa..c52ccafb8c 100644 --- a/iot-e2e-tests/pom.xml +++ b/iot-e2e-tests/pom.xml @@ -25,6 +25,15 @@ edge-e2e iot-e2e-jvm-tests + + + + com.github.monkeywie + proxyee + 1.7.6 + compile + + From 9791553c516744dbcc6944cfc38bcf30a6969994 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 15:50:51 -0800 Subject: [PATCH 086/114] test proxy with auth --- .../iot/iothub/MultiplexingClientTests.java | 19 ++++++++++++--- .../sdk/iot/iothub/TokenRenewalTests.java | 19 ++++++++++++--- .../iothub/connection/ConnectionTests.java | 23 +++++++++++++++---- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java index 05e72a6fa9..721658839b 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java @@ -7,6 +7,9 @@ import com.github.monkeywie.proxyee.server.HttpProxyServer; +import com.github.monkeywie.proxyee.server.HttpProxyServerConfig; +import com.github.monkeywie.proxyee.server.auth.BasicHttpProxyAuthenticationProvider; +import com.github.monkeywie.proxyee.server.auth.model.BasicHttpToken; import com.microsoft.azure.sdk.iot.device.auth.IotHubSSLContext; import com.microsoft.azure.sdk.iot.device.ClientOptions; import com.microsoft.azure.sdk.iot.device.DeviceClient; @@ -117,7 +120,7 @@ public class MultiplexingClientTests extends IntegrationTest protected static final String testProxyUser = "proxyUsername"; // lgtm // Semmle flags this as a security issue, but this is a test password so the warning can be suppressed - protected static final char[] testProxyPass = "1234".toCharArray(); // lgtm + protected static final String testProxyPass = "1234"; // lgtm @Parameterized.Parameters(name = "{0}") public static Collection inputs() throws Exception @@ -214,7 +217,17 @@ public void tearDownTest() @BeforeClass public static void startProxy() { - proxyServer = new HttpProxyServer(); + HttpProxyServerConfig config = new HttpProxyServerConfig(); + config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() { + @Override + protected BasicHttpToken authenticate(String usr, String pwd) { + if (testProxyUser.equals(usr) && testProxyPass.equals(pwd)) { + return new BasicHttpToken(usr, pwd); + } + return null; + } + }); + proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.start(testProxyPort); } @@ -471,7 +484,7 @@ public void sendMessagesWithProxy() throws Exception assumeTrue(testInstance.protocol == IotHubClientProtocol.AMQPS_WS); Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - ProxySettings proxySettings = new ProxySettings(testProxy, testProxyUser, testProxyPass); + ProxySettings proxySettings = new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray()); //re-setup test instance to use proxy instead testInstance.setup(DEVICE_MULTIPLEX_COUNT, MultiplexingClientOptions.builder().proxySettings(proxySettings).build(), false); diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java index ea77d1bc63..e04ae5bc91 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java @@ -7,6 +7,9 @@ import com.github.monkeywie.proxyee.server.HttpProxyServer; +import com.github.monkeywie.proxyee.server.HttpProxyServerConfig; +import com.github.monkeywie.proxyee.server.auth.BasicHttpProxyAuthenticationProvider; +import com.github.monkeywie.proxyee.server.auth.model.BasicHttpToken; import com.microsoft.azure.sdk.iot.device.*; import com.microsoft.azure.sdk.iot.device.exceptions.IotHubClientException; import com.microsoft.azure.sdk.iot.device.transport.IotHubConnectionStatus; @@ -56,7 +59,7 @@ public class TokenRenewalTests extends IntegrationTest protected static final String testProxyUser = "proxyUsername"; // lgtm // Semmle flags this as a security issue, but this is a test password so the warning can be suppressed - protected static final char[] testProxyPass = "1234".toCharArray(); // lgtm + protected static final String testProxyPass = "1234"; // lgtm final int SECONDS_FOR_SAS_TOKEN_TO_LIVE_BEFORE_RENEWAL = 30; @@ -90,7 +93,17 @@ public static void setUp() @BeforeClass public static void startProxy() { - proxyServer = new HttpProxyServer(); + HttpProxyServerConfig config = new HttpProxyServerConfig(); + config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() { + @Override + protected BasicHttpToken authenticate(String usr, String pwd) { + if (testProxyUser.equals(usr) && testProxyPass.equals(pwd)) { + return new BasicHttpToken(usr, pwd); + } + return null; + } + }); + proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.start(testProxyPort); } @@ -231,7 +244,7 @@ private List createClientsToTest() throws IotHubException, IOExc clients.add(createDeviceClient(protocol, null)); if (protocol == HTTPS || protocol == MQTT_WS || protocol == AMQPS_WS) { - ProxySettings proxySettings = new ProxySettings(testProxy, testProxyUser, testProxyPass); + ProxySettings proxySettings = new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray()); InternalClient client = createDeviceClient(protocol, proxySettings); clients.add(client); } diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index 280d930937..6fa12eedc2 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -1,6 +1,9 @@ package tests.integration.com.microsoft.azure.sdk.iot.iothub.connection; import com.github.monkeywie.proxyee.server.HttpProxyServer; +import com.github.monkeywie.proxyee.server.HttpProxyServerConfig; +import com.github.monkeywie.proxyee.server.auth.BasicHttpProxyAuthenticationProvider; +import com.github.monkeywie.proxyee.server.auth.model.BasicHttpToken; import com.microsoft.azure.sdk.iot.device.*; import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; import com.microsoft.azure.sdk.iot.service.auth.IotHubConnectionStringBuilder; @@ -105,7 +108,7 @@ public void setup() throws Exception if (this.useHttpProxy) { Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass)); + optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); } if (clientType == ClientType.DEVICE_CLIENT) @@ -124,7 +127,7 @@ public void setupEccDevice() throws Exception if (this.useHttpProxy) { Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass)); + optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); } X509CertificateGenerator certificateGenerator = new X509CertificateGenerator(X509CertificateGenerator.CertificateAlgorithm.ECC); @@ -181,12 +184,22 @@ public void dispose() protected static final String testProxyUser = "proxyUsername"; // lgtm // Semmle flags this as a security issue, but this is a test password so the warning can be suppressed - protected static final char[] testProxyPass = "1234".toCharArray(); // lgtm + protected static final String testProxyPass = "1234"; // lgtm @BeforeClass public static void startProxy() { - proxyServer = new HttpProxyServer(); + HttpProxyServerConfig config = new HttpProxyServerConfig(); + config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() { + @Override + protected BasicHttpToken authenticate(String usr, String pwd) { + if (testProxyUser.equals(usr) && testProxyPass.equals(pwd)) { + return new BasicHttpToken(usr, pwd); + } + return null; + } + }); + proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.start(testProxyPort); } @@ -253,7 +266,7 @@ public void CanOpenMultiplexingConnection() throws Exception if (testInstance.useHttpProxy) { Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass)); + optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); } MultiplexingClient multiplexingClient = new MultiplexingClient(hostName, testInstance.protocol, optionsBuilder.build()); From 8264d79b8d18c8efc534695a3f2beb71828b9fdd Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 16:21:42 -0800 Subject: [PATCH 087/114] old groups --- .../sdk/iot/androidtest/ExampleTest.java | 30 ----------- .../iothub/FileUploadAndroidRunner.java | 22 ++++++++ .../MultiplexingClientAndroidRunner.java | 52 +++++++++++++++++++ .../iothub/TokenRenewalAndroidRunner.java | 15 ++++++ .../ConnectionTestsAndroidRunner.java | 4 +- .../DirectMethodsErrInjAndroidRunner.java | 27 ++++++++++ .../ReceiveMessagesErrInjAndroidRunner.java | 26 ++++++++++ .../SendMessagesErrInjAndroidRunner.java | 26 ++++++++++ .../TwinErrInjAndroidRunner.java | 24 +++++++++ .../ReceiveMessagesAndroidRunner.java | 26 ++++++++++ .../messaging/SendMessagesAndroidRunner.java | 26 ++++++++++ .../methods/DirectMethodsAndroidRunner.java | 26 ++++++++++ .../iothub/twin/TwinAndroidRunner.java | 24 +++++++++ ...ioningClientSymmetricKeyAndroidRunner.java | 34 ++++++++++++ .../ProvisioningClientX509AndroidRunner.java | 34 ++++++++++++ ...rovisioningServiceClientAndroidRunner.java | 17 ++++++ ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 18 +++++++ 17 files changed, 399 insertions(+), 32 deletions(-) delete mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java rename iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/{ => iothub/connection}/ConnectionTestsAndroidRunner.java (85%) create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java deleted file mode 100644 index 8d25d4106f..0000000000 --- a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ExampleTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.microsoft.azure.sdk.iot.androidtest; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import com.microsoft.azure.sdk.iot.androidtest.testgroup.TestGroup1; -import com.microsoft.azure.sdk.iot.androidtest.testgroup.TestGroup2; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleTest { - @Test - @TestGroup1 - public void shouldPass() { - - } - - @Test - @TestGroup2 - public void shouldFail() { - Assert.fail("lolololol"); - } - -} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java new file mode 100644 index 0000000000..215c2a650c --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.FileUploadTests; + +@TestGroup10 +@RunWith(Parameterized.class) +public class FileUploadAndroidRunner extends FileUploadTests +{ + public FileUploadAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, boolean withProxy) throws Exception { + super(protocol, authenticationType, withProxy); + } +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java new file mode 100644 index 0000000000..3442c6df91 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.FlakeyTest; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.MultiplexingClientTests; + +@TestGroup6 +@RunWith(Parameterized.class) +public class MultiplexingClientAndroidRunner extends MultiplexingClientTests +{ + public MultiplexingClientAndroidRunner(IotHubClientProtocol protocol) + { + super(protocol); + } + + // This test is a bit too heavy for android to reliably pass, even for nightly builds + @Ignore + @Override + public void sendMessagesMaxDevicesAllowed() { + + } + + // This test is a bit too heavy for android to reliably pass, but it can still be run during nightly builds + @FlakeyTest + @Override + public void multiplexedConnectionRecoversFromDeviceSessionDropsParallel() { + + } + + // This test is a bit too heavy for android to reliably pass, but it can still be run during nightly builds + @FlakeyTest + @Override + public void multiplexedConnectionRecoversFromDeviceSessionDropsSequential() { + + } + + // This test is a bit too heavy for android to reliably pass, but it can still be run during nightly builds + @FlakeyTest + @Override + public void multiplexedConnectionRecoversFromTcpConnectionDrop() { + + } +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java new file mode 100644 index 0000000000..c0831a85db --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; + +import tests.integration.com.microsoft.azure.sdk.iot.iothub.TokenRenewalTests; + +@TestGroup12 +public class TokenRenewalAndroidRunner extends TokenRenewalTests +{ +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ConnectionTestsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java similarity index 85% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ConnectionTestsAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java index 6151f7b850..16a0d7f0d7 100644 --- a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/ConnectionTestsAndroidRunner.java +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java @@ -1,6 +1,6 @@ -package com.microsoft.azure.sdk.iot.androidtest; +package com.microsoft.azure.sdk.iot.androidtest.iothub.connection; -import com.microsoft.azure.sdk.iot.androidtest.testgroup.TestGroup11; +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; import org.junit.runner.RunWith; diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java new file mode 100644 index 0000000000..1989f4ad27 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.errorinjection; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.DirectMethodsErrInjTests; + +@TestGroup5 +@RunWith(Parameterized.class) +public class DirectMethodsErrInjAndroidRunner extends DirectMethodsErrInjTests +{ + public DirectMethodsErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} + diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java new file mode 100644 index 0000000000..a5cec7d907 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.errorinjection; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.ReceiveMessagesErrInjTests; + +@TestGroup3 +@RunWith(Parameterized.class) +public class ReceiveMessagesErrInjAndroidRunner extends ReceiveMessagesErrInjTests +{ + public ReceiveMessagesErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java new file mode 100644 index 0000000000..e59330fd21 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.errorinjection; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.SendMessagesErrInjTests; + +@TestGroup4 +@RunWith(Parameterized.class) +public class SendMessagesErrInjAndroidRunner extends SendMessagesErrInjTests +{ + public SendMessagesErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java new file mode 100644 index 0000000000..052c20a4a3 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.errorinjection; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.TwinErrInjTests; + +@TestGroup7 +@RunWith(Parameterized.class) +public class TwinErrInjAndroidRunner extends TwinErrInjTests +{ + public TwinErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java new file mode 100644 index 0000000000..9606b994a8 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.messaging; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.telemetry.ReceiveMessagesTests; + +@TestGroup8 +@RunWith(Parameterized.class) +public class ReceiveMessagesAndroidRunner extends ReceiveMessagesTests +{ + public ReceiveMessagesAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java new file mode 100644 index 0000000000..0e90fe9907 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.messaging; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.telemetry.SendMessagesTests; + +@TestGroup8 +@RunWith(Parameterized.class) +public class SendMessagesAndroidRunner extends SendMessagesTests +{ + public SendMessagesAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java new file mode 100644 index 0000000000..076d7b5416 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.methods; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.methods.DirectMethodsTests; + +@TestGroup9 +@RunWith(Parameterized.class) +public class DirectMethodsAndroidRunner extends DirectMethodsTests +{ + public DirectMethodsAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java new file mode 100644 index 0000000000..338b4fc504 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.twin; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; +import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; +import tests.integration.com.microsoft.azure.sdk.iot.iothub.twin.TwinTests; + +@TestGroup10 +@RunWith(Parameterized.class) +public class TwinAndroidRunner extends TwinTests +{ + public TwinAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception + { + super(protocol, authenticationType, clientType); + } +} diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java new file mode 100644 index 0000000000..2fadc6c0a9 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.provisioning; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.provisioning.device.ProvisioningDeviceClientTransportProtocol; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Collection; + +import tests.integration.com.microsoft.azure.sdk.iot.provisioning.ProvisioningTests; +import tests.integration.com.microsoft.azure.sdk.iot.provisioning.setup.ProvisioningCommon; + +@TestGroup1 +@RunWith(Parameterized.class) +public class ProvisioningClientSymmetricKeyAndroidRunner extends ProvisioningTests +{ + public ProvisioningClientSymmetricKeyAndroidRunner(ProvisioningDeviceClientTransportProtocol protocol, AttestationType attestationType) + { + super(protocol, attestationType); + } + + //This overrides the inputs defined in the super class. This is done to split this large test group into symmetric key and x509 runners. + @Parameterized.Parameters(name = "{0}_{1}") + public static Collection inputs() + { + return ProvisioningCommon.inputs(AttestationType.SYMMETRIC_KEY); + } +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java new file mode 100644 index 0000000000..26ae5c38f8 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.provisioning; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; +import com.microsoft.azure.sdk.iot.provisioning.device.ProvisioningDeviceClientTransportProtocol; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Collection; + +import tests.integration.com.microsoft.azure.sdk.iot.provisioning.ProvisioningTests; +import tests.integration.com.microsoft.azure.sdk.iot.provisioning.setup.ProvisioningCommon; + +@TestGroup2 +@RunWith(Parameterized.class) +public class ProvisioningClientX509AndroidRunner extends ProvisioningTests +{ + public ProvisioningClientX509AndroidRunner(ProvisioningDeviceClientTransportProtocol protocol, AttestationType attestationType) + { + super(protocol, attestationType); + } + + //This overrides the inputs defined in the super class. This is done to split this large test group into symmetric key and x509 runners. + @Parameterized.Parameters(name = "{0}_{1}") + public static Collection inputs() + { + return ProvisioningCommon.inputs(AttestationType.X509); //tpm tests can't be run on Android until infrastructure is setup + } +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java new file mode 100644 index 0000000000..99813fc29f --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.provisioning; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.TestGroup1; + +import tests.integration.com.microsoft.azure.sdk.iot.provisioning.ProvisioningServiceClientTests; + +@TestGroup1 +public class ProvisioningServiceClientAndroidRunner extends ProvisioningServiceClientTests +{ + // Intentionally empty class. The important part of this file is that the class inherits tests + // from ProvisioningServiceClientTests and is assigned to a test group. +} \ No newline at end of file diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 5daa5c3e36..bd928629cd 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -310,8 +310,26 @@ jobs: ANDROID_TEST_GROUP_ID: TestGroup1 TestGroup2: ANDROID_TEST_GROUP_ID: TestGroup2 + TestGroup3: + ANDROID_TEST_GROUP_ID: TestGroup3 + TestGroup4: + ANDROID_TEST_GROUP_ID: TestGroup4 + TestGroup5: + ANDROID_TEST_GROUP_ID: TestGroup5 + TestGroup6: + ANDROID_TEST_GROUP_ID: TestGroup6 + TestGroup7: + ANDROID_TEST_GROUP_ID: TestGroup7 + TestGroup8: + ANDROID_TEST_GROUP_ID: TestGroup8 + TestGroup9: + ANDROID_TEST_GROUP_ID: TestGroup9 + TestGroup10: + ANDROID_TEST_GROUP_ID: TestGroup10 TestGroup11: ANDROID_TEST_GROUP_ID: TestGroup11 + TestGroup12: + ANDROID_TEST_GROUP_ID: TestGroup12 displayName: Android Test dependsOn: AndroidBuild From 4a58154a55d05d7e766ba8605a0bd822428ea6e4 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 16:24:42 -0800 Subject: [PATCH 088/114] digital twin tests --- .../DigitalTwinClientAndroidRunner.java | 17 +++++++++++++++++ ...alTwinClientComponentTestsAndroidRunner.java | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java create mode 100644 iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java new file mode 100644 index 0000000000..9231a7a8bb --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.digitaltwin; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; + +import tests.integration.com.microsoft.azure.sdk.iot.digitaltwin.DigitalTwinClientTests; + +@TestGroup10 +public class DigitalTwinClientAndroidRunner extends DigitalTwinClientTests +{ + // Intentionally empty class. The important part of this file is that the class inherits tests + // from DigitalTwinClientTests and is assigned to a test group. +} \ No newline at end of file diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java new file mode 100644 index 0000000000..bac2cc95d0 --- /dev/null +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +package com.microsoft.azure.sdk.iot.androidtest.iothub.digitaltwin; + +import com.microsoft.azure.sdk.iot.androidtest.testgroup.*; + +import tests.integration.com.microsoft.azure.sdk.iot.digitaltwin.DigitalTwinClientComponentTests; + +@TestGroup10 +public class DigitalTwinClientComponentTestsAndroidRunner extends DigitalTwinClientComponentTests +{ + // Intentionally empty class. The important part of this file is that the class inherits tests + // from DigitalTwinClientComponentTests and is assigned to a test group. +} \ No newline at end of file From a6fe5f8708efca8bb182840773c0247378296402 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 16:37:56 -0800 Subject: [PATCH 089/114] timeout --- .../azure/sdk/iot/iothub/connection/ConnectionTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index 6fa12eedc2..9b92d00eaf 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -249,7 +249,7 @@ public void CanOpenConnectionWithECCCertificates() throws Exception testInstance.identity.getClient().close(); } - @Test + @Test(timeout = 60000) // 1 minute @IotHubTest public void CanOpenMultiplexingConnection() throws Exception { From 51d9ab35a4b18b544fe3faea3bfcabaa15aab7b1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 16:55:42 -0800 Subject: [PATCH 090/114] manifest --- iot-e2e-tests/android2/app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml index 44008a4332..5357a2198b 100644 --- a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml +++ b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file From 6d25533fa871aafe801640e5e7c4969a42abc13e Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 17:12:56 -0800 Subject: [PATCH 091/114] manifest error? --- .../android2/app/src/main/AndroidManifest.xml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml index 5357a2198b..7bc67652e6 100644 --- a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml +++ b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml @@ -1,4 +1,21 @@ - + + + + + + + + + + + + \ No newline at end of file From 18fb3e688cf1520a93133abadda0e13d31a4c24d Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 17:44:25 -0800 Subject: [PATCH 092/114] ? --- .../android2/app/src/main/AndroidManifest.xml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml index 7bc67652e6..c70e12201d 100644 --- a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml +++ b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml @@ -3,19 +3,4 @@ package="com.microsoft.azure.sdk.iot.androidtest"> - - - - - - - - - - \ No newline at end of file From 973cc7e673c9579ee654722f200765c82716c9b9 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 18:42:02 -0800 Subject: [PATCH 093/114] not needed --- iot-e2e-tests/android/app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iot-e2e-tests/android/app/build.gradle b/iot-e2e-tests/android/app/build.gradle index 7451d2fc8f..0b86c4f4a3 100644 --- a/iot-e2e-tests/android/app/build.gradle +++ b/iot-e2e-tests/android/app/build.gradle @@ -30,8 +30,8 @@ android { //buildTypes.mBuildConfigFields 'DATATYPE','VARIABLE',|"GRADLE VARIABLE|"' buildConfigField STRING, 'IOTHUB_CONNECTION_STRING', IOTHUB_CONNECTION_STRING_ENV_VAR_NAME buildConfigField STRING, 'IOT_DPS_CONNECTION_STRING', IOT_DPS_CONNECTION_STRING - buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT - buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING + //buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT + //buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING buildConfigField STRING, 'IOT_DPS_ID_SCOPE', DEVICE_PROVISIONING_SERVICE_ID_SCOPE buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST From ee3ab65e0c1c979a6d7ac3effb6a1c79532d16a1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 18:43:00 -0800 Subject: [PATCH 094/114] asdf --- iot-e2e-tests/android/app/build.gradle | 4 ++-- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iot-e2e-tests/android/app/build.gradle b/iot-e2e-tests/android/app/build.gradle index 0b86c4f4a3..67dd0a2aa5 100644 --- a/iot-e2e-tests/android/app/build.gradle +++ b/iot-e2e-tests/android/app/build.gradle @@ -3,8 +3,8 @@ apply plugin: 'com.android.application' //***********************************************************************************************// def IOTHUB_CONNECTION_STRING_ENV_VAR_NAME = project.hasProperty('IOTHUB_CONNECTION_STRING') ? '"'+project.property('IOTHUB_CONNECTION_STRING')+'"' : '""' def IOT_DPS_CONNECTION_STRING = project.hasProperty('IOT_DPS_CONNECTION_STRING') ? '"'+project.property('IOT_DPS_CONNECTION_STRING')+'"': '""' -def INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT = project.hasProperty('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT') ? '"'+project.property('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT')+'"': '""' -def INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING = project.hasProperty('PROVISIONING_CONNECTION_STRING_INVALIDCERT') ? '"'+project.property('PROVISIONING_CONNECTION_STRING_INVALIDCERT')+'"': '""' +//def INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT = project.hasProperty('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT') ? '"'+project.property('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT')+'"': '""' +//def INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING = project.hasProperty('PROVISIONING_CONNECTION_STRING_INVALIDCERT') ? '"'+project.property('PROVISIONING_CONNECTION_STRING_INVALIDCERT')+'"': '""' def DEVICE_PROVISIONING_SERVICE_ID_SCOPE = project.hasProperty('IOT_DPS_ID_SCOPE') ? '"'+project.property('IOT_DPS_ID_SCOPE')+'"': '""' def IS_BASIC_TIER_HUB = project.hasProperty('IS_BASIC_TIER_HUB') ? '"'+project.property('IS_BASIC_TIER_HUB')+'"' : '"false"' def IS_PULL_REQUEST = project.hasProperty('IS_PULL_REQUEST') ? '"'+project.property('IS_PULL_REQUEST')+'"' : '"false"' diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index bd928629cd..256077d9cf 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -270,7 +270,7 @@ jobs: JAVA_VERSION: $(JAVA_VERSION) IOT_DPS_CONNECTION_STRING: $(PROVISIONING_CONNECTION_STRING) IOT_DPS_ID_SCOPE: $(DPS_IDSCOPE) - IOTHUB_CONNECTION_STRING: "bob" + IOTHUB_CONNECTION_STRING: $(IOTHUB_CONNECTION_STRING) TARGET_BRANCH: $(System.PullRequest.TargetBranch) RECYCLE_TEST_IDENTITIES: "true" condition: always() From 616a74494879f40ee01cd160f61c54c271021132 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 18:43:41 -0800 Subject: [PATCH 095/114] fix? --- vsts/gradle_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index fb4ea5a8a3..4b0f63e7ab 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -20,5 +20,5 @@ Write-Host "Assembling the test APK with the provided secrets" ./gradlew :app:assembleDebugAndroidTest ` `-PIOTHUB_CONNECTION_STRING=$env:IOTHUB_CONNECTION_STRING ` `-PIOT_DPS_CONNECTION_STRING=$env:IOT_DPS_CONNECTION_STRING ` - `-PIOT_DPS_ID_SCOPE=$env:DEVICE_PROVISIONING_SERVICE_ID_SCOPE ` + `-PIOT_DPS_ID_SCOPE=$env:IOT_DPS_ID_SCOPE ` `-PRECYCLE_TEST_IDENTITIES=true From e507afec3028e067aaccc0173b5f5a24677e5f86 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Tue, 20 Jan 2026 19:38:37 -0800 Subject: [PATCH 096/114] delete old android path --- iot-e2e-tests/android/AndroidDeviceSelect.py | 34 ------- iot-e2e-tests/android/app/build.gradle | 96 ------------------- iot-e2e-tests/android/app/proguard-rules.pro | 31 ------ .../DigitalTwinClientAndroidRunner.java | 17 ---- ...TwinClientComponentTestsAndroidRunner.java | 17 ---- .../sdk/iot/android/helper/TestGroup1.java | 17 ---- .../sdk/iot/android/helper/TestGroup10.java | 17 ---- .../sdk/iot/android/helper/TestGroup11.java | 17 ---- .../sdk/iot/android/helper/TestGroup12.java | 17 ---- .../sdk/iot/android/helper/TestGroup2.java | 17 ---- .../sdk/iot/android/helper/TestGroup3.java | 17 ---- .../sdk/iot/android/helper/TestGroup4.java | 17 ---- .../sdk/iot/android/helper/TestGroup5.java | 17 ---- .../sdk/iot/android/helper/TestGroup6.java | 17 ---- .../sdk/iot/android/helper/TestGroup7.java | 17 ---- .../sdk/iot/android/helper/TestGroup8.java | 17 ---- .../sdk/iot/android/helper/TestGroup9.java | 17 ---- .../iothub/FileUploadAndroidRunner.java | 22 ----- .../MultiplexingClientAndroidRunner.java | 52 ---------- .../iothub/TokenRenewalAndroidRunner.java | 15 --- .../ConnectionTestsAndroidRunner.java | 19 ---- .../DirectMethodsErrInjAndroidRunner.java | 27 ------ .../ReceiveMessagesErrInjAndroidRunner.java | 26 ----- .../SendMessagesErrInjAndroidRunner.java | 26 ----- .../TwinErrInjAndroidRunner.java | 24 ----- .../ReceiveMessagesAndroidRunner.java | 26 ----- .../messaging/SendMessagesAndroidRunner.java | 26 ----- .../methods/DirectMethodsAndroidRunner.java | 26 ----- .../iothub/twin/TwinAndroidRunner.java | 24 ----- ...ioningClientSymmetricKeyAndroidRunner.java | 34 ------- .../ProvisioningClientX509AndroidRunner.java | 34 ------- ...rovisioningServiceClientAndroidRunner.java | 17 ---- .../android/app/src/main/AndroidManifest.xml | 6 -- iot-e2e-tests/android/build.gradle | 26 ----- iot-e2e-tests/android/gradle.properties | 18 ---- .../gradle/wrapper/gradle-wrapper.properties | 0 iot-e2e-tests/android/renew_env.cmd | 12 --- .../android/runInstrumentationTests.py | 20 ---- iot-e2e-tests/android/runTestsOnThings.cmd | 16 ---- iot-e2e-tests/android/settings.gradle | 1 - 40 files changed, 896 deletions(-) delete mode 100644 iot-e2e-tests/android/AndroidDeviceSelect.py delete mode 100644 iot-e2e-tests/android/app/build.gradle delete mode 100644 iot-e2e-tests/android/app/proguard-rules.pro delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup1.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup10.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup11.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup12.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup2.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup3.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup4.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup5.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup6.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup7.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup8.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup9.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/FileUploadAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/MultiplexingClientAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/TokenRenewalAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/connection/ConnectionTestsAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/TwinErrInjAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/ReceiveMessagesAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/SendMessagesAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/methods/DirectMethodsAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/twin/TwinAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientX509AndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningServiceClientAndroidRunner.java delete mode 100644 iot-e2e-tests/android/app/src/main/AndroidManifest.xml delete mode 100644 iot-e2e-tests/android/build.gradle delete mode 100644 iot-e2e-tests/android/gradle.properties delete mode 100644 iot-e2e-tests/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 iot-e2e-tests/android/renew_env.cmd delete mode 100644 iot-e2e-tests/android/runInstrumentationTests.py delete mode 100644 iot-e2e-tests/android/runTestsOnThings.cmd delete mode 100644 iot-e2e-tests/android/settings.gradle diff --git a/iot-e2e-tests/android/AndroidDeviceSelect.py b/iot-e2e-tests/android/AndroidDeviceSelect.py deleted file mode 100644 index 7089b6c016..0000000000 --- a/iot-e2e-tests/android/AndroidDeviceSelect.py +++ /dev/null @@ -1,34 +0,0 @@ -import os -import time -import re - -def setTarget(deviceName): - #os.popen("echo " + deviceName + ">device_udid.txt").read() - os.popen("setx ANDROID_DEVICE_NAME "+deviceName).read() - -def getDeviceList(): - res = os.popen("adb devices").read() - formatted_string = res.strip().split('\n') - deviceList = [] - for x in formatted_string: - if "\tdevice" in x: - deviceList.append(x) - print (deviceList) - return deviceList - -def killAvd(): - hasRealDevice = False - deviceList = getDeviceList() - print("Getting connected Devices") - for device in deviceList: - if not device.startswith('emulator'): - hasRealDevice = True - print("found real device "+device) - device = re.sub('\tdevice$', '', device) - setTarget(device) - break - if not hasRealDevice: - print("no real android device found") - -print("selecting android device") -killAvd() \ No newline at end of file diff --git a/iot-e2e-tests/android/app/build.gradle b/iot-e2e-tests/android/app/build.gradle deleted file mode 100644 index 67dd0a2aa5..0000000000 --- a/iot-e2e-tests/android/app/build.gradle +++ /dev/null @@ -1,96 +0,0 @@ -apply plugin: 'com.android.application' - -//***********************************************************************************************// -def IOTHUB_CONNECTION_STRING_ENV_VAR_NAME = project.hasProperty('IOTHUB_CONNECTION_STRING') ? '"'+project.property('IOTHUB_CONNECTION_STRING')+'"' : '""' -def IOT_DPS_CONNECTION_STRING = project.hasProperty('IOT_DPS_CONNECTION_STRING') ? '"'+project.property('IOT_DPS_CONNECTION_STRING')+'"': '""' -//def INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT = project.hasProperty('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT') ? '"'+project.property('DPS_GLOBALDEVICEENDPOINT_INVALIDCERT')+'"': '""' -//def INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING = project.hasProperty('PROVISIONING_CONNECTION_STRING_INVALIDCERT') ? '"'+project.property('PROVISIONING_CONNECTION_STRING_INVALIDCERT')+'"': '""' -def DEVICE_PROVISIONING_SERVICE_ID_SCOPE = project.hasProperty('IOT_DPS_ID_SCOPE') ? '"'+project.property('IOT_DPS_ID_SCOPE')+'"': '""' -def IS_BASIC_TIER_HUB = project.hasProperty('IS_BASIC_TIER_HUB') ? '"'+project.property('IS_BASIC_TIER_HUB')+'"' : '"false"' -def IS_PULL_REQUEST = project.hasProperty('IS_PULL_REQUEST') ? '"'+project.property('IS_PULL_REQUEST')+'"' : '"false"' -def RECYCLE_TEST_IDENTITIES = project.hasProperty('RECYCLE_TEST_IDENTITIES') ? '"'+project.property('RECYCLE_TEST_IDENTITIES')+'"' : '"false"' - -def STRING='String' -//***********************************************************************************************// - -android { - compileSdkVersion 28 - - defaultConfig { - javaCompileOptions.annotationProcessorOptions.includeCompileClasspath true - applicationId "com.iothub.azure.microsoft.com.androide2e" - minSdkVersion 24 - targetSdkVersion 28 - multiDexEnabled true - versionCode 1 - versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - //********** We can define variables here ********** - each { - //buildTypes.mBuildConfigFields 'DATATYPE','VARIABLE',|"GRADLE VARIABLE|"' - buildConfigField STRING, 'IOTHUB_CONNECTION_STRING', IOTHUB_CONNECTION_STRING_ENV_VAR_NAME - buildConfigField STRING, 'IOT_DPS_CONNECTION_STRING', IOT_DPS_CONNECTION_STRING - //buildConfigField STRING, 'DPS_GLOBALDEVICEENDPOINT_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_GLOBAL_ENDPOINT - //buildConfigField STRING, 'PROVISIONING_CONNECTION_STRING_INVALIDCERT', INVALID_DEVICE_PROVISIONING_SERVICE_CONNECTION_STRING - buildConfigField STRING, 'IOT_DPS_ID_SCOPE', DEVICE_PROVISIONING_SERVICE_ID_SCOPE - buildConfigField STRING, 'IS_BASIC_TIER_HUB', IS_BASIC_TIER_HUB - buildConfigField STRING, 'IS_PULL_REQUEST', IS_PULL_REQUEST - buildConfigField STRING, 'RECYCLE_TEST_IDENTITIES', RECYCLE_TEST_IDENTITIES - } - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - packagingOptions { - exclude "META-INF/*.SF" - exclude "META-INF/*.DSA" - exclude "META-INF/*.RSA" - exclude 'META-INF/DEPENDENCIES' - exclude 'META-INF/NOTICE' - exclude 'META-INF/LICENSE' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/NOTICE.txt' - exclude 'thirdpartynotice.txt' - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - lintOptions{ - ignore 'InvalidPackage' - } -} - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support:appcompat-v7:28.0.0' - implementation 'com.android.support:multidex:1.0.3' - - // This jar contains the test code that will be run on android. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run - implementation files('../../common/target/iot-e2e-common-1.0.0-tests.jar') - - // This jar contains the dependencies of the test code. DeviceClient, for instance. This jar isn't in the m2 folder, but rather it is in this cloned repo after mvn install is run - implementation files('../../common/target/iot-e2e-common-1.0.0-with-deps.jar') - - implementation ('org.apache.commons:commons-lang3:3.6') - implementation ('javax.xml.stream:stax-api:1.0-2') - - androidTestImplementation 'com.android.support:support-annotations:27.1.1' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'junit:junit:4.12' -} - -repositories { - mavenLocal() - mavenCentral() -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/proguard-rules.pro b/iot-e2e-tests/android/app/proguard-rules.pro deleted file mode 100644 index 6947b3de18..0000000000 --- a/iot-e2e-tests/android/app/proguard-rules.pro +++ /dev/null @@ -1,31 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in C:\Users\v-askhur.REDMOND\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# JSON parser classes don't mix well with minification because JSON parser classes use reflection -# based on the name of the field to create the JSON, and minification changes those names. As a result -# all the message payload serializing and deserializing breaks. These lines explicitly exclude -# the packages where we keep our JSON parsing classes from minification to avoid this issue --keep class com.microsoft.azure.sdk.iot.provisioning.device.internal.parser.* { *; } --keep class com.microsoft.azure.sdk.iot.deps.serializer.* { *; } --keep class com.microsoft.azure.sdk.iot.provisioning.service.configs.* { *; } --keep class com.microsoft.azure.sdk.iot.deps.twin.* { *; } --keep class com.microsoft.azure.sdk.iot.service.registry.ImportMode { *; } --keep class com.microsoft.azure.sdk.iot.service.AuthenticationMechanism { *; } --keep class com.microsoft.azure.sdk.iot.device.edge.MethodRequest { *; } --keep class com.microsoft.azure.sdk.iot.device.hsm.parser.ErrorResponse { *; } --keep class com.microsoft.azure.sdk.iot.device.hsm.parser.SignRequest { *; } \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientAndroidRunner.java deleted file mode 100644 index d3d041bf1c..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientAndroidRunner.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.digitaltwin; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup10; - -import tests.integration.com.microsoft.azure.sdk.iot.digitaltwin.DigitalTwinClientTests; - -@TestGroup10 -public class DigitalTwinClientAndroidRunner extends DigitalTwinClientTests -{ - // Intentionally empty class. The important part of this file is that the class inherits tests - // from DigitalTwinClientTests and is assigned to a test group. -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java deleted file mode 100644 index 5c3886c0c9..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.digitaltwin; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup10; - -import tests.integration.com.microsoft.azure.sdk.iot.digitaltwin.DigitalTwinClientComponentTests; - -@TestGroup10 -public class DigitalTwinClientComponentTestsAndroidRunner extends DigitalTwinClientComponentTests -{ - // Intentionally empty class. The important part of this file is that the class inherits tests - // from DigitalTwinClientComponentTests and is assigned to a test group. -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup1.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup1.java deleted file mode 100644 index a74ded95b3..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup1.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup1 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup10.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup10.java deleted file mode 100644 index 21324651a7..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup10.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup10 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup11.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup11.java deleted file mode 100644 index 1fb43af7c5..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup11.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup11 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup12.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup12.java deleted file mode 100644 index 80f22a7c41..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup12.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup12 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup2.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup2.java deleted file mode 100644 index 10b2069954..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup2.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup2 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup3.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup3.java deleted file mode 100644 index 5f7536edc5..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup3.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup3 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup4.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup4.java deleted file mode 100644 index eec5a84751..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup4.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup4 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup5.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup5.java deleted file mode 100644 index 176a019c2a..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup5.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup5 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup6.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup6.java deleted file mode 100644 index 77a9dfeda8..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup6.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup6 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup7.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup7.java deleted file mode 100644 index 2f76099385..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup7.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup7 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup8.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup8.java deleted file mode 100644 index 5d3ec5a5ed..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup8.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup8 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup9.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup9.java deleted file mode 100644 index afe1137073..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/helper/TestGroup9.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.helper; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface TestGroup9 -{ -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/FileUploadAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/FileUploadAndroidRunner.java deleted file mode 100644 index 5aa573b410..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/FileUploadAndroidRunner.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup10; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.FileUploadTests; - -@TestGroup10 -@RunWith(Parameterized.class) -public class FileUploadAndroidRunner extends FileUploadTests -{ - public FileUploadAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, boolean withProxy) throws Exception { - super(protocol, authenticationType, withProxy); - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/MultiplexingClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/MultiplexingClientAndroidRunner.java deleted file mode 100644 index f1ecf35ad9..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/MultiplexingClientAndroidRunner.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup6; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import org.junit.Ignore; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.FlakeyTest; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.MultiplexingClientTests; - -@TestGroup6 -@RunWith(Parameterized.class) -public class MultiplexingClientAndroidRunner extends MultiplexingClientTests -{ - public MultiplexingClientAndroidRunner(IotHubClientProtocol protocol) - { - super(protocol); - } - - // This test is a bit too heavy for android to reliably pass, even for nightly builds - @Ignore - @Override - public void sendMessagesMaxDevicesAllowed() { - - } - - // This test is a bit too heavy for android to reliably pass, but it can still be run during nightly builds - @FlakeyTest - @Override - public void multiplexedConnectionRecoversFromDeviceSessionDropsParallel() { - - } - - // This test is a bit too heavy for android to reliably pass, but it can still be run during nightly builds - @FlakeyTest - @Override - public void multiplexedConnectionRecoversFromDeviceSessionDropsSequential() { - - } - - // This test is a bit too heavy for android to reliably pass, but it can still be run during nightly builds - @FlakeyTest - @Override - public void multiplexedConnectionRecoversFromTcpConnectionDrop() { - - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/TokenRenewalAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/TokenRenewalAndroidRunner.java deleted file mode 100644 index 881ed8cb4d..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/TokenRenewalAndroidRunner.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup12; - -import tests.integration.com.microsoft.azure.sdk.iot.iothub.TokenRenewalTests; - -@TestGroup12 -public class TokenRenewalAndroidRunner extends TokenRenewalTests -{ -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/connection/ConnectionTestsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/connection/ConnectionTestsAndroidRunner.java deleted file mode 100644 index 255792674a..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/connection/ConnectionTestsAndroidRunner.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.microsoft.azure.sdk.iot.android.iothub.connection; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup11; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.connection.ConnectionTests; - -@TestGroup11 -@RunWith(Parameterized.class) -public class ConnectionTestsAndroidRunner extends ConnectionTests -{ - public ConnectionTestsAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean withProxy) throws Exception - { - super(protocol, authenticationType, clientType, withProxy); - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java deleted file mode 100644 index d99b2b205b..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.errorinjection; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup5; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.DirectMethodsErrInjTests; - -@TestGroup5 -@RunWith(Parameterized.class) -public class DirectMethodsErrInjAndroidRunner extends DirectMethodsErrInjTests -{ - public DirectMethodsErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} - diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java deleted file mode 100644 index 683fc56e39..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.errorinjection; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup3; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.ReceiveMessagesErrInjTests; - -@TestGroup3 -@RunWith(Parameterized.class) -public class ReceiveMessagesErrInjAndroidRunner extends ReceiveMessagesErrInjTests -{ - public ReceiveMessagesErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java deleted file mode 100644 index 6445c718d1..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.errorinjection; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup4; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.SendMessagesErrInjTests; - -@TestGroup4 -@RunWith(Parameterized.class) -public class SendMessagesErrInjAndroidRunner extends SendMessagesErrInjTests -{ - public SendMessagesErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/TwinErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/TwinErrInjAndroidRunner.java deleted file mode 100644 index ee24fc600a..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/errorinjection/TwinErrInjAndroidRunner.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.errorinjection; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup7; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.errorinjection.TwinErrInjTests; - -@TestGroup7 -@RunWith(Parameterized.class) -public class TwinErrInjAndroidRunner extends TwinErrInjTests -{ - public TwinErrInjAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/ReceiveMessagesAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/ReceiveMessagesAndroidRunner.java deleted file mode 100644 index dced9f3bfb..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/ReceiveMessagesAndroidRunner.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.messaging; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup8; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.telemetry.ReceiveMessagesTests; - -@TestGroup8 -@RunWith(Parameterized.class) -public class ReceiveMessagesAndroidRunner extends ReceiveMessagesTests -{ - public ReceiveMessagesAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/SendMessagesAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/SendMessagesAndroidRunner.java deleted file mode 100644 index 8b553fc856..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/messaging/SendMessagesAndroidRunner.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.messaging; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup8; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.telemetry.SendMessagesTests; - -@TestGroup8 -@RunWith(Parameterized.class) -public class SendMessagesAndroidRunner extends SendMessagesTests -{ - public SendMessagesAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/methods/DirectMethodsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/methods/DirectMethodsAndroidRunner.java deleted file mode 100644 index a6ff74aa2b..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/methods/DirectMethodsAndroidRunner.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.methods; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup9; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.methods.DirectMethodsTests; - -@TestGroup9 -@RunWith(Parameterized.class) -public class DirectMethodsAndroidRunner extends DirectMethodsTests -{ - public DirectMethodsAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/twin/TwinAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/twin/TwinAndroidRunner.java deleted file mode 100644 index 4b2c9903ec..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/iothub/twin/TwinAndroidRunner.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.iothub.twin; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup10; -import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol; -import com.microsoft.azure.sdk.iot.service.auth.AuthenticationType; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ClientType; -import tests.integration.com.microsoft.azure.sdk.iot.iothub.twin.TwinTests; - -@TestGroup10 -@RunWith(Parameterized.class) -public class TwinAndroidRunner extends TwinTests -{ - public TwinAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType) throws Exception - { - super(protocol, authenticationType, clientType); - } -} diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java deleted file mode 100644 index cc4d944809..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.provisioning; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup1; -import com.microsoft.azure.sdk.iot.provisioning.device.ProvisioningDeviceClientTransportProtocol; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.Collection; - -import tests.integration.com.microsoft.azure.sdk.iot.provisioning.ProvisioningTests; -import tests.integration.com.microsoft.azure.sdk.iot.provisioning.setup.ProvisioningCommon; - -@TestGroup1 -@RunWith(Parameterized.class) -public class ProvisioningClientSymmetricKeyAndroidRunner extends ProvisioningTests -{ - public ProvisioningClientSymmetricKeyAndroidRunner(ProvisioningDeviceClientTransportProtocol protocol, AttestationType attestationType) - { - super(protocol, attestationType); - } - - //This overrides the inputs defined in the super class. This is done to split this large test group into symmetric key and x509 runners. - @Parameterized.Parameters(name = "{0}_{1}") - public static Collection inputs() - { - return ProvisioningCommon.inputs(AttestationType.SYMMETRIC_KEY); - } -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientX509AndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientX509AndroidRunner.java deleted file mode 100644 index 85d5228fc1..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningClientX509AndroidRunner.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.provisioning; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup2; -import com.microsoft.azure.sdk.iot.provisioning.device.ProvisioningDeviceClientTransportProtocol; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.Collection; - -import tests.integration.com.microsoft.azure.sdk.iot.provisioning.ProvisioningTests; -import tests.integration.com.microsoft.azure.sdk.iot.provisioning.setup.ProvisioningCommon; - -@TestGroup2 -@RunWith(Parameterized.class) -public class ProvisioningClientX509AndroidRunner extends ProvisioningTests -{ - public ProvisioningClientX509AndroidRunner(ProvisioningDeviceClientTransportProtocol protocol, AttestationType attestationType) - { - super(protocol, attestationType); - } - - //This overrides the inputs defined in the super class. This is done to split this large test group into symmetric key and x509 runners. - @Parameterized.Parameters(name = "{0}_{1}") - public static Collection inputs() - { - return ProvisioningCommon.inputs(AttestationType.X509); //tpm tests can't be run on Android until infrastructure is setup - } -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningServiceClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningServiceClientAndroidRunner.java deleted file mode 100644 index b326774696..0000000000 --- a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/android/provisioning/ProvisioningServiceClientAndroidRunner.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Microsoft. All rights reserved. - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -package com.microsoft.azure.sdk.iot.android.provisioning; - -import com.microsoft.azure.sdk.iot.android.helper.TestGroup1; - -import tests.integration.com.microsoft.azure.sdk.iot.provisioning.ProvisioningServiceClientTests; - -@TestGroup1 -public class ProvisioningServiceClientAndroidRunner extends ProvisioningServiceClientTests -{ - // Intentionally empty class. The important part of this file is that the class inherits tests - // from ProvisioningServiceClientTests and is assigned to a test group. -} \ No newline at end of file diff --git a/iot-e2e-tests/android/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index c502335841..0000000000 --- a/iot-e2e-tests/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android/build.gradle b/iot-e2e-tests/android/build.gradle deleted file mode 100644 index 685f19721b..0000000000 --- a/iot-e2e-tests/android/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - mavenLocal() - google() - mavenCentral() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} \ No newline at end of file diff --git a/iot-e2e-tests/android/gradle.properties b/iot-e2e-tests/android/gradle.properties deleted file mode 100644 index 89e0d99e21..0000000000 --- a/iot-e2e-tests/android/gradle.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true diff --git a/iot-e2e-tests/android/gradle/wrapper/gradle-wrapper.properties b/iot-e2e-tests/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/iot-e2e-tests/android/renew_env.cmd b/iot-e2e-tests/android/renew_env.cmd deleted file mode 100644 index 7d4a7ca585..0000000000 --- a/iot-e2e-tests/android/renew_env.cmd +++ /dev/null @@ -1,12 +0,0 @@ -@echo off -echo. -echo Refreshing ANDROID_DEVICE_NAME from registry - -:: Get User ANDROID_DEVICE_NAME -for /f "tokens=3*" %%A in ('reg query "HKCU\Environment" /v ANDROID_DEVICE_NAME') do set userANDROID_DEVICE_NAME=%%A%%B - -:: Set Refreshed ANDROID_DEVICE_NAME -set ANDROID_DEVICE_NAME=%userANDROID_DEVICE_NAME% - -echo Refreshed ANDROID_DEVICE_NAME -echo %ANDROID_DEVICE_NAME% \ No newline at end of file diff --git a/iot-e2e-tests/android/runInstrumentationTests.py b/iot-e2e-tests/android/runInstrumentationTests.py deleted file mode 100644 index 3320186fa2..0000000000 --- a/iot-e2e-tests/android/runInstrumentationTests.py +++ /dev/null @@ -1,20 +0,0 @@ -import subprocess -import os -import time -import sys - -env=dict(os.environ, PATH="path") -cmd = "adb -s "+sys.argv[1]+" shell am instrument -w -r -e debug false -e package 'com.microsoft.azure.sdk.iot.androidthings' com.microsoft.azure.sdk.iot.androidthings.test/android.support.test.runner.AndroidJUnitRunner" -print(cmd) -p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8') -(out, err) = p.communicate() -print(out) -print(err) -os.popen("taskkill /IM cmd.exe /FI \"WINDOWTITLE eq C:\windows\system32\cmd.exe - emulator*\"") -os.popen("setx ANDROID_DEVICE_NAME \"\"").read() -if "Failures:" in out or len(err)>0: - sys.exit(-1) - print("exit-1") -else: - sys.exit(0) - print("exit-0") \ No newline at end of file diff --git a/iot-e2e-tests/android/runTestsOnThings.cmd b/iot-e2e-tests/android/runTestsOnThings.cmd deleted file mode 100644 index 59b4aaacbf..0000000000 --- a/iot-e2e-tests/android/runTestsOnThings.cmd +++ /dev/null @@ -1,16 +0,0 @@ -@REM Copyright (c) Microsoft. All rights reserved. -@REM Licensed under the MIT license. See LICENSE file in the project root for full license information. - -@REM -- Select Android Device -- -python AndroidDeviceSelect.py -@REM -- set device variable -- -call renew_env.cmd -ECHO We're working with "%ANDROID_DEVICE_NAME%" -@REM -- installing device and test apk-- -ECHO installing apk on device -call adb -s %ANDROID_DEVICE_NAME% install -r -t "things\build\outputs\apk\debug\things-debug.apk" -ECHO installing test apk on device -call adb -s %ANDROID_DEVICE_NAME% install -r -t "things\build\outputs\apk\androidTest\debug\things-debug-androidTest.apk" -@REM -- Starting Android Tests -- -ECHO starting android tests -python runInstrumentationTests.py %ANDROID_DEVICE_NAME% diff --git a/iot-e2e-tests/android/settings.gradle b/iot-e2e-tests/android/settings.gradle deleted file mode 100644 index 9d495b34f8..0000000000 --- a/iot-e2e-tests/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' \ No newline at end of file From 307139ca6ad916c02c3384976176359bb995a94a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 11:32:01 -0800 Subject: [PATCH 097/114] latest azure core fixes it? --- iot-e2e-tests/common/pom.xml | 11 ++++------- .../iot/digitaltwin/DigitalTwinClientTests.java | 9 +++++++-- .../azure/sdk/iot/iothub/FileUploadTests.java | 9 +++++++-- .../sdk/iot/iothub/MultiplexingClientTests.java | 3 ++- .../azure/sdk/iot/iothub/TokenRenewalTests.java | 3 ++- .../iot/iothub/connection/ConnectionTests.java | 10 ++++++---- iot-e2e-tests/pom.xml | 9 --------- pom.xml | 17 +++++++++++------ 8 files changed, 39 insertions(+), 32 deletions(-) diff --git a/iot-e2e-tests/common/pom.xml b/iot-e2e-tests/common/pom.xml index 1a9d57fce0..7201cc2ed6 100644 --- a/iot-e2e-tests/common/pom.xml +++ b/iot-e2e-tests/common/pom.xml @@ -106,14 +106,11 @@ io.netty netty-all - - com.azure - azure-storage-blob - 12.8.0 + com.github.monkeywie + proxyee + 1.7.6 + compile + + io.netty + netty-buffer + 4.2.9.Final + io.netty netty-all @@ -115,6 +120,11 @@ netty-handler 4.2.9.Final + + io.netty + netty-handler-proxy + 4.2.9.Final + io.netty netty-codec @@ -130,11 +140,6 @@ netty-codec-http2 4.2.9.Final - - io.projectreactor.netty - reactor-netty-http - 1.0.39 - commons-cli commons-cli From 66316040d07aa2fa5c3538573b4c87980fb7412a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 11:35:39 -0800 Subject: [PATCH 098/114] re-enable linux + win --- vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 256077d9cf..f869e2c49c 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -44,7 +44,6 @@ jobs: ### Windows ### - job: Windows timeoutInMinutes: 180 - condition: false dependsOn: DeployCloudTestResources variables: IOTHUB_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.IOTHUB_CONNECTION_STRING'] ] @@ -151,7 +150,6 @@ jobs: DPS_IDSCOPE: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.DPS_IDSCOPE'] ] PROVISIONING_CONNECTION_STRING: $[ dependencies.DeployCloudTestResources.outputs['deployCloudTestResources.PROVISIONING_CONNECTION_STRING'] ] timeoutInMinutes: 180 - condition: false pool: # If this is changed, don't forget to update supported_platforms.md in the root directory. That document outlines what OS we test on and should stay up to date. vmImage: ubuntu-latest From 45d9afbecc12e8ce1e652ba6e9f1ccc83b95e863 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 11:37:26 -0800 Subject: [PATCH 099/114] android2 to android --- .../{android2 => android}/.gitignore | 0 .../{android2 => android}/app/.gitignore | 0 .../{android2 => android}/app/build.gradle | 0 .../app/proguard-rules.pro | 0 .../iothub/FileUploadAndroidRunner.java | 0 .../MultiplexingClientAndroidRunner.java | 0 .../iothub/TokenRenewalAndroidRunner.java | 0 .../ConnectionTestsAndroidRunner.java | 0 .../DigitalTwinClientAndroidRunner.java | 0 ...TwinClientComponentTestsAndroidRunner.java | 0 .../DirectMethodsErrInjAndroidRunner.java | 0 .../ReceiveMessagesErrInjAndroidRunner.java | 0 .../SendMessagesErrInjAndroidRunner.java | 0 .../TwinErrInjAndroidRunner.java | 0 .../ReceiveMessagesAndroidRunner.java | 0 .../messaging/SendMessagesAndroidRunner.java | 0 .../methods/DirectMethodsAndroidRunner.java | 0 .../iothub/twin/TwinAndroidRunner.java | 0 ...ioningClientSymmetricKeyAndroidRunner.java | 0 .../ProvisioningClientX509AndroidRunner.java | 0 ...rovisioningServiceClientAndroidRunner.java | 0 .../iot/androidtest/testgroup/TestGroup1.java | 0 .../androidtest/testgroup/TestGroup10.java | 0 .../androidtest/testgroup/TestGroup11.java | 0 .../androidtest/testgroup/TestGroup12.java | 0 .../iot/androidtest/testgroup/TestGroup2.java | 0 .../iot/androidtest/testgroup/TestGroup3.java | 0 .../iot/androidtest/testgroup/TestGroup4.java | 0 .../iot/androidtest/testgroup/TestGroup5.java | 0 .../iot/androidtest/testgroup/TestGroup6.java | 0 .../iot/androidtest/testgroup/TestGroup7.java | 0 .../iot/androidtest/testgroup/TestGroup8.java | 0 .../iot/androidtest/testgroup/TestGroup9.java | 0 .../app/src/main/AndroidManifest.xml | 0 .../{android2 => android}/build.gradle | 0 .../{android2 => android}/settings.gradle | 0 iot-e2e-tests/android2/.idea/.gitignore | 3 --- iot-e2e-tests/android2/.idea/.name | 1 - .../android2/.idea/AndroidProjectSystem.xml | 6 ------ iot-e2e-tests/android2/.idea/compiler.xml | 6 ------ .../.idea/deploymentTargetSelector.xml | 10 --------- iot-e2e-tests/android2/.idea/gradle.xml | 18 ---------------- iot-e2e-tests/android2/.idea/migrations.xml | 10 --------- iot-e2e-tests/android2/.idea/misc.xml | 10 --------- .../android2/.idea/runConfigurations.xml | 17 --------------- iot-e2e-tests/android2/.idea/vcs.xml | 6 ------ iot-e2e-tests/android2/gradle.properties | 21 ------------------- .../android2/gradle/libs.versions.toml | 20 ------------------ vsts/RunTestsOnEmulator.sh | 8 +++---- vsts/gradle_build.ps1 | 2 +- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 6 +++--- 51 files changed, 8 insertions(+), 136 deletions(-) rename iot-e2e-tests/{android2 => android}/.gitignore (100%) rename iot-e2e-tests/{android2 => android}/app/.gitignore (100%) rename iot-e2e-tests/{android2 => android}/app/build.gradle (100%) rename iot-e2e-tests/{android2 => android}/app/proguard-rules.pro (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/main/AndroidManifest.xml (100%) rename iot-e2e-tests/{android2 => android}/build.gradle (100%) rename iot-e2e-tests/{android2 => android}/settings.gradle (100%) delete mode 100644 iot-e2e-tests/android2/.idea/.gitignore delete mode 100644 iot-e2e-tests/android2/.idea/.name delete mode 100644 iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml delete mode 100644 iot-e2e-tests/android2/.idea/compiler.xml delete mode 100644 iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml delete mode 100644 iot-e2e-tests/android2/.idea/gradle.xml delete mode 100644 iot-e2e-tests/android2/.idea/migrations.xml delete mode 100644 iot-e2e-tests/android2/.idea/misc.xml delete mode 100644 iot-e2e-tests/android2/.idea/runConfigurations.xml delete mode 100644 iot-e2e-tests/android2/.idea/vcs.xml delete mode 100644 iot-e2e-tests/android2/gradle.properties delete mode 100644 iot-e2e-tests/android2/gradle/libs.versions.toml diff --git a/iot-e2e-tests/android2/.gitignore b/iot-e2e-tests/android/.gitignore similarity index 100% rename from iot-e2e-tests/android2/.gitignore rename to iot-e2e-tests/android/.gitignore diff --git a/iot-e2e-tests/android2/app/.gitignore b/iot-e2e-tests/android/app/.gitignore similarity index 100% rename from iot-e2e-tests/android2/app/.gitignore rename to iot-e2e-tests/android/app/.gitignore diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android/app/build.gradle similarity index 100% rename from iot-e2e-tests/android2/app/build.gradle rename to iot-e2e-tests/android/app/build.gradle diff --git a/iot-e2e-tests/android2/app/proguard-rules.pro b/iot-e2e-tests/android/app/proguard-rules.pro similarity index 100% rename from iot-e2e-tests/android2/app/proguard-rules.pro rename to iot-e2e-tests/android/app/proguard-rules.pro diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android/app/src/main/AndroidManifest.xml similarity index 100% rename from iot-e2e-tests/android2/app/src/main/AndroidManifest.xml rename to iot-e2e-tests/android/app/src/main/AndroidManifest.xml diff --git a/iot-e2e-tests/android2/build.gradle b/iot-e2e-tests/android/build.gradle similarity index 100% rename from iot-e2e-tests/android2/build.gradle rename to iot-e2e-tests/android/build.gradle diff --git a/iot-e2e-tests/android2/settings.gradle b/iot-e2e-tests/android/settings.gradle similarity index 100% rename from iot-e2e-tests/android2/settings.gradle rename to iot-e2e-tests/android/settings.gradle diff --git a/iot-e2e-tests/android2/.idea/.gitignore b/iot-e2e-tests/android2/.idea/.gitignore deleted file mode 100644 index 26d33521af..0000000000 --- a/iot-e2e-tests/android2/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/iot-e2e-tests/android2/.idea/.name b/iot-e2e-tests/android2/.idea/.name deleted file mode 100644 index b3405b3b32..0000000000 --- a/iot-e2e-tests/android2/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -My Application \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml b/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml deleted file mode 100644 index 4a53bee8cb..0000000000 --- a/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/compiler.xml b/iot-e2e-tests/android2/.idea/compiler.xml deleted file mode 100644 index b86273d942..0000000000 --- a/iot-e2e-tests/android2/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml b/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml deleted file mode 100644 index b268ef36cd..0000000000 --- a/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/gradle.xml b/iot-e2e-tests/android2/.idea/gradle.xml deleted file mode 100644 index 97f0a8e140..0000000000 --- a/iot-e2e-tests/android2/.idea/gradle.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/migrations.xml b/iot-e2e-tests/android2/.idea/migrations.xml deleted file mode 100644 index f8051a6f97..0000000000 --- a/iot-e2e-tests/android2/.idea/migrations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/misc.xml b/iot-e2e-tests/android2/.idea/misc.xml deleted file mode 100644 index 74dd639e4e..0000000000 --- a/iot-e2e-tests/android2/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/runConfigurations.xml b/iot-e2e-tests/android2/.idea/runConfigurations.xml deleted file mode 100644 index 16660f1d80..0000000000 --- a/iot-e2e-tests/android2/.idea/runConfigurations.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/vcs.xml b/iot-e2e-tests/android2/.idea/vcs.xml deleted file mode 100644 index b2bdec2d71..0000000000 --- a/iot-e2e-tests/android2/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/gradle.properties b/iot-e2e-tests/android2/gradle.properties deleted file mode 100644 index 4387edc225..0000000000 --- a/iot-e2e-tests/android2/gradle.properties +++ /dev/null @@ -1,21 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. For more details, visit -# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true \ No newline at end of file diff --git a/iot-e2e-tests/android2/gradle/libs.versions.toml b/iot-e2e-tests/android2/gradle/libs.versions.toml deleted file mode 100644 index dcd4625cf4..0000000000 --- a/iot-e2e-tests/android2/gradle/libs.versions.toml +++ /dev/null @@ -1,20 +0,0 @@ -[versions] -agp = "8.13.2" -junit = "4.13.2" -junitVersion = "1.1.5" -espressoCore = "3.5.1" -appcompat = "1.6.1" -material = "1.10.0" -runner = "1.7.0" - -[libraries] -junit = { group = "junit", name = "junit", version.ref = "junit" } -ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } -espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } -appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } -material = { group = "com.google.android.material", name = "material", version.ref = "material" } -runner = { module = "androidx.test:runner", version.ref = "runner" } - -[plugins] -android-application = { id = "com.android.application", version.ref = "agp" } - diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index 4ef5215a85..5c91d5a357 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -2,20 +2,20 @@ # This APK file is generated by the Android build task and then is copied into the android test run task. If the APK file # is missing, then either the copy failed, or the APK was never successfully built. -if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk" ]; then +if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi -if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then +if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi # -e flag to force this command to run on what should be the only emulator active on this machine echo 'Installing APKs on emulator' -adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk -adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk +adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk +adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk #List instrumentation classes, for logging purposes only echo 'Listing available instrumentations:' diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index 4b0f63e7ab..dd8095b52c 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -1,5 +1,5 @@ # This script assumes it is being run from the root of the repository -cd iot-e2e-tests\android2 +cd iot-e2e-tests\android # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index f869e2c49c..9c34bd2b45 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -276,7 +276,7 @@ jobs: - task: CopyFiles@2 displayName: 'Copy Test Results to Artifact Staging Directory' inputs: - SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk' + SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk' Contents: | *.* TargetFolder: '$(Build.ArtifactStagingDirectory)' @@ -287,7 +287,7 @@ jobs: displayName: 'Publish APKs to test in next job' inputs: artifactName: 'androidBuildFiles' - targetPath: 'iot-e2e-tests/android2/app/build/outputs/apk' + targetPath: 'iot-e2e-tests/android/app/build/outputs/apk' - task: ComponentGovernanceComponentDetection@0 displayName: Component Governance Detection @@ -348,7 +348,7 @@ jobs: #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') inputs: artifactName: 'androidBuildFiles' - targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk + targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk - task: Bash@3 #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') From 8c99b7a62f8ef3c64c657991c69353706432acca Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 12:11:36 -0800 Subject: [PATCH 100/114] bah --- .../iot/helpers/BasicProxyAuthenticator.java | 55 +++++++++++++++++++ .../iot/iothub/MultiplexingClientTests.java | 18 +----- .../sdk/iot/iothub/TokenRenewalTests.java | 10 +--- .../iothub/connection/ConnectionTests.java | 21 +++---- pom.xml | 2 +- 5 files changed, 70 insertions(+), 36 deletions(-) create mode 100644 iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java new file mode 100644 index 0000000000..7d188c692f --- /dev/null +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java @@ -0,0 +1,55 @@ +package tests.integration.com.microsoft.azure.sdk.iot.helpers; + +import com.github.monkeywie.proxyee.server.auth.HttpProxyAuthenticationProvider; +import com.github.monkeywie.proxyee.server.auth.model.BasicHttpToken; + +import java.util.Base64; + +public class BasicProxyAuthenticator implements HttpProxyAuthenticationProvider +{ + public static final String AUTH_TYPE_BASIC = "BASIC"; + public static final String AUTH_REALM_BASIC = "Access to the staging site"; + + public String expectedUsername; + public String expectedPassword; + + public BasicProxyAuthenticator(String expectedUsername, String expectedPassword) + { + this.expectedUsername = expectedUsername; + this.expectedPassword = expectedPassword; + } + + + public String authType() { + return AUTH_TYPE_BASIC; + } + + public String authRealm() { + return AUTH_REALM_BASIC; + } + + protected BasicHttpToken authenticate(String usr, String pwd) + { + if (this.expectedUsername.equals(usr) && this.expectedPassword.equals(pwd)) { + return new BasicHttpToken(usr, pwd); + } + return null; + } + + public BasicHttpToken authenticate(String authorization) { + String usr = ""; + String pwd = ""; + if (authorization != null && authorization.length() > 0) { + String token = authorization.substring(AUTH_TYPE_BASIC.length() + 1); + String decode = new String(Base64.getDecoder().decode(token)); + String[] arr = decode.split(":"); + if (arr.length >= 1) { + usr = arr[0]; + } + if (arr.length >= 2) { + pwd = arr[1]; + } + } + return authenticate(usr, pwd); + } +} \ No newline at end of file diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java index b9c763bcd6..8ac63243ae 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java @@ -54,13 +54,7 @@ import org.junit.rules.Timeout; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.ErrorInjectionHelper; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.EventCallback; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.IntegrationTest; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.Success; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.TestConstants; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.TestDeviceIdentity; -import tests.integration.com.microsoft.azure.sdk.iot.helpers.Tools; +import tests.integration.com.microsoft.azure.sdk.iot.helpers.*; import tests.integration.com.microsoft.azure.sdk.iot.helpers.annotations.*; import tests.integration.com.microsoft.azure.sdk.iot.helpers.rules.RerunFailedTestRule; import tests.integration.com.microsoft.azure.sdk.iot.helpers.rules.ThrottleResistantTestRule; @@ -218,15 +212,7 @@ public void tearDownTest() public static void startProxy() { HttpProxyServerConfig config = new HttpProxyServerConfig(); - config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() { - @Override - protected BasicHttpToken authenticate(String usr, String pwd) { - if (testProxyUser.equals(usr) && testProxyPass.equals(pwd)) { - return new BasicHttpToken(usr, pwd); - } - return null; - } - }); + config.setAuthenticationProvider(new BasicProxyAuthenticator(testProxyUser, testProxyPass)); config.setHandleSsl(false); proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.startAsync(testProxyPort); diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java index cdeba8cecb..fc5cae91d1 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java @@ -94,15 +94,7 @@ public static void setUp() public static void startProxy() { HttpProxyServerConfig config = new HttpProxyServerConfig(); - config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() { - @Override - protected BasicHttpToken authenticate(String usr, String pwd) { - if (testProxyUser.equals(usr) && testProxyPass.equals(pwd)) { - return new BasicHttpToken(usr, pwd); - } - return null; - } - }); + config.setAuthenticationProvider(new BasicProxyAuthenticator(testProxyUser, testProxyPass)); config.setHandleSsl(false); proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.startAsync(testProxyPort); diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index c8ad578374..8162495571 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -106,7 +106,16 @@ public void setup() throws Exception if (this.useHttpProxy) { Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); + // TODO AMQP_WS proxy authentication doesn't work against our automated test proxy library. It does work against other proxies though, so it is probably a bug in the test proxy + // Just testing the proxy support w/o proxy user + pass for now + if (this.protocol == AMQPS_WS) + { + optionsBuilder.proxySettings(new ProxySettings(testProxy)); + } + else + { + optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); + } } if (clientType == ClientType.DEVICE_CLIENT) @@ -188,15 +197,7 @@ public void dispose() public static void startProxy() { HttpProxyServerConfig config = new HttpProxyServerConfig(); - config.setAuthenticationProvider(new BasicHttpProxyAuthenticationProvider() { - @Override - protected BasicHttpToken authenticate(String usr, String pwd) { - if (testProxyUser.equals(usr) && testProxyPass.equals(pwd)) { - return new BasicHttpToken(usr, pwd); - } - return null; - } - }); + config.setAuthenticationProvider(new BasicProxyAuthenticator(testProxyUser, testProxyPass)); config.setHandleSsl(false); proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.startAsync(testProxyPort); diff --git a/pom.xml b/pom.xml index fce9dc02fb..85bb2362f5 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ com.microsoft.azure qpid-proton-j-extensions - 1.2.4 + 1.2.7 org.apache.commons From a36b41178c92c7b86adaac0a2a246c0882143655 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 12:21:19 -0800 Subject: [PATCH 101/114] proxy auth vs no auth --- .../iot/iothub/MultiplexingClientTests.java | 9 +- .../sdk/iot/iothub/TokenRenewalTests.java | 9 +- .../iothub/connection/ConnectionTests.java | 104 +++++++++++------- 3 files changed, 69 insertions(+), 53 deletions(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java index 8ac63243ae..d9889107e9 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/MultiplexingClientTests.java @@ -110,12 +110,6 @@ public class MultiplexingClientTests extends IntegrationTest protected static String testProxyHostname = "127.0.0.1"; protected static int testProxyPort = 8849; - // Semmle flags this as a security issue, but this is a test username so the warning can be suppressed - protected static final String testProxyUser = "proxyUsername"; // lgtm - - // Semmle flags this as a security issue, but this is a test password so the warning can be suppressed - protected static final String testProxyPass = "1234"; // lgtm - @Parameterized.Parameters(name = "{0}") public static Collection inputs() throws Exception { @@ -212,7 +206,6 @@ public void tearDownTest() public static void startProxy() { HttpProxyServerConfig config = new HttpProxyServerConfig(); - config.setAuthenticationProvider(new BasicProxyAuthenticator(testProxyUser, testProxyPass)); config.setHandleSsl(false); proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.startAsync(testProxyPort); @@ -471,7 +464,7 @@ public void sendMessagesWithProxy() throws Exception assumeTrue(testInstance.protocol == IotHubClientProtocol.AMQPS_WS); Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - ProxySettings proxySettings = new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray()); + ProxySettings proxySettings = new ProxySettings(testProxy); //re-setup test instance to use proxy instead testInstance.setup(DEVICE_MULTIPLEX_COUNT, MultiplexingClientOptions.builder().proxySettings(proxySettings).build(), false); diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java index fc5cae91d1..289ad24b22 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/TokenRenewalTests.java @@ -55,12 +55,6 @@ public class TokenRenewalTests extends IntegrationTest protected static String testProxyHostname = "127.0.0.1"; protected static int testProxyPort = 8898; - // Semmle flags this as a security issue, but this is a test username so the warning can be suppressed - protected static final String testProxyUser = "proxyUsername"; // lgtm - - // Semmle flags this as a security issue, but this is a test password so the warning can be suppressed - protected static final String testProxyPass = "1234"; // lgtm - final int SECONDS_FOR_SAS_TOKEN_TO_LIVE_BEFORE_RENEWAL = 30; final long EXPIRED_SAS_TOKEN_GRACE_PERIOD_SECONDS = 600; //service extends 10 minute grace period after a token has expired @@ -94,7 +88,6 @@ public static void setUp() public static void startProxy() { HttpProxyServerConfig config = new HttpProxyServerConfig(); - config.setAuthenticationProvider(new BasicProxyAuthenticator(testProxyUser, testProxyPass)); config.setHandleSsl(false); proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.startAsync(testProxyPort); @@ -237,7 +230,7 @@ private List createClientsToTest() throws IotHubException, IOExc clients.add(createDeviceClient(protocol, null)); if (protocol == HTTPS || protocol == MQTT_WS || protocol == AMQPS_WS) { - ProxySettings proxySettings = new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray()); + ProxySettings proxySettings = new ProxySettings(testProxy); InternalClient client = createDeviceClient(protocol, proxySettings); clients.add(client); } diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index 8162495571..7a5cbdb045 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -49,39 +49,47 @@ public static Collection inputs() throws Exception return Arrays.asList( new Object[][] { - {HTTPS, SAS, ClientType.DEVICE_CLIENT, false}, - {AMQPS, SAS, ClientType.DEVICE_CLIENT, false}, - {AMQPS_WS, SAS, ClientType.DEVICE_CLIENT, false}, - {MQTT, SAS, ClientType.DEVICE_CLIENT, false}, - {MQTT_WS, SAS, ClientType.DEVICE_CLIENT, false}, - - {HTTPS, SELF_SIGNED, ClientType.DEVICE_CLIENT, false}, - {AMQPS, SELF_SIGNED, ClientType.DEVICE_CLIENT, false}, - {MQTT, SELF_SIGNED, ClientType.DEVICE_CLIENT, false}, - {MQTT_WS, SELF_SIGNED, ClientType.DEVICE_CLIENT, false}, - - {AMQPS, SAS, ClientType.MODULE_CLIENT, false}, - {AMQPS_WS, SAS, ClientType.MODULE_CLIENT, false}, - {MQTT, SAS, ClientType.MODULE_CLIENT, false}, - {MQTT_WS, SAS, ClientType.MODULE_CLIENT, false}, - - {AMQPS, SELF_SIGNED, ClientType.MODULE_CLIENT, false}, - {MQTT, SELF_SIGNED, ClientType.MODULE_CLIENT, false}, - {MQTT_WS, SELF_SIGNED, ClientType.MODULE_CLIENT, false}, - - {HTTPS, SAS, ClientType.DEVICE_CLIENT, true}, - {AMQPS_WS, SAS, ClientType.DEVICE_CLIENT, true}, - {MQTT_WS, SAS, ClientType.DEVICE_CLIENT, true}, - {MQTT_WS, SELF_SIGNED, ClientType.DEVICE_CLIENT, true}, - {AMQPS_WS, SAS, ClientType.MODULE_CLIENT, true}, - {MQTT_WS, SAS, ClientType.MODULE_CLIENT, true}, - {MQTT_WS, SELF_SIGNED, ClientType.MODULE_CLIENT, true}, + {HTTPS, SAS, ClientType.DEVICE_CLIENT, false, false}, + {AMQPS, SAS, ClientType.DEVICE_CLIENT, false, false}, + {AMQPS_WS, SAS, ClientType.DEVICE_CLIENT, false, false}, + {MQTT, SAS, ClientType.DEVICE_CLIENT, false, false}, + {MQTT_WS, SAS, ClientType.DEVICE_CLIENT, false, false}, + + {HTTPS, SELF_SIGNED, ClientType.DEVICE_CLIENT, false, false}, + {AMQPS, SELF_SIGNED, ClientType.DEVICE_CLIENT, false, false}, + {MQTT, SELF_SIGNED, ClientType.DEVICE_CLIENT, false, false}, + {MQTT_WS, SELF_SIGNED, ClientType.DEVICE_CLIENT, false, false}, + + {AMQPS, SAS, ClientType.MODULE_CLIENT, false, false}, + {AMQPS_WS, SAS, ClientType.MODULE_CLIENT, false, false}, + {MQTT, SAS, ClientType.MODULE_CLIENT, false, false}, + {MQTT_WS, SAS, ClientType.MODULE_CLIENT, false, false}, + + {AMQPS, SELF_SIGNED, ClientType.MODULE_CLIENT, false, false}, + {MQTT, SELF_SIGNED, ClientType.MODULE_CLIENT, false, false}, + {MQTT_WS, SELF_SIGNED, ClientType.MODULE_CLIENT, false, false}, + + {HTTPS, SAS, ClientType.DEVICE_CLIENT, true, false}, + {AMQPS_WS, SAS, ClientType.DEVICE_CLIENT, true, false}, + {MQTT_WS, SAS, ClientType.DEVICE_CLIENT, true, false}, + {MQTT_WS, SELF_SIGNED, ClientType.DEVICE_CLIENT, true, false}, + {AMQPS_WS, SAS, ClientType.MODULE_CLIENT, true, false}, + {MQTT_WS, SAS, ClientType.MODULE_CLIENT, true, false}, + {MQTT_WS, SELF_SIGNED, ClientType.MODULE_CLIENT, true, false}, + + // TODO AMQP_WS with proxy with auth doesn't work against our test proxy. It does work against + // other proxies, so this is likely just a bug in our current test proxy + {HTTPS, SAS, ClientType.DEVICE_CLIENT, true, true}, + {MQTT_WS, SAS, ClientType.DEVICE_CLIENT, true, true}, + {MQTT_WS, SELF_SIGNED, ClientType.DEVICE_CLIENT, true, true}, + {MQTT_WS, SAS, ClientType.MODULE_CLIENT, true, true}, + {MQTT_WS, SELF_SIGNED, ClientType.MODULE_CLIENT, true, true}, }); } - public ConnectionTests(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean withProxy) + public ConnectionTests(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean withProxy, boolean withProxyAuth) { - this.testInstance = new ConnectionTestInstance(protocol, authenticationType, clientType, withProxy); + this.testInstance = new ConnectionTestInstance(protocol, authenticationType, clientType, withProxy, withProxyAuth); } public class ConnectionTestInstance @@ -91,13 +99,15 @@ public class ConnectionTestInstance public AuthenticationType authenticationType; public ClientType clientType; public boolean useHttpProxy; + public boolean useHttpProxyAuth; - public ConnectionTestInstance(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean useHttpProxy) + public ConnectionTestInstance(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean useHttpProxy, boolean useHttpProxyAuth) { this.protocol = protocol; this.authenticationType = authenticationType; this.clientType = clientType; this.useHttpProxy = useHttpProxy; + this.useHttpProxyAuth = useHttpProxyAuth; } public void setup() throws Exception @@ -106,15 +116,13 @@ public void setup() throws Exception if (this.useHttpProxy) { Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - // TODO AMQP_WS proxy authentication doesn't work against our automated test proxy library. It does work against other proxies though, so it is probably a bug in the test proxy - // Just testing the proxy support w/o proxy user + pass for now - if (this.protocol == AMQPS_WS) + if (this.useHttpProxyAuth) { - optionsBuilder.proxySettings(new ProxySettings(testProxy)); + optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); } else { - optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); + optionsBuilder.proxySettings(new ProxySettings(testProxy)); } } @@ -187,6 +195,10 @@ public void dispose() protected static String testProxyHostname = "127.0.0.1"; protected static int testProxyPort = 8899; + protected static HttpProxyServer proxyServerWithoutAuth; + protected static String testProxyHostnameWithoutAuth = "127.0.0.1"; + protected static int testProxyPortWithoutAuth = 9000; + // Semmle flags this as a security issue, but this is a test username so the warning can be suppressed protected static final String testProxyUser = "proxyUsername"; // lgtm @@ -201,6 +213,11 @@ public static void startProxy() config.setHandleSsl(false); proxyServer = new HttpProxyServer().serverConfig(config); proxyServer.startAsync(testProxyPort); + + HttpProxyServerConfig configWithoutAuth = new HttpProxyServerConfig(); + config.setHandleSsl(false); + proxyServerWithoutAuth = new HttpProxyServer().serverConfig(configWithoutAuth); + proxyServerWithoutAuth.startAsync(testProxyPortWithoutAuth); } @AfterClass @@ -210,6 +227,11 @@ public static void stopProxy() { proxyServer.close(); } + + if (proxyServerWithoutAuth != null) + { + proxyServerWithoutAuth.close(); + } } @Test(timeout = 60000) // 1 minute @@ -268,8 +290,16 @@ public void CanOpenMultiplexingConnection() throws Exception MultiplexingClientOptions.MultiplexingClientOptionsBuilder optionsBuilder = MultiplexingClientOptions.builder(); if (testInstance.useHttpProxy) { - Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); - optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); + if (testInstance.useHttpProxyAuth) + { + Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); + optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); + } + else + { + Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostnameWithoutAuth, testProxyPortWithoutAuth)); + optionsBuilder.proxySettings(new ProxySettings(testProxy)); + } } MultiplexingClient multiplexingClient = new MultiplexingClient(hostName, testInstance.protocol, optionsBuilder.build()); From 1d06a69449189b79cae1cde344d3173f81d50c9a Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 13:22:28 -0800 Subject: [PATCH 102/114] 4 --- .../azure/sdk/iot/iothub/connection/ConnectionTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index 7a5cbdb045..741866472a 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -40,7 +40,7 @@ public class ConnectionTests extends IntegrationTest private static String iotHubConnectionString; private static String hostName; - @Parameterized.Parameters(name = "{0}_{1}_{2}_{3}") + @Parameterized.Parameters(name = "{0}_{1}_{2}_{3}_{4}") public static Collection inputs() throws Exception { iotHubConnectionString = Tools.retrieveEnvironmentVariableValue(TestConstants.IOT_HUB_CONNECTION_STRING_ENV_VAR_NAME); From 3da9edb7ef1793dc79db2e916cb8689768cbffa2 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 13:24:41 -0800 Subject: [PATCH 103/114] asdf --- .../azure/sdk/iot/iothub/connection/ConnectionTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index 741866472a..24de0dcd99 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -115,13 +115,14 @@ public void setup() throws Exception ClientOptions.ClientOptionsBuilder optionsBuilder = ClientOptions.builder(); if (this.useHttpProxy) { - Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); if (this.useHttpProxyAuth) { + Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostname, testProxyPort)); optionsBuilder.proxySettings(new ProxySettings(testProxy, testProxyUser, testProxyPass.toCharArray())); } else { + Proxy testProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(testProxyHostnameWithoutAuth, testProxyPortWithoutAuth)); optionsBuilder.proxySettings(new ProxySettings(testProxy)); } } From af48f549f93f92784daeb64718681ffb13a08218 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 13:40:18 -0800 Subject: [PATCH 104/114] Revert "android2 to android" This reverts commit 45d9afbecc12e8ce1e652ba6e9f1ccc83b95e863. --- .../{android => android2}/.gitignore | 0 iot-e2e-tests/android2/.idea/.gitignore | 3 +++ iot-e2e-tests/android2/.idea/.name | 1 + .../android2/.idea/AndroidProjectSystem.xml | 6 ++++++ iot-e2e-tests/android2/.idea/compiler.xml | 6 ++++++ .../.idea/deploymentTargetSelector.xml | 10 +++++++++ iot-e2e-tests/android2/.idea/gradle.xml | 18 ++++++++++++++++ iot-e2e-tests/android2/.idea/migrations.xml | 10 +++++++++ iot-e2e-tests/android2/.idea/misc.xml | 10 +++++++++ .../android2/.idea/runConfigurations.xml | 17 +++++++++++++++ iot-e2e-tests/android2/.idea/vcs.xml | 6 ++++++ .../{android => android2}/app/.gitignore | 0 .../{android => android2}/app/build.gradle | 0 .../app/proguard-rules.pro | 0 .../iothub/FileUploadAndroidRunner.java | 0 .../MultiplexingClientAndroidRunner.java | 0 .../iothub/TokenRenewalAndroidRunner.java | 0 .../ConnectionTestsAndroidRunner.java | 0 .../DigitalTwinClientAndroidRunner.java | 0 ...TwinClientComponentTestsAndroidRunner.java | 0 .../DirectMethodsErrInjAndroidRunner.java | 0 .../ReceiveMessagesErrInjAndroidRunner.java | 0 .../SendMessagesErrInjAndroidRunner.java | 0 .../TwinErrInjAndroidRunner.java | 0 .../ReceiveMessagesAndroidRunner.java | 0 .../messaging/SendMessagesAndroidRunner.java | 0 .../methods/DirectMethodsAndroidRunner.java | 0 .../iothub/twin/TwinAndroidRunner.java | 0 ...ioningClientSymmetricKeyAndroidRunner.java | 0 .../ProvisioningClientX509AndroidRunner.java | 0 ...rovisioningServiceClientAndroidRunner.java | 0 .../iot/androidtest/testgroup/TestGroup1.java | 0 .../androidtest/testgroup/TestGroup10.java | 0 .../androidtest/testgroup/TestGroup11.java | 0 .../androidtest/testgroup/TestGroup12.java | 0 .../iot/androidtest/testgroup/TestGroup2.java | 0 .../iot/androidtest/testgroup/TestGroup3.java | 0 .../iot/androidtest/testgroup/TestGroup4.java | 0 .../iot/androidtest/testgroup/TestGroup5.java | 0 .../iot/androidtest/testgroup/TestGroup6.java | 0 .../iot/androidtest/testgroup/TestGroup7.java | 0 .../iot/androidtest/testgroup/TestGroup8.java | 0 .../iot/androidtest/testgroup/TestGroup9.java | 0 .../app/src/main/AndroidManifest.xml | 0 .../{android => android2}/build.gradle | 0 iot-e2e-tests/android2/gradle.properties | 21 +++++++++++++++++++ .../android2/gradle/libs.versions.toml | 20 ++++++++++++++++++ .../{android => android2}/settings.gradle | 0 vsts/RunTestsOnEmulator.sh | 8 +++---- vsts/gradle_build.ps1 | 2 +- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 6 +++--- 51 files changed, 136 insertions(+), 8 deletions(-) rename iot-e2e-tests/{android => android2}/.gitignore (100%) create mode 100644 iot-e2e-tests/android2/.idea/.gitignore create mode 100644 iot-e2e-tests/android2/.idea/.name create mode 100644 iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml create mode 100644 iot-e2e-tests/android2/.idea/compiler.xml create mode 100644 iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml create mode 100644 iot-e2e-tests/android2/.idea/gradle.xml create mode 100644 iot-e2e-tests/android2/.idea/migrations.xml create mode 100644 iot-e2e-tests/android2/.idea/misc.xml create mode 100644 iot-e2e-tests/android2/.idea/runConfigurations.xml create mode 100644 iot-e2e-tests/android2/.idea/vcs.xml rename iot-e2e-tests/{android => android2}/app/.gitignore (100%) rename iot-e2e-tests/{android => android2}/app/build.gradle (100%) rename iot-e2e-tests/{android => android2}/app/proguard-rules.pro (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java (100%) rename iot-e2e-tests/{android => android2}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java (100%) rename iot-e2e-tests/{android => android2}/app/src/main/AndroidManifest.xml (100%) rename iot-e2e-tests/{android => android2}/build.gradle (100%) create mode 100644 iot-e2e-tests/android2/gradle.properties create mode 100644 iot-e2e-tests/android2/gradle/libs.versions.toml rename iot-e2e-tests/{android => android2}/settings.gradle (100%) diff --git a/iot-e2e-tests/android/.gitignore b/iot-e2e-tests/android2/.gitignore similarity index 100% rename from iot-e2e-tests/android/.gitignore rename to iot-e2e-tests/android2/.gitignore diff --git a/iot-e2e-tests/android2/.idea/.gitignore b/iot-e2e-tests/android2/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/iot-e2e-tests/android2/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/iot-e2e-tests/android2/.idea/.name b/iot-e2e-tests/android2/.idea/.name new file mode 100644 index 0000000000..b3405b3b32 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/.name @@ -0,0 +1 @@ +My Application \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml b/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000000..4a53bee8cb --- /dev/null +++ b/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/compiler.xml b/iot-e2e-tests/android2/.idea/compiler.xml new file mode 100644 index 0000000000..b86273d942 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml b/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000000..b268ef36cd --- /dev/null +++ b/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/gradle.xml b/iot-e2e-tests/android2/.idea/gradle.xml new file mode 100644 index 0000000000..97f0a8e140 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/migrations.xml b/iot-e2e-tests/android2/.idea/migrations.xml new file mode 100644 index 0000000000..f8051a6f97 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/misc.xml b/iot-e2e-tests/android2/.idea/misc.xml new file mode 100644 index 0000000000..74dd639e4e --- /dev/null +++ b/iot-e2e-tests/android2/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/runConfigurations.xml b/iot-e2e-tests/android2/.idea/runConfigurations.xml new file mode 100644 index 0000000000..16660f1d80 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/vcs.xml b/iot-e2e-tests/android2/.idea/vcs.xml new file mode 100644 index 0000000000..b2bdec2d71 --- /dev/null +++ b/iot-e2e-tests/android2/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/iot-e2e-tests/android/app/.gitignore b/iot-e2e-tests/android2/app/.gitignore similarity index 100% rename from iot-e2e-tests/android/app/.gitignore rename to iot-e2e-tests/android2/app/.gitignore diff --git a/iot-e2e-tests/android/app/build.gradle b/iot-e2e-tests/android2/app/build.gradle similarity index 100% rename from iot-e2e-tests/android/app/build.gradle rename to iot-e2e-tests/android2/app/build.gradle diff --git a/iot-e2e-tests/android/app/proguard-rules.pro b/iot-e2e-tests/android2/app/proguard-rules.pro similarity index 100% rename from iot-e2e-tests/android/app/proguard-rules.pro rename to iot-e2e-tests/android2/app/proguard-rules.pro diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java diff --git a/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java similarity index 100% rename from iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java rename to iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java diff --git a/iot-e2e-tests/android/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml similarity index 100% rename from iot-e2e-tests/android/app/src/main/AndroidManifest.xml rename to iot-e2e-tests/android2/app/src/main/AndroidManifest.xml diff --git a/iot-e2e-tests/android/build.gradle b/iot-e2e-tests/android2/build.gradle similarity index 100% rename from iot-e2e-tests/android/build.gradle rename to iot-e2e-tests/android2/build.gradle diff --git a/iot-e2e-tests/android2/gradle.properties b/iot-e2e-tests/android2/gradle.properties new file mode 100644 index 0000000000..4387edc225 --- /dev/null +++ b/iot-e2e-tests/android2/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/iot-e2e-tests/android2/gradle/libs.versions.toml b/iot-e2e-tests/android2/gradle/libs.versions.toml new file mode 100644 index 0000000000..dcd4625cf4 --- /dev/null +++ b/iot-e2e-tests/android2/gradle/libs.versions.toml @@ -0,0 +1,20 @@ +[versions] +agp = "8.13.2" +junit = "4.13.2" +junitVersion = "1.1.5" +espressoCore = "3.5.1" +appcompat = "1.6.1" +material = "1.10.0" +runner = "1.7.0" + +[libraries] +junit = { group = "junit", name = "junit", version.ref = "junit" } +ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +runner = { module = "androidx.test:runner", version.ref = "runner" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } + diff --git a/iot-e2e-tests/android/settings.gradle b/iot-e2e-tests/android2/settings.gradle similarity index 100% rename from iot-e2e-tests/android/settings.gradle rename to iot-e2e-tests/android2/settings.gradle diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index 5c91d5a357..4ef5215a85 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -2,20 +2,20 @@ # This APK file is generated by the Android build task and then is copied into the android test run task. If the APK file # is missing, then either the copy failed, or the APK was never successfully built. -if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk" ]; then +if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi -if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then +if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi # -e flag to force this command to run on what should be the only emulator active on this machine echo 'Installing APKs on emulator' -adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk -adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk +adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk +adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk #List instrumentation classes, for logging purposes only echo 'Listing available instrumentations:' diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index dd8095b52c..4b0f63e7ab 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -1,5 +1,5 @@ # This script assumes it is being run from the root of the repository -cd iot-e2e-tests\android +cd iot-e2e-tests\android2 # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 9c34bd2b45..f869e2c49c 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -276,7 +276,7 @@ jobs: - task: CopyFiles@2 displayName: 'Copy Test Results to Artifact Staging Directory' inputs: - SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk' + SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk' Contents: | *.* TargetFolder: '$(Build.ArtifactStagingDirectory)' @@ -287,7 +287,7 @@ jobs: displayName: 'Publish APKs to test in next job' inputs: artifactName: 'androidBuildFiles' - targetPath: 'iot-e2e-tests/android/app/build/outputs/apk' + targetPath: 'iot-e2e-tests/android2/app/build/outputs/apk' - task: ComponentGovernanceComponentDetection@0 displayName: Component Governance Detection @@ -348,7 +348,7 @@ jobs: #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') inputs: artifactName: 'androidBuildFiles' - targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk + targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk - task: Bash@3 #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') From 643db67a3f2fe02d0c2dc19605ec765d59fa40cc Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 14:16:46 -0800 Subject: [PATCH 105/114] super --- .../iothub/connection/ConnectionTestsAndroidRunner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java index 16a0d7f0d7..b79a539cb0 100644 --- a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java +++ b/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java @@ -12,8 +12,8 @@ @RunWith(Parameterized.class) public class ConnectionTestsAndroidRunner extends ConnectionTests { - public ConnectionTestsAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean withProxy) throws Exception + public ConnectionTestsAndroidRunner(IotHubClientProtocol protocol, AuthenticationType authenticationType, ClientType clientType, boolean withProxy, boolean withProxyAuth) throws Exception { - super(protocol, authenticationType, clientType, withProxy); + super(protocol, authenticationType, clientType, withProxy, withProxyAuth); } } From 98e4f69d199c5c7cf271f54c248cb704b6c3657f Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 14:41:52 -0800 Subject: [PATCH 106/114] android2 to android saser --- .../{android2 => android}/.gitignore | 0 .../{android2 => android}/app/.gitignore | 0 .../{android2 => android}/app/build.gradle | 0 .../app/proguard-rules.pro | 0 .../iothub/FileUploadAndroidRunner.java | 0 .../MultiplexingClientAndroidRunner.java | 0 .../iothub/TokenRenewalAndroidRunner.java | 0 .../ConnectionTestsAndroidRunner.java | 0 .../DigitalTwinClientAndroidRunner.java | 0 ...TwinClientComponentTestsAndroidRunner.java | 0 .../DirectMethodsErrInjAndroidRunner.java | 0 .../ReceiveMessagesErrInjAndroidRunner.java | 0 .../SendMessagesErrInjAndroidRunner.java | 0 .../TwinErrInjAndroidRunner.java | 0 .../ReceiveMessagesAndroidRunner.java | 0 .../messaging/SendMessagesAndroidRunner.java | 0 .../methods/DirectMethodsAndroidRunner.java | 0 .../iothub/twin/TwinAndroidRunner.java | 0 ...ioningClientSymmetricKeyAndroidRunner.java | 0 .../ProvisioningClientX509AndroidRunner.java | 0 ...rovisioningServiceClientAndroidRunner.java | 0 .../iot/androidtest/testgroup/TestGroup1.java | 0 .../androidtest/testgroup/TestGroup10.java | 0 .../androidtest/testgroup/TestGroup11.java | 0 .../androidtest/testgroup/TestGroup12.java | 0 .../iot/androidtest/testgroup/TestGroup2.java | 0 .../iot/androidtest/testgroup/TestGroup3.java | 0 .../iot/androidtest/testgroup/TestGroup4.java | 0 .../iot/androidtest/testgroup/TestGroup5.java | 0 .../iot/androidtest/testgroup/TestGroup6.java | 0 .../iot/androidtest/testgroup/TestGroup7.java | 0 .../iot/androidtest/testgroup/TestGroup8.java | 0 .../iot/androidtest/testgroup/TestGroup9.java | 0 .../app/src/main/AndroidManifest.xml | 0 .../{android2 => android}/build.gradle | 0 .../gradle/libs.versions.toml | 0 .../{android2 => android}/settings.gradle | 0 iot-e2e-tests/android2/.idea/.gitignore | 3 --- iot-e2e-tests/android2/.idea/.name | 1 - .../android2/.idea/AndroidProjectSystem.xml | 6 ------ iot-e2e-tests/android2/.idea/compiler.xml | 6 ------ .../.idea/deploymentTargetSelector.xml | 10 --------- iot-e2e-tests/android2/.idea/gradle.xml | 18 ---------------- iot-e2e-tests/android2/.idea/migrations.xml | 10 --------- iot-e2e-tests/android2/.idea/misc.xml | 10 --------- .../android2/.idea/runConfigurations.xml | 17 --------------- iot-e2e-tests/android2/.idea/vcs.xml | 6 ------ iot-e2e-tests/android2/gradle.properties | 21 ------------------- vsts/RunTestsOnEmulator.sh | 8 +++---- vsts/gradle_build.ps1 | 2 +- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 6 +++--- 51 files changed, 8 insertions(+), 116 deletions(-) rename iot-e2e-tests/{android2 => android}/.gitignore (100%) rename iot-e2e-tests/{android2 => android}/app/.gitignore (100%) rename iot-e2e-tests/{android2 => android}/app/build.gradle (100%) rename iot-e2e-tests/{android2 => android}/app/proguard-rules.pro (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java (100%) rename iot-e2e-tests/{android2 => android}/app/src/main/AndroidManifest.xml (100%) rename iot-e2e-tests/{android2 => android}/build.gradle (100%) rename iot-e2e-tests/{android2 => android}/gradle/libs.versions.toml (100%) rename iot-e2e-tests/{android2 => android}/settings.gradle (100%) delete mode 100644 iot-e2e-tests/android2/.idea/.gitignore delete mode 100644 iot-e2e-tests/android2/.idea/.name delete mode 100644 iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml delete mode 100644 iot-e2e-tests/android2/.idea/compiler.xml delete mode 100644 iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml delete mode 100644 iot-e2e-tests/android2/.idea/gradle.xml delete mode 100644 iot-e2e-tests/android2/.idea/migrations.xml delete mode 100644 iot-e2e-tests/android2/.idea/misc.xml delete mode 100644 iot-e2e-tests/android2/.idea/runConfigurations.xml delete mode 100644 iot-e2e-tests/android2/.idea/vcs.xml delete mode 100644 iot-e2e-tests/android2/gradle.properties diff --git a/iot-e2e-tests/android2/.gitignore b/iot-e2e-tests/android/.gitignore similarity index 100% rename from iot-e2e-tests/android2/.gitignore rename to iot-e2e-tests/android/.gitignore diff --git a/iot-e2e-tests/android2/app/.gitignore b/iot-e2e-tests/android/app/.gitignore similarity index 100% rename from iot-e2e-tests/android2/app/.gitignore rename to iot-e2e-tests/android/app/.gitignore diff --git a/iot-e2e-tests/android2/app/build.gradle b/iot-e2e-tests/android/app/build.gradle similarity index 100% rename from iot-e2e-tests/android2/app/build.gradle rename to iot-e2e-tests/android/app/build.gradle diff --git a/iot-e2e-tests/android2/app/proguard-rules.pro b/iot-e2e-tests/android/app/proguard-rules.pro similarity index 100% rename from iot-e2e-tests/android2/app/proguard-rules.pro rename to iot-e2e-tests/android/app/proguard-rules.pro diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/FileUploadAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/MultiplexingClientAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/TokenRenewalAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/connection/ConnectionTestsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/digitaltwin/DigitalTwinClientComponentTestsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/DirectMethodsErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/ReceiveMessagesErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/SendMessagesErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/errorinjection/TwinErrInjAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/ReceiveMessagesAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/messaging/SendMessagesAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/methods/DirectMethodsAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/iothub/twin/TwinAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientSymmetricKeyAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningClientX509AndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/provisioning/ProvisioningServiceClientAndroidRunner.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup1.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup10.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup11.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup12.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup2.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup3.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup4.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup5.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup6.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup7.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup8.java diff --git a/iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java b/iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java similarity index 100% rename from iot-e2e-tests/android2/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java rename to iot-e2e-tests/android/app/src/androidTest/java/com/microsoft/azure/sdk/iot/androidtest/testgroup/TestGroup9.java diff --git a/iot-e2e-tests/android2/app/src/main/AndroidManifest.xml b/iot-e2e-tests/android/app/src/main/AndroidManifest.xml similarity index 100% rename from iot-e2e-tests/android2/app/src/main/AndroidManifest.xml rename to iot-e2e-tests/android/app/src/main/AndroidManifest.xml diff --git a/iot-e2e-tests/android2/build.gradle b/iot-e2e-tests/android/build.gradle similarity index 100% rename from iot-e2e-tests/android2/build.gradle rename to iot-e2e-tests/android/build.gradle diff --git a/iot-e2e-tests/android2/gradle/libs.versions.toml b/iot-e2e-tests/android/gradle/libs.versions.toml similarity index 100% rename from iot-e2e-tests/android2/gradle/libs.versions.toml rename to iot-e2e-tests/android/gradle/libs.versions.toml diff --git a/iot-e2e-tests/android2/settings.gradle b/iot-e2e-tests/android/settings.gradle similarity index 100% rename from iot-e2e-tests/android2/settings.gradle rename to iot-e2e-tests/android/settings.gradle diff --git a/iot-e2e-tests/android2/.idea/.gitignore b/iot-e2e-tests/android2/.idea/.gitignore deleted file mode 100644 index 26d33521af..0000000000 --- a/iot-e2e-tests/android2/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/iot-e2e-tests/android2/.idea/.name b/iot-e2e-tests/android2/.idea/.name deleted file mode 100644 index b3405b3b32..0000000000 --- a/iot-e2e-tests/android2/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -My Application \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml b/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml deleted file mode 100644 index 4a53bee8cb..0000000000 --- a/iot-e2e-tests/android2/.idea/AndroidProjectSystem.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/compiler.xml b/iot-e2e-tests/android2/.idea/compiler.xml deleted file mode 100644 index b86273d942..0000000000 --- a/iot-e2e-tests/android2/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml b/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml deleted file mode 100644 index b268ef36cd..0000000000 --- a/iot-e2e-tests/android2/.idea/deploymentTargetSelector.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/gradle.xml b/iot-e2e-tests/android2/.idea/gradle.xml deleted file mode 100644 index 97f0a8e140..0000000000 --- a/iot-e2e-tests/android2/.idea/gradle.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/migrations.xml b/iot-e2e-tests/android2/.idea/migrations.xml deleted file mode 100644 index f8051a6f97..0000000000 --- a/iot-e2e-tests/android2/.idea/migrations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/misc.xml b/iot-e2e-tests/android2/.idea/misc.xml deleted file mode 100644 index 74dd639e4e..0000000000 --- a/iot-e2e-tests/android2/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/runConfigurations.xml b/iot-e2e-tests/android2/.idea/runConfigurations.xml deleted file mode 100644 index 16660f1d80..0000000000 --- a/iot-e2e-tests/android2/.idea/runConfigurations.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/.idea/vcs.xml b/iot-e2e-tests/android2/.idea/vcs.xml deleted file mode 100644 index b2bdec2d71..0000000000 --- a/iot-e2e-tests/android2/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/iot-e2e-tests/android2/gradle.properties b/iot-e2e-tests/android2/gradle.properties deleted file mode 100644 index 4387edc225..0000000000 --- a/iot-e2e-tests/android2/gradle.properties +++ /dev/null @@ -1,21 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. For more details, visit -# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true \ No newline at end of file diff --git a/vsts/RunTestsOnEmulator.sh b/vsts/RunTestsOnEmulator.sh index 4ef5215a85..5c91d5a357 100644 --- a/vsts/RunTestsOnEmulator.sh +++ b/vsts/RunTestsOnEmulator.sh @@ -2,20 +2,20 @@ # This APK file is generated by the Android build task and then is copied into the android test run task. If the APK file # is missing, then either the copy failed, or the APK was never successfully built. -if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk" ]; then +if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi -if [ ! -f "iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then +if [ ! -f "iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" ]; then echo 'Missing expected apk file. Android build task likely failed silently.' exit -1 fi # -e flag to force this command to run on what should be the only emulator active on this machine echo 'Installing APKs on emulator' -adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/debug/app-debug.apk -adb -e install -r iot-e2e-tests/android2/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk +adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/debug/app-debug.apk +adb -e install -r iot-e2e-tests/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk #List instrumentation classes, for logging purposes only echo 'Listing available instrumentations:' diff --git a/vsts/gradle_build.ps1 b/vsts/gradle_build.ps1 index 4b0f63e7ab..dd8095b52c 100644 --- a/vsts/gradle_build.ps1 +++ b/vsts/gradle_build.ps1 @@ -1,5 +1,5 @@ # This script assumes it is being run from the root of the repository -cd iot-e2e-tests\android2 +cd iot-e2e-tests\android # This script pulls down this version of gradle because the default version installed on ADO # can change over time. This allows us more control over when we want to upgrade gradle versions diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index f869e2c49c..9c34bd2b45 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -276,7 +276,7 @@ jobs: - task: CopyFiles@2 displayName: 'Copy Test Results to Artifact Staging Directory' inputs: - SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk' + SourceFolder: '$(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk' Contents: | *.* TargetFolder: '$(Build.ArtifactStagingDirectory)' @@ -287,7 +287,7 @@ jobs: displayName: 'Publish APKs to test in next job' inputs: artifactName: 'androidBuildFiles' - targetPath: 'iot-e2e-tests/android2/app/build/outputs/apk' + targetPath: 'iot-e2e-tests/android/app/build/outputs/apk' - task: ComponentGovernanceComponentDetection@0 displayName: Component Governance Detection @@ -348,7 +348,7 @@ jobs: #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') inputs: artifactName: 'androidBuildFiles' - targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android2/app/build/outputs/apk + targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk - task: Bash@3 #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') From 737eba42aaa9020f3433e2910662b0a5a02189c1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 14:51:37 -0800 Subject: [PATCH 107/114] todo --- .../integration/com/microsoft/azure/sdk/iot/helpers/Tools.java | 1 - 1 file changed, 1 deletion(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java index d1fcf789bf..7f87c56a5d 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/Tools.java @@ -64,7 +64,6 @@ public class Tools private static final long WAIT_FOR_RETRY = 2000; private static boolean IS_ANDROID = false; -//TODO this guy? private static final String ANDROID_BUILD_CONFIG_CLASS = "com.microsoft.azure.sdk.iot.androidtest.test.BuildConfig"; private static final Map ANDROID_ENV_VAR = retrieveAndroidEnvVariables(); From d396de56544caaf0343eb4ad6e68b16353f6303b Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 14:55:53 -0800 Subject: [PATCH 108/114] gradle properties file --- iot-e2e-tests/android/gradle.properties | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 iot-e2e-tests/android/gradle.properties diff --git a/iot-e2e-tests/android/gradle.properties b/iot-e2e-tests/android/gradle.properties new file mode 100644 index 0000000000..4387edc225 --- /dev/null +++ b/iot-e2e-tests/android/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file From 11d594498175ab5b3bc1961aabe90f3f1ed22686 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 15:17:18 -0800 Subject: [PATCH 109/114] unused --- .../com/microsoft/azure/sdk/iot/Tools.java | 43 ++----------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java b/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java index 487a895c11..789cda0aa0 100644 --- a/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java +++ b/iot-e2e-tests/iot-e2e-jvm-tests/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/Tools.java @@ -14,62 +14,25 @@ @Slf4j public class Tools { - private static final Map ANDROID_ENV_VAR = retrieveAndroidEnvVariables(); - private static String IOT_HUB_CONNECTION_STRING_ENV_VAR_NAME = "IOTHUB_CONNECTION_STRING"; private static final String IS_BASIC_TIER_HUB_ENV_VAR_NAME = "IS_BASIC_TIER_HUB"; public static final String iotHubConnectionString = retrieveEnvironmentVariableValue(IOT_HUB_CONNECTION_STRING_ENV_VAR_NAME); public static final boolean isBasicTierHub = Boolean.parseBoolean(retrieveEnvironmentVariableValue(IS_BASIC_TIER_HUB_ENV_VAR_NAME)); -//UNUSED? JVM test project - private static final String ANDROID_BUILD_CONFIG_CLASS = "com.iothub.azure.microsoft.com.androide2e.test.BuildConfig"; - public static String retrieveEnvironmentVariableValue(String environmentVariableName) { String environmentVariableValue; - if (ANDROID_ENV_VAR.containsKey(environmentVariableName)) + environmentVariableValue = System.getenv().get(environmentVariableName); + if ((environmentVariableValue == null) || environmentVariableValue.isEmpty()) { - environmentVariableValue = ANDROID_ENV_VAR.get(environmentVariableName); - } - else - { - environmentVariableValue = System.getenv().get(environmentVariableName); - if ((environmentVariableValue == null) || environmentVariableValue.isEmpty()) - { - environmentVariableValue = System.getProperty(environmentVariableName); - } + environmentVariableValue = System.getProperty(environmentVariableName); } return environmentVariableValue; } - public static Map retrieveAndroidEnvVariables() - { - Map envVariables = new HashMap<>(); - try - { - Class buildConfig = Class.forName(ANDROID_BUILD_CONFIG_CLASS); - Arrays.stream(buildConfig.getFields()).forEach(field -> { - try - { - envVariables.put(field.getName(), field.get(null).toString()); - } - catch (IllegalAccessException e) - { - log.error("Cannot access the following field: {}", field.getName(), e); - } - }); - } - catch (ClassNotFoundException e) - { - log.debug("Likely running the JVM tests, ignoring ClassNotFoundException\n"); - } - - return envVariables; - } - public static String getHostName(String iotHubConnectionString) { return IotHubConnectionStringBuilder.createIotHubConnectionString(iotHubConnectionString).getHostName(); From 5ff00dc939312bf4e9c8a509d0802cc5aff243a1 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Wed, 21 Jan 2026 16:41:10 -0800 Subject: [PATCH 110/114] re-add --- pom.xml | 5 +++++ vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 85bb2362f5..54630e0e4e 100644 --- a/pom.xml +++ b/pom.xml @@ -140,6 +140,11 @@ netty-codec-http2 4.2.9.Final + + io.projectreactor.netty + reactor-netty-http + 1.0.39 + commons-cli commons-cli diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 9c34bd2b45..6cec8bf54e 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -16,7 +16,7 @@ variables: maxParallel: 2 jobs: - - job: DeployCloudTestResources + - job: DeployCloudTestResources #TODO need this step to always run? Or only run delete resources if all stages pass? Then run nightly cleanup of rgs? pool: vmImage: windows-latest steps: From 1c9b2806af1d0feacbb1b5c756a12bec225870d2 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 23 Jan 2026 15:04:07 -0800 Subject: [PATCH 111/114] cr comments --- .../azure/sdk/iot/helpers/BasicProxyAuthenticator.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java index 7d188c692f..53713c0341 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java @@ -39,16 +39,12 @@ protected BasicHttpToken authenticate(String usr, String pwd) public BasicHttpToken authenticate(String authorization) { String usr = ""; String pwd = ""; - if (authorization != null && authorization.length() > 0) { + if (authorization != null && authorization.startsWith(AUTH_TYPE_BASIC)) { String token = authorization.substring(AUTH_TYPE_BASIC.length() + 1); String decode = new String(Base64.getDecoder().decode(token)); String[] arr = decode.split(":"); - if (arr.length >= 1) { - usr = arr[0]; - } - if (arr.length >= 2) { - pwd = arr[1]; - } + usr = arr.length >= 1 ? arr[0] : ""; + pwd = arr.length >= 2 ? arr[1] : ""; } return authenticate(usr, pwd); } From ad096d9fbb0bbe25b5153a9dae4241cbb137e083 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 23 Jan 2026 15:06:43 -0800 Subject: [PATCH 112/114] re-enable skipping tests when relevant --- ...ndowsLinuxAndAndroidBuildMatrixConfig.yaml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml index 6cec8bf54e..e54ffcb5be 100644 --- a/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml +++ b/vsts/windowsLinuxAndAndroidBuildMatrixConfig.yaml @@ -16,7 +16,7 @@ variables: maxParallel: 2 jobs: - - job: DeployCloudTestResources #TODO need this step to always run? Or only run delete resources if all stages pass? Then run nightly cleanup of rgs? + - job: DeployCloudTestResources pool: vmImage: windows-latest steps: @@ -332,26 +332,26 @@ jobs: displayName: Android Test dependsOn: AndroidBuild steps: - #- task: PowerShell@2 - # displayName: 'determine if testing needed' - # condition: always() - # inputs: - # targetType: 'filePath' - # filePath: ./vsts/determine_if_android_test_group_needs_to_run.ps1 - # env: - # TEST_GROUP_ID: $(ANDROID_TEST_GROUP_ID) - # IS_BASIC_TIER_HUB: $(IS-BASIC-TIER-HUB) - # TARGET_BRANCH: $(System.PullRequest.TargetBranch) + - task: PowerShell@2 + displayName: 'determine if testing needed' + condition: always() + inputs: + targetType: 'filePath' + filePath: ./vsts/determine_if_android_test_group_needs_to_run.ps1 + env: + TEST_GROUP_ID: $(ANDROID_TEST_GROUP_ID) + IS_BASIC_TIER_HUB: $(IS-BASIC-TIER-HUB) + TARGET_BRANCH: $(System.PullRequest.TargetBranch) - task: DownloadPipelineArtifact@0 displayName: "Download APKs to test from previous job" - #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') + condition: eq(variables['task.android.needToRunTestGroup'], 'yes') inputs: artifactName: 'androidBuildFiles' targetPath: $(Build.SourcesDirectory)/iot-e2e-tests/android/app/build/outputs/apk - task: Bash@3 - #condition: eq(variables['task.android.needToRunTestGroup'], 'yes') + condition: eq(variables['task.android.needToRunTestGroup'], 'yes') displayName: 'Start Android Emulator' timeoutInMinutes: 15 continueOnError: false @@ -361,7 +361,7 @@ jobs: - task: Bash@3 #only run tests on emulator if tests should be run, and if the emulator boot up was successful - #condition: and(succeeded(), eq(variables['task.android.needToRunTestGroup'], 'yes')) + condition: and(succeeded(), eq(variables['task.android.needToRunTestGroup'], 'yes')) displayName: 'Run tests on emulator' timeoutInMinutes: 45 inputs: From 4a8f8f1898e7fa891f56b44dc0fc5cf0e70b0a5e Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 23 Jan 2026 15:53:51 -0800 Subject: [PATCH 113/114] small fix --- .../azure/sdk/iot/iothub/connection/ConnectionTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java index 24de0dcd99..30f0ddf9b8 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/iothub/connection/ConnectionTests.java @@ -216,7 +216,7 @@ public static void startProxy() proxyServer.startAsync(testProxyPort); HttpProxyServerConfig configWithoutAuth = new HttpProxyServerConfig(); - config.setHandleSsl(false); + configWithoutAuth.setHandleSsl(false); proxyServerWithoutAuth = new HttpProxyServer().serverConfig(configWithoutAuth); proxyServerWithoutAuth.startAsync(testProxyPortWithoutAuth); } From c4096c0db36d6f8d14d4c274631265507e9b1199 Mon Sep 17 00:00:00 2001 From: Tim Taylor Date: Fri, 23 Jan 2026 16:42:47 -0800 Subject: [PATCH 114/114] This broke some tests, oddly --- .../azure/sdk/iot/helpers/BasicProxyAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java index 53713c0341..f04fd7700e 100644 --- a/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java +++ b/iot-e2e-tests/common/src/test/java/tests/integration/com/microsoft/azure/sdk/iot/helpers/BasicProxyAuthenticator.java @@ -39,7 +39,7 @@ protected BasicHttpToken authenticate(String usr, String pwd) public BasicHttpToken authenticate(String authorization) { String usr = ""; String pwd = ""; - if (authorization != null && authorization.startsWith(AUTH_TYPE_BASIC)) { + if (authorization != null && authorization.length() > 0) { String token = authorization.substring(AUTH_TYPE_BASIC.length() + 1); String decode = new String(Base64.getDecoder().decode(token)); String[] arr = decode.split(":");