[automerger skipped] Log ServiceEntitlementException in EapAkaHelper.getEapAkaResponse am: 379684e8ab am: 8d9ae32ef5 am: 7abbe8c5f3 am: 65a306f31b am: 7620255b73 -s ours

am skip reason: Merged-In I33363d5f10f0a1be03ebc72680fc73c8b42fa75d with SHA-1 91c9485a81 is already in history

Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/service_entitlement/+/1871748

Change-Id: Iba64881f556516fa68842077b27bf529b358519c
diff --git a/coverage.sh b/coverage.sh
new file mode 100755
index 0000000..7cd2bf2
--- /dev/null
+++ b/coverage.sh
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+
+##### App specific parameters #####
+
+PACKAGE_NAME='com.android.libraries.entitlement'
+MODULE_NAME='service-entitlement'
+MODULE_PATH='frameworks/libs/service_entitlement'
+
+TEST_PACKAGE='com.android.libraries.entitlement.tests'
+TEST_MODULE_NAME='service-entitlement-tests'
+TEST_MODULE_PATH='frameworks/libs/service_entitlement/tests'
+TEST_MODULE_INSTALL_PATH="testcases/$TEST_MODULE_NAME/arm64/$TEST_MODULE_NAME.apk"
+TEST_RUNNER="$TEST_PACKAGE/androidx.test.runner.AndroidJUnitRunner"
+
+##### End app specific parameters #####
+
+if [[ $# != 0 && ! ($# == 1 && ($1 == "html" || $1 == "xml" || $1 == "csv")) ]]; then
+  echo "$0: usage: coverage.sh [REPORT_TYPE]"
+  echo "REPORT_TYPE [html | xml | csv] : the type of the report (default is html)"
+  exit 1
+fi
+
+REPORT_TYPE=${1:-html}
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+
+REPORTER_JAR="$ANDROID_BUILD_TOP/out/soong/host/linux-x86/framework/jacoco-cli.jar"
+
+OUTPUT_DIR="$ANDROID_BUILD_TOP/out/coverage/$MODULE_NAME"
+
+echo "Running tests and generating coverage report"
+echo "Output dir: $OUTPUT_DIR"
+echo "Report type: $REPORT_TYPE"
+
+# location on the device to store coverage results, need to be accessible by the app
+REMOTE_COVERAGE_OUTPUT_FILE="/data/user/0/$TEST_PACKAGE/files/coverage.ec"
+
+COVERAGE_OUTPUT_FILE="$ANDROID_BUILD_TOP/out/$PACKAGE_NAME.ec"
+OUT_COMMON="$ANDROID_BUILD_TOP/out/target/common"
+COVERAGE_CLASS_FILE="$OUT/obj/JAVA_LIBRARIES/${MODULE_NAME}_intermediates/javalib.jar"
+
+source $ANDROID_BUILD_TOP/build/envsetup.sh
+
+set -e # fail early
+
+echo ""
+echo "BUILDING PACKAGE $PACKAGE_NAME"
+echo "============================================"
+(cd "$ANDROID_BUILD_TOP/$MODULE_PATH" && EMMA_INSTRUMENT=true EMMA_INSTRUMENT_STATIC=true mma -j32)
+echo "============================================"
+
+echo ""
+echo "BUILDING TEST PACKAGE $TEST_MODULE_NAME"
+echo "============================================"
+(cd "$ANDROID_BUILD_TOP/$TEST_MODULE_PATH" && EMMA_INSTRUMENT=true EMMA_INSTRUMENT_STATIC=true mma -j32)
+echo "============================================"
+
+#set -x # print commands
+
+adb root
+adb wait-for-device
+
+adb shell rm -f "$REMOTE_COVERAGE_OUTPUT_FILE"
+
+adb install -r -g "$OUT/$TEST_MODULE_INSTALL_PATH"
+
+echo ""
+echo "RUNNING TESTS $TEST_RUNNER"
+echo "============================================"
+adb shell am instrument -e coverage true -w $TEST_RUNNER
+echo "============================================"
+
+mkdir -p "$OUTPUT_DIR"
+
+adb pull "$REMOTE_COVERAGE_OUTPUT_FILE" "$COVERAGE_OUTPUT_FILE"
+
+java -jar "$REPORTER_JAR" \
+  report "$COVERAGE_OUTPUT_FILE" \
+  --$REPORT_TYPE "$OUTPUT_DIR" \
+  --classfiles "$COVERAGE_CLASS_FILE" \
+  --sourcefiles "$ANDROID_BUILD_TOP/$MODULE_PATH/java"
+
+#set +x
+
+# Echo the file as URI to quickly open the result using ctrl-click in terminal
+if [[ REPORT_TYPE == html ]] ; then
+  echo "COVERAGE RESULTS IN:"
+  echo "file://$OUTPUT_DIR/index.html"
+fi
diff --git a/tests/src/com/android/libraries/entitlement/ServiceEntitlementTest.java b/tests/src/com/android/libraries/entitlement/ServiceEntitlementTest.java
index e54d87f..7e2b0f1 100644
--- a/tests/src/com/android/libraries/entitlement/ServiceEntitlementTest.java
+++ b/tests/src/com/android/libraries/entitlement/ServiceEntitlementTest.java
@@ -18,8 +18,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
 
+import android.content.Context;
+import android.telephony.TelephonyManager;
+
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.libraries.entitlement.eapaka.EapAkaApi;
@@ -38,13 +44,20 @@
 public class ServiceEntitlementTest {
     private static final String QUERY_APP_VOLTE_RESULT = "QUERY_APP_VOLTE_RESULT";
     private static final String QUERY_APP_VOWIFI_RESULT = "QUERY_APP_VOWIFI_RESULT";
+    private static final String QUERY_APP_ODSA_COMPANION_RESULT = "QUERY_APP_ODSA_COMPANION_RESULT";
+    private static final String QUERY_APP_ODSA_PRIMARY_RESULT = "QUERY_APP_ODSA_PRIMARY_RESULT";
     private static final String TEST_URL = "https://test.url";
 
-    @Rule
-    public final MockitoRule rule = MockitoJUnit.rule();
-    @Mock
-    EapAkaApi mMockEapAkaApi;
+    private static final String IMSI = "234107813240779";
+    private static final String MCCMNC = "23410";
+    private static final int SUB_ID = 1;
 
+    @Rule public final MockitoRule rule = MockitoJUnit.rule();
+    @Mock EapAkaApi mMockEapAkaApi;
+    @Mock private TelephonyManager mMockTelephonyManager;
+    @Mock private TelephonyManager mMockTelephonyManagerForSubId;
+
+    private Context mContext;
     private ServiceEntitlement mServiceEntitlement;
     private CarrierConfig mCarrierConfig;
 
@@ -52,6 +65,31 @@
     public void setUp() {
         mCarrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
         mServiceEntitlement = new ServiceEntitlement(mCarrierConfig, mMockEapAkaApi);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+    }
+
+    @Test
+    public void queryEntitlementStatus_noServerAddress_throwException() throws Exception {
+        CarrierConfig config = CarrierConfig.builder().build();
+        ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+        ServiceEntitlement serviceEntitlement = new ServiceEntitlement(mContext, config, SUB_ID);
+        when(mContext.getSystemService(TelephonyManager.class))
+                .thenReturn(mMockTelephonyManager);
+        when(mMockTelephonyManager.createForSubscriptionId(SUB_ID))
+                .thenReturn(mMockTelephonyManagerForSubId);
+        when(mMockTelephonyManagerForSubId.getSubscriberId()).thenReturn(IMSI);
+        when(mMockTelephonyManagerForSubId.getSimOperator()).thenReturn(MCCMNC);
+
+        ServiceEntitlementException exception = expectThrows(
+                ServiceEntitlementException.class,
+                () -> serviceEntitlement.queryEntitlementStatus(
+                        ImmutableList.of(ServiceEntitlement.APP_VOWIFI), request));
+
+        assertThat(exception.getErrorCode()).isEqualTo(
+                ServiceEntitlementException.ERROR_SERVER_NOT_CONNECTABLE);
+        assertThat(exception.getMessage()).isEqualTo("Configure connection failed!");
+        assertThat(exception.getHttpStatus()).isEqualTo(0);
+        assertThat(exception.getRetryAfter()).isEmpty();
     }
 
     @Test
@@ -79,4 +117,32 @@
                         request))
                 .isEqualTo(QUERY_APP_VOWIFI_RESULT);
     }
