aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsamalin <samalin@google.com>2021-02-26 02:55:07 +0800
committerSama Lin <samalin@google.com>2021-05-11 16:53:59 +0000
commit35ab884e53b2b6f8072be2f286617a313e3c38bd (patch)
tree59ae754043651a791365914c52328de466ebf0df
parent0930a0c7630dea225e846219bf746a49c079068a (diff)
downloadservice_entitlement-35ab884e53b2b6f8072be2f286617a313e3c38bd.tar.gz
Implement for EsimOsdaOprations
Bug: 177544547 Test: unit tests Change-Id: I0fe91dadc6af7d1a6a72b96d50d0b731586e980d (cherry picked from commit b48a7e91915dc87faeea10ce3b7e0c4c8008ca11)
-rw-r--r--java/com/android/libraries/entitlement/EsimOdsaOperation.java43
-rw-r--r--java/com/android/libraries/entitlement/ServiceEntitlement.java3
-rw-r--r--java/com/android/libraries/entitlement/eapaka/EapAkaApi.java182
-rw-r--r--tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java82
4 files changed, 212 insertions, 98 deletions
diff --git a/java/com/android/libraries/entitlement/EsimOdsaOperation.java b/java/com/android/libraries/entitlement/EsimOdsaOperation.java
index ce764f2..20f4fa3 100644
--- a/java/com/android/libraries/entitlement/EsimOdsaOperation.java
+++ b/java/com/android/libraries/entitlement/EsimOdsaOperation.java
@@ -44,7 +44,7 @@ public abstract class EsimOdsaOperation {
/**
* Indicates that operation_type is not set.
*/
- static final int OPERATION_TYPE_NOT_SET = -1;
+ public static final int OPERATION_TYPE_NOT_SET = -1;
/**
* To activate a subscription, used by {@link #OPERATION_MANAGE_SUBSCRIPTION}.
*/
@@ -138,13 +138,12 @@ public abstract class EsimOdsaOperation {
public abstract String companionTerminalIccid();
/**
- * Returns the ICCID of the companion device. Used by HTTP parameter
- * "companion_terminal_iccid".
+ * Returns the EID of the companion device. Used by HTTP parameter "companion_terminal_eid".
*/
public abstract String companionTerminalEid();
/**
- * Returns the ICCID of the primary device eSIM. Used by HTTP parameter "terminal_eid".
+ * Returns the ICCID of the primary device eSIM. Used by HTTP parameter "terminal_iccid".
*/
public abstract String terminalIccid();
@@ -175,7 +174,22 @@ public abstract class EsimOdsaOperation {
* Returns a new {@link Builder} object.
*/
public static Builder builder() {
- return new AutoValue_EsimOdsaOperation.Builder().setOperationType(OPERATION_TYPE_NOT_SET);
+ return new AutoValue_EsimOdsaOperation.Builder()
+ .setOperation("")
+ .setOperationType(OPERATION_TYPE_NOT_SET)
+ .setCompanionTerminalId("")
+ .setCompanionTerminalVendor("")
+ .setCompanionTerminalModel("")
+ .setCompanionTerminalSoftwareVersion("")
+ .setCompanionTerminalFriendlyName("")
+ .setCompanionTerminalService("")
+ .setCompanionTerminalIccid("")
+ .setCompanionTerminalEid("")
+ .setTerminalIccid("")
+ .setTerminalEid("")
+ .setTargetTerminalId("")
+ .setTargetTerminalIccid("")
+ .setTargetTerminalEid("");
}
/**
@@ -283,39 +297,40 @@ public abstract class EsimOdsaOperation {
public abstract Builder setCompanionTerminalEid(String value);
/**
- * Sets the ICCID of the primary device eSIM. Used by HTTP parameter "terminal_eid" if set.
+ * Sets the ICCID of the primary device eSIM in case of primary SIM not present. Used by
+ * HTTP parameter "terminal_eid" if set.
*
* <p>Used by primary device ODSA operation.
*/
public abstract Builder setTerminalIccid(String value);
/**
- * Sets the eUICC identifier (EID) of the primary device eSIM. Used by HTTP parameter
- * "terminal_eid" if set.
+ * Sets the eUICC identifier (EID) of the primary device eSIM in case of primary SIM not
+ * present. Used by HTTP parameter "terminal_eid" if set.
*
* <p>Used by primary device ODSA operation.
*/
public abstract Builder setTerminalEid(String value);
/**
- * Sets the unique identifier of the primary device eSIM, like the IMEI associated with the
- * eSIM. Used by HTTP parameter "target_terminal_id" if set.
+ * Sets the unique identifier of the primary device eSIM in case of multiple SIM, like the
+ * IMEI associated with the eSIM. Used by HTTP parameter "target_terminal_id" if set.
*
* <p>Used by primary device ODSA operation.
*/
public abstract Builder setTargetTerminalId(String value);
/**
- * Sets the ICCID primary device eSIM. Used by HTTP parameter "target_terminal_iccid" if
- * set.
+ * Sets the ICCID primary device eSIM in case of multiple SIM. Used by HTTP parameter
+ * "target_terminal_iccid" if set.
*
* <p>Used by primary device ODSA operation.
*/
public abstract Builder setTargetTerminalIccid(String value);
/**
- * Sets the eUICC identifier (EID) of the primary device eSIM. Used by HTTP parameter
- * "target_terminal_eid" if set.
+ * Sets the eUICC identifier (EID) of the primary device eSIM in case of multiple SIM. Used
+ * by HTTP parameter "target_terminal_eid" if set.
*
* <p>Used by primary device ODSA operation.
*/
diff --git a/java/com/android/libraries/entitlement/ServiceEntitlement.java b/java/com/android/libraries/entitlement/ServiceEntitlement.java
index 16aeeaa..efb0734 100644
--- a/java/com/android/libraries/entitlement/ServiceEntitlement.java
+++ b/java/com/android/libraries/entitlement/ServiceEntitlement.java
@@ -152,7 +152,6 @@ public class ServiceEntitlement {
public String performEsimOdsa(
String appId, ServiceEntitlementRequest request, EsimOdsaOperation operation)
throws ServiceEntitlementException {
- // TODO(b/177544547): Add implementation
- return null;
+ return eapAkaApi.performEsimOdsaOperation(appId, carrierConfig, request, operation);
}
}
diff --git a/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java b/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java
index dd15426..bf53d87 100644
--- a/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java
+++ b/java/com/android/libraries/entitlement/eapaka/EapAkaApi.java
@@ -29,6 +29,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.libraries.entitlement.CarrierConfig;
+import com.android.libraries.entitlement.EsimOdsaOperation;
import com.android.libraries.entitlement.ServiceEntitlementException;
import com.android.libraries.entitlement.ServiceEntitlementRequest;
import com.android.libraries.entitlement.http.HttpClient;
@@ -48,69 +49,45 @@ public class EapAkaApi {
public static final String EAP_CHALLENGE_RESPONSE = "eap-relay-packet";
- /**
- * Current version of the entitlement configuration.
- */
private static final String VERS = "vers";
- /**
- * Version of the entitlement configuration.
- */
private static final String ENTITLEMENT_VERSION = "entitlement_version";
- /**
- * Unique identifier for the device. Refer to
- * {@link android.telephony.TelephonyManager#getImei()}.
- */
private static final String TERMINAL_ID = "terminal_id";
- /**
- * Device manufacturer.
- */
private static final String TERMINAL_VENDOR = "terminal_vendor";
- /**
- * Device model.
- */
private static final String TERMINAL_MODEL = "terminal_model";
- /**
- * Device software version.
- */
private static final String TERMIAL_SW_VERSION = "terminal_sw_version";
- /**
- * Identifier for the requested entitlement.
- */
private static final String APP = "app";
- /**
- * NAI needed for EAP-AKA authentication.
- */
private static final String EAP_ID = "EAP_ID";
-
private static final String IMSI = "IMSI";
private static final String TOKEN = "token";
- /**
- * Action for the notification registration token.
- */
private static final String NOTIF_ACTION = "notif_action";
- /**
- * Attribute name of the notification registration token.
- */
private static final String NOTIF_TOKEN = "notif_token";
- /**
- * Attribute name of the app version.
- */
private static final String APP_VERSION = "app_version";
- /**
- * Attribute name of the app name.
- */
private static final String APP_NAME = "app_name";
- /**
- * Expected content type of the response body.
- */
+
private static final String ACCEPT_CONTENT_TYPE_JSON_AND_XML =
"application/vnd.gsma.eap-relay.v1.0+json, text/vnd.wap.connectivity-xml";
- /**
- * Required content type to the response body.
- */
private static final String REQUEST_CONTENT_TYPE_JSON =
"application/vnd.gsma.eap-relay.v1.0+json";
+ private static final String OPERATION = "operation";
+ private static final String OPERATION_TYPE = "operation_type";
+ private static final String COMPANION_TERMINAL_ID = "companion_terminal_id";
+ private static final String COMPANION_TERMINAL_VENDOR = "companion_terminal_vendor";
+ private static final String COMPANION_TERMINAL_MODEL = "companion_terminal_model";
+ private static final String COMPANION_TERMINAL_SW_VERSION = "companion_terminal_sw_version";
+ private static final String COMPANION_TERMINAL_FRIENDLY_NAME =
+ "companion_terminal_friendly_name";
+ private static final String COMPANION_TERMINAL_SERVICE = "companion_terminal_service";
+ private static final String COMPANION_TERMINAL_ICCID = "companion_terminal_iccid";
+ private static final String COMPANION_TERMINAL_EID = "companion_terminal_eid";
+
+ private static final String TERMINAL_ICCID = "terminal_iccid";
+ private static final String TERMINAL_EID = "terminal_eid";
+
+ private static final String TARGET_TERMINAL_ID = "target_terminal_id";
+ private static final String TARGET_TERMINAL_ICCID = "target_terminal_iccid";
+ private static final String TARGET_TERMINAL_EID = "target_terminal_eid";
+
// In case of EAP-AKA synchronization failure, we try to recover for at most two times.
private static final int FOLLOW_SYNC_FAILURE_MAX_COUNT = 2;
@@ -138,18 +115,11 @@ public class EapAkaApi {
*/
@Nullable
public String queryEntitlementStatus(ImmutableList<String> appIds,
- CarrierConfig carrierConfig,
- ServiceEntitlementRequest request)
+ CarrierConfig carrierConfig, ServiceEntitlementRequest request)
throws ServiceEntitlementException {
- HttpRequest httpRequest =
- HttpRequest.builder()
- .setUrl(entitlementStatusUrl(appIds, carrierConfig.serverUrl(), request))
- .setRequestMethod(RequestMethod.GET)
- .addRequestProperty(HttpHeaders.ACCEPT, ACCEPT_CONTENT_TYPE_JSON_AND_XML)
- .setTimeoutInSec(carrierConfig.timeoutInSec())
- .setNetwork(carrierConfig.network())
- .build();
- HttpResponse response = mHttpClient.request(httpRequest);
+ Uri.Builder urlBuilder = Uri.parse(carrierConfig.serverUrl()).buildUpon();
+ appendParametersForServiceEntitlementRequest(urlBuilder, appIds, request);
+ HttpResponse response = httpGet(urlBuilder.toString(), carrierConfig);
if (!request.authenticationToken().isEmpty()) {
// Fast Re-Authentication flow with pre-existing auth token
Log.d(TAG, "Fast Re-Authentication");
@@ -210,8 +180,8 @@ public class EapAkaApi {
carrierConfig, newChallenge, followSyncFailureCount - 1);
} else {
throw new ServiceEntitlementException(
- ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE,
- "Unable to recover from EAP-AKA synchroinization failure");
+ ERROR_EAP_AKA_SYNCHRONIZATION_FAILURE,
+ "Unable to recover from EAP-AKA synchroinization failure");
}
} else { // not possible
throw new AssertionError("EapAkaResponse invalid.");
@@ -243,11 +213,36 @@ public class EapAkaApi {
return mHttpClient.request(request);
}
- String entitlementStatusUrl(
- ImmutableList<String> appIds, String serverUrl, ServiceEntitlementRequest request) {
+ /**
+ * Retrieves raw doc of performing ODSA operations. For operation type, see {@link
+ * EsimOdsaOperation}.
+ *
+ * <p>Implementation based on GSMA TS.43-v5.0 6.1.
+ */
+ public String performEsimOdsaOperation(String appId, CarrierConfig carrierConfig,
+ ServiceEntitlementRequest request, EsimOdsaOperation odsaOperation)
+ throws ServiceEntitlementException {
+ Uri.Builder urlBuilder = Uri.parse(carrierConfig.serverUrl()).buildUpon();
+ appendParametersForServiceEntitlementRequest(urlBuilder, ImmutableList.of(appId), request);
+ appendParametersForEsimOdsaOperation(urlBuilder, odsaOperation);
+
+ HttpResponse response = httpGet(urlBuilder.toString(), carrierConfig);
+ if (!request.authenticationToken().isEmpty()) {
+ // Fast Re-Authentication flow with pre-existing auth token
+ Log.d(TAG, "Fast Re-Authentication");
+ return response.body();
+ }
+ // Full Authentication flow
+ Log.d(TAG, "Full Authentication");
+ return respondToEapAkaChallenge(carrierConfig, response, FOLLOW_SYNC_FAILURE_MAX_COUNT)
+ .body();
+ }
+
+ private void appendParametersForServiceEntitlementRequest(
+ Uri.Builder urlBuilder, ImmutableList<String> appIds,
+ ServiceEntitlementRequest request) {
TelephonyManager telephonyManager = mContext.getSystemService(
TelephonyManager.class).createForSubscriptionId(mSimSubscriptionId);
- Uri.Builder urlBuilder = Uri.parse(serverUrl).buildUpon();
if (TextUtils.isEmpty(request.authenticationToken())) {
// EAP_ID required for initial AuthN
urlBuilder.appendQueryParameter(
@@ -276,27 +271,74 @@ public class EapAkaApi {
}
// Optional query parameters, append them if not empty
- if (!TextUtils.isEmpty(request.appVersion())) {
- urlBuilder.appendQueryParameter(APP_VERSION, request.appVersion());
- }
-
- if (!TextUtils.isEmpty(request.appName())) {
- urlBuilder.appendQueryParameter(APP_NAME, request.appName());
- }
+ appendOptionalQueryParameter(urlBuilder, APP_VERSION, request.appVersion());
+ appendOptionalQueryParameter(urlBuilder, APP_NAME, request.appName());
for (String appId : appIds) {
urlBuilder.appendQueryParameter(APP, appId);
}
- return urlBuilder
+ urlBuilder
// Identity and Authentication parameters
.appendQueryParameter(TERMINAL_VENDOR, request.terminalVendor())
.appendQueryParameter(TERMINAL_MODEL, request.terminalModel())
.appendQueryParameter(TERMIAL_SW_VERSION, request.terminalSoftwareVersion())
// General Service parameters
.appendQueryParameter(VERS, Integer.toString(request.configurationVersion()))
- .appendQueryParameter(ENTITLEMENT_VERSION, request.entitlementVersion())
- .toString();
+ .appendQueryParameter(ENTITLEMENT_VERSION, request.entitlementVersion());
+ }
+
+ private void appendParametersForEsimOdsaOperation(
+ Uri.Builder urlBuilder, EsimOdsaOperation odsaOperation) {
+ urlBuilder.appendQueryParameter(OPERATION, odsaOperation.operation());
+ if (odsaOperation.operationType() != EsimOdsaOperation.OPERATION_TYPE_NOT_SET) {
+ urlBuilder.appendQueryParameter(OPERATION_TYPE,
+ Integer.toString(odsaOperation.operationType()));
+ }
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_ID,
+ odsaOperation.companionTerminalId());
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_VENDOR,
+ odsaOperation.companionTerminalVendor());
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_MODEL,
+ odsaOperation.companionTerminalModel());
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_SW_VERSION,
+ odsaOperation.companionTerminalSoftwareVersion());
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_FRIENDLY_NAME,
+ odsaOperation.companionTerminalFriendlyName());
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_SERVICE,
+ odsaOperation.companionTerminalService());
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_ICCID,
+ odsaOperation.companionTerminalIccid());
+ appendOptionalQueryParameter(urlBuilder, COMPANION_TERMINAL_EID,
+ odsaOperation.companionTerminalEid());
+ appendOptionalQueryParameter(urlBuilder, TERMINAL_ICCID,
+ odsaOperation.terminalIccid());
+ appendOptionalQueryParameter(urlBuilder, TERMINAL_EID, odsaOperation.terminalEid());
+ appendOptionalQueryParameter(urlBuilder, TARGET_TERMINAL_ID,
+ odsaOperation.targetTerminalId());
+ appendOptionalQueryParameter(urlBuilder, TARGET_TERMINAL_ICCID,
+ odsaOperation.targetTerminalIccid());
+ appendOptionalQueryParameter(urlBuilder, TARGET_TERMINAL_EID,
+ odsaOperation.targetTerminalEid());
+ }
+
+ private HttpResponse httpGet(String url, CarrierConfig carrierConfig)
+ throws ServiceEntitlementException {
+ HttpRequest httpRequest =
+ HttpRequest.builder()
+ .setUrl(url)
+ .setRequestMethod(RequestMethod.GET)
+ .addRequestProperty(HttpHeaders.ACCEPT, ACCEPT_CONTENT_TYPE_JSON_AND_XML)
+ .setTimeoutInSec(carrierConfig.timeoutInSec())
+ .setNetwork(carrierConfig.network())
+ .build();
+ return mHttpClient.request(httpRequest);
+ }
+
+ private void appendOptionalQueryParameter(Uri.Builder urlBuilder, String key, String value) {
+ if (!TextUtils.isEmpty(value)) {
+ urlBuilder.appendQueryParameter(key, value);
+ }
}
/**
diff --git a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
index cc80ea0..99e8cfa 100644
--- a/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
+++ b/tests/src/com/android/libraries/entitlement/eapaka/EapAkaApiTest.java
@@ -38,6 +38,7 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
import com.android.libraries.entitlement.CarrierConfig;
+import com.android.libraries.entitlement.EsimOdsaOperation;
import com.android.libraries.entitlement.ServiceEntitlement;
import com.android.libraries.entitlement.ServiceEntitlementException;
import com.android.libraries.entitlement.ServiceEntitlementRequest;
@@ -92,13 +93,19 @@ public class EapAkaApiTest {
private static final String ACCEPT_CONTENT_TYPE_JSON_AND_XML =
"application/vnd.gsma.eap-relay.v1.0+json, text/vnd.wap.connectivity-xml";
- @Rule public final MockitoRule rule = MockitoJUnit.rule();
+ @Rule
+ public final MockitoRule rule = MockitoJUnit.rule();
- @Mock private HttpClient mMockHttpClient;
- @Mock private Network mMockNetwork;
- @Mock private TelephonyManager mMockTelephonyManager;
- @Mock private TelephonyManager mMockTelephonyManagerForSubId;
- @Captor private ArgumentCaptor<HttpRequest> mHttpRequestCaptor;
+ @Mock
+ private HttpClient mMockHttpClient;
+ @Mock
+ private Network mMockNetwork;
+ @Mock
+ private TelephonyManager mMockTelephonyManager;
+ @Mock
+ private TelephonyManager mMockTelephonyManagerForSubId;
+ @Captor
+ private ArgumentCaptor<HttpRequest> mHttpRequestCaptor;
private Context mContext;
private EapAkaApi mEapAkaApi;
@@ -117,20 +124,20 @@ public class EapAkaApiTest {
@Test
public void queryEntitlementStatus_hasAuthenticationToken() throws Exception {
- HttpResponse response =
+ HttpResponse httpResponse =
HttpResponse.builder().setContentType(ContentType.XML).setBody(RESPONSE_XML)
.build();
- when(mMockHttpClient.request(any())).thenReturn(response);
+ when(mMockHttpClient.request(any())).thenReturn(httpResponse);
CarrierConfig carrierConfig =
CarrierConfig.builder().setServerUrl(TEST_URL).setNetwork(mMockNetwork).build();
ServiceEntitlementRequest request =
ServiceEntitlementRequest.builder().setAuthenticationToken(TOKEN).build();
- String respopnse =
+ String response =
mEapAkaApi.queryEntitlementStatus(
ImmutableList.of(ServiceEntitlement.APP_VOWIFI), carrierConfig, request);
- assertThat(respopnse).isEqualTo(RESPONSE_XML);
+ assertThat(response).isEqualTo(RESPONSE_XML);
verify(mMockHttpClient).request(mHttpRequestCaptor.capture());
assertThat(mHttpRequestCaptor.getValue().timeoutInSec())
.isEqualTo(CarrierConfig.DEFAULT_TIMEOUT_IN_SEC);
@@ -208,7 +215,7 @@ public class EapAkaApiTest {
ServiceEntitlementException exception = expectThrows(
ServiceEntitlementException.class,
- () -> mEapAkaApi.queryEntitlementStatus(
+ () -> mEapAkaApi.queryEntitlementStatus(
ImmutableList.of(ServiceEntitlement.APP_VOWIFI),
carrierConfig,
request));
@@ -230,7 +237,7 @@ public class EapAkaApiTest {
ServiceEntitlementException exception = expectThrows(
ServiceEntitlementException.class,
- () -> mEapAkaApi.queryEntitlementStatus(
+ () -> mEapAkaApi.queryEntitlementStatus(
ImmutableList.of(ServiceEntitlement.APP_VOWIFI),
carrierConfig,
request));
@@ -276,4 +283,55 @@ public class EapAkaApiTest {
assertThat(mHttpRequestCaptor.getAllValues().get(2).requestProperties())
.containsEntry(HTTP_HEADER_COOKIE, COOKIE_VALUE);
}
+
+ @Test
+ public void performEsimOdsaOperation_noAuthenticationToken_returnsResult() throws Exception {
+ when(mMockTelephonyManagerForSubId.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ EAP_AKA_SECURITY_CONTEXT_REQUEST_EXPECTED))
+ .thenReturn(EAP_AKA_SECURITY_CONTEXT_RESPONSE_SUCCESS);
+ HttpResponse eapChallengeResponse =
+ HttpResponse
+ .builder().setContentType(ContentType.JSON).setBody(EAP_AKA_CHALLENGE)
+ .setCookie(COOKIE_VALUE).build();
+ HttpResponse xmlResponse =
+ HttpResponse.builder().setContentType(ContentType.XML).setBody(RESPONSE_XML)
+ .build();
+ when(mMockHttpClient.request(any()))
+ .thenReturn(eapChallengeResponse).thenReturn(xmlResponse);
+ CarrierConfig carrierConfig = CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request = ServiceEntitlementRequest.builder().build();
+ EsimOdsaOperation operation = EsimOdsaOperation.builder().build();
+
+ String response =
+ mEapAkaApi.performEsimOdsaOperation(ServiceEntitlement.APP_ODSA_COMPANION,
+ carrierConfig, request, operation);
+
+ assertThat(response).isEqualTo(RESPONSE_XML);
+ verify(mMockHttpClient, times(2)).request(any());
+ }
+
+ @Test
+ public void performEsimOdsaOperation_manageSubscription_returnsResult() throws Exception {
+ HttpResponse httpResponse =
+ HttpResponse.builder().setContentType(ContentType.XML).setBody(RESPONSE_XML)
+ .build();
+ when(mMockHttpClient.request(any())).thenReturn(httpResponse);
+ CarrierConfig carrierConfig =
+ CarrierConfig.builder().setServerUrl(TEST_URL).build();
+ ServiceEntitlementRequest request =
+ ServiceEntitlementRequest.builder().setAuthenticationToken(TOKEN).build();
+ EsimOdsaOperation operation = EsimOdsaOperation.builder()
+ .setOperation(EsimOdsaOperation.OPERATION_MANAGE_SUBSCRIPTION)
+ .setOperationType(EsimOdsaOperation.OPERATION_TYPE_SUBSCRIBE)
+ .build();
+
+ String response =
+ mEapAkaApi.performEsimOdsaOperation(ServiceEntitlement.APP_ODSA_COMPANION,
+ carrierConfig, request, operation);
+
+ assertThat(response).isEqualTo(RESPONSE_XML);
+ verify(mMockHttpClient, times(1)).request(any());
+ }
}