+
+    @Test
+    public void performEsimOdsa_appOdsaCompanion_returnResult() throws Exception {
+        ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+        EsimOdsaOperation odsaOperation = EsimOdsaOperation.builder().build();
+        when(mMockEapAkaApi.performEsimOdsaOperation(
+                ServiceEntitlement.APP_ODSA_COMPANION, mCarrierConfig, request, odsaOperation))
+                .thenReturn(QUERY_APP_ODSA_COMPANION_RESULT);
+
+        assertThat(
+                mServiceEntitlement.performEsimOdsa(
+                        ServiceEntitlement.APP_ODSA_COMPANION, request, odsaOperation))
+                .isEqualTo(QUERY_APP_ODSA_COMPANION_RESULT);
+    }
+
+    @Test
+    public void performEsimOdsa_appOdsaPrimary_returnResult() throws Exception {
+        ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+        EsimOdsaOperation odsaOperation = EsimOdsaOperation.builder().build();
+        when(mMockEapAkaApi.performEsimOdsaOperation(
+                ServiceEntitlement.APP_ODSA_PRIMARY, mCarrierConfig, request, odsaOperation))
+                .thenReturn(QUERY_APP_ODSA_PRIMARY_RESULT);
+
+        assertThat(
+                mServiceEntitlement.performEsimOdsa(
+                        ServiceEntitlement.APP_ODSA_PRIMARY, request, odsaOperation))
+                .isEqualTo(QUERY_APP_ODSA_PRIMARY_RESULT);
+    }
 }
diff --git a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
index f655258..b837695 100644
--- a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
+++ b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
@@ -220,6 +220,8 @@
                 ServiceEntitlementException.ERROR_MALFORMED_HTTP_RESPONSE);
         assertThat(exception.getMessage()).isEqualTo("Failed to parse json object");
         assertThat(exception.getCause()).isInstanceOf(JSONException.class);
+        assertThat(exception.getHttpStatus()).isEqualTo(0);
+        assertThat(exception.getRetryAfter()).isEmpty();
     }
 
     @Test
@@ -263,7 +265,7 @@
             throws Exception {
         HttpResponse response = HttpResponse.builder().setBody(RESPONSE_XML).build();
         when(mMockHttpClient.request(any())).thenReturn(response);
-        CarrierConfig carrierConfig = CarrierConfig.builder().build();
+        CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
         ServiceEntitlementRequest request =
                 ServiceEntitlementRequest
                         .builder()
@@ -284,7 +286,7 @@
             throws Exception {
         HttpResponse response = HttpResponse.builder().setBody(RESPONSE_XML).build();
         when(mMockHttpClient.request(any())).thenReturn(response);
-        CarrierConfig carrierConfig = CarrierConfig.builder().build();
+        CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
         ServiceEntitlementRequest request =
                 ServiceEntitlementRequest
                         .builder()
diff --git a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaSecurityContextTest.java b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaSecurityContextTest.java
index 219737d..e6d1c0c 100644
--- a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaSecurityContextTest.java
+++ b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaSecurityContextTest.java
@@ -104,6 +104,8 @@
                 .isEqualTo(ServiceEntitlementException.ERROR_ICC_AUTHENTICATION_NOT_AVAILABLE);
         assertThat(exception.getMessage())
                 .isEqualTo("Invalid SIM EAP-AKA authentication response!");
+        assertThat(exception.getHttpStatus()).isEqualTo(0);
+        assertThat(exception.getRetryAfter()).isEmpty();
     }
 
     @Test
diff --git a/tests/src/com/android/libraries/entitlement/http/HttpClientTest.java b/tests/src/com/android/libraries/entitlement/http/HttpClientTest.java
index 5838bb7..505e8b5 100644
--- a/tests/src/com/android/libraries/entitlement/http/HttpClientTest.java
+++ b/tests/src/com/android/libraries/entitlement/http/HttpClientTest.java
@@ -192,4 +192,56 @@
         FakeHttpsURLConnection connection = sFakeURLStreamHandler.getConnections().get(0);
         assertThat(connection.getBytesWrittenToOutputStream()).isEqualTo(postData.getBytes(UTF_8));
     }
+
+    @Test
+    public void request_getResponseCodeFailed_expectThrowsException() {
+        HttpRequest request =
+                HttpRequest.builder()
+                        .setUrl(TEST_URL)
+                        .setRequestMethod(RequestMethod.GET)
+                        .build();
+        FakeResponse responseContent =
+                FakeResponse.builder()
+                        .setResponseBody(TEST_RESPONSE_BODY.getBytes(UTF_8))
+                        .setContentType(CONTENT_TYPE_STRING_JSON)
+                        .setHasException(true)
+                        .build();
+        Map<String, FakeResponse> response = ImmutableMap.of(TEST_URL, responseContent);
+        sFakeURLStreamHandler.stubResponse(response);
+
+        ServiceEntitlementException exception = expectThrows(
+                ServiceEntitlementException.class, () -> mHttpClient.request(request));
+
+        assertThat(exception.getErrorCode()).isEqualTo(
+                ServiceEntitlementException.ERROR_HTTP_STATUS_NOT_SUCCESS);
+        assertThat(exception.getMessage()).isEqualTo("Read response code failed!");
+        assertThat(exception.getHttpStatus()).isEqualTo(0);
+        assertThat(exception.getRetryAfter()).isEmpty();
+    }
+
+    @Test
+    public void request_getResponseBodyFailed_expectThrowsException() {
+        HttpRequest request =
+                HttpRequest.builder()
+                        .setUrl(TEST_URL)
+                        .setRequestMethod(RequestMethod.GET)
+                        .build();
+        FakeResponse responseContent =
+                FakeResponse.builder()
+                        .setResponseCode(HttpURLConnection.HTTP_OK)
+                        .setContentType(CONTENT_TYPE_STRING_JSON)
+                        .setHasException(true)
+                        .build();
+        Map<String, FakeResponse> response = ImmutableMap.of(TEST_URL, responseContent);
+        sFakeURLStreamHandler.stubResponse(response);
+
+        ServiceEntitlementException exception = expectThrows(
+                ServiceEntitlementException.class, () -> mHttpClient.request(request));
+
+        assertThat(exception.getErrorCode()).isEqualTo(
+                ServiceEntitlementException.ERROR_MALFORMED_HTTP_RESPONSE);
+        assertThat(exception.getMessage()).isEqualTo("Read response body/message failed!");
+        assertThat(exception.getHttpStatus()).isEqualTo(0);
+        assertThat(exception.getRetryAfter()).isEmpty();
+    }
 }
diff --git a/tests/src/com/android/libraries/entitlement/utils/BytesConverterTest.java b/tests/src/com/android/libraries/entitlement/utils/BytesConverterTest.java
new file mode 100644
index 0000000..41c8445
--- /dev/null
+++ b/tests/src/com/android/libraries/entitlement/utils/BytesConverterTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.libraries.entitlement.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class BytesConverterTest {
+    @Test
+    public void convertBytesToHexString_nullBytes_returnsNull() {
+        assertThat(BytesConverter.convertBytesToHexString(null)).isNull();
+    }
+
+    @Test
+    public void convertBytesToHexString_integerBytes_returnsHexString() {
+        byte[] integerBytes = BytesConverter.convertIntegerTo4Bytes(123);
+
+        String hexString = BytesConverter.convertBytesToHexString(integerBytes);
+
+        assertThat(hexString).isEqualTo("0000007B");
+    }
+}
diff --git a/tests/utils/com/android/libraries/entitlement/testing/FakeURLStreamHandler.java b/tests/utils/com/android/libraries/entitlement/testing/FakeURLStreamHandler.java
index a5bdb4c..9f1d233 100644
--- a/tests/utils/com/android/libraries/entitlement/testing/FakeURLStreamHandler.java
+++ b/tests/utils/com/android/libraries/entitlement/testing/FakeURLStreamHandler.java
@@ -16,6 +16,8 @@
 
 package com.android.libraries.entitlement.testing;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -90,6 +92,9 @@
 
         @Override
         public InputStream getInputStream() throws IOException {
+            if (mResponse.hasException() && mResponse.responseBody().length == 0) {
+                throw new IOException("stub exception");
+            }
             return new ByteArrayInputStream(mResponse.responseBody());
         }
 
@@ -98,12 +103,20 @@
             return mOutputStream;
         }
 
+        @Override
+        public InputStream getErrorStream() {
+            return new ByteArrayInputStream("stub error".getBytes(UTF_8));
+        }
+
         public byte[] getBytesWrittenToOutputStream() {
             return mOutputStream.toByteArray();
         }
 
         @Override
-        public int getResponseCode() {
+        public int getResponseCode() throws IOException {
+            if (mResponse.hasException() && mResponse.responseCode() == 0) {
+                throw new IOException("stub exception");
+            }
             return mResponse.responseCode();
         }
 
@@ -170,13 +183,16 @@
 
         public abstract String retryAfter();
 
+        abstract boolean hasException();
+
         public static Builder builder() {
             return new AutoValue_FakeURLStreamHandler_FakeResponse.Builder()
                     .setResponseBody(new byte[]{})
                     .setContentType("")
                     .setResponseCode(0)
                     .setResponseLocation("")
-                    .setRetryAfter("");
+                    .setRetryAfter("")
+                    .setHasException(false);
         }
 
         @AutoValue.Builder
@@ -191,6 +207,8 @@
 
             public abstract Builder setRetryAfter(String retryAfter);
 
+            public abstract Builder setHasException(boolean hasException);
+
             public abstract FakeResponse build();
         }
     }