EuiccCardTest.java revision c8845bcb6daffaf186fb2b36edda545f28db2ed6
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony.uicc.euicc;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.fail;
21import static org.mockito.ArgumentMatchers.any;
22import static org.mockito.ArgumentMatchers.eq;
23import static org.mockito.Mockito.times;
24import static org.mockito.Mockito.verify;
25
26import android.os.Handler;
27import android.os.HandlerThread;
28import android.service.euicc.EuiccProfileInfo;
29import android.util.ExceptionUtils;
30import android.util.Log;
31
32import com.android.internal.telephony.CommandsInterface;
33import com.android.internal.telephony.TelephonyTest;
34import com.android.internal.telephony.uicc.IccCardApplicationStatus;
35import com.android.internal.telephony.uicc.IccCardStatus;
36import com.android.internal.telephony.uicc.euicc.apdu.LogicalChannelMocker;
37import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback;
38
39import org.junit.After;
40import org.junit.Before;
41import org.junit.Test;
42import org.mockito.Mock;
43
44import java.util.concurrent.CountDownLatch;
45import java.util.concurrent.TimeUnit;
46
47public class EuiccCardTest extends TelephonyTest {
48    private static final long WAIT_TIMEOUT_MLLIS = 5000;
49
50    private static class ResultCaptor<T> extends AsyncResultCallback<T> {
51        public T result;
52        public Throwable exception;
53
54        private CountDownLatch mLatch;
55
56        private ResultCaptor() {
57            mLatch = new CountDownLatch(1);
58        }
59
60        public void await() {
61            try {
62                mLatch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS);
63            } catch (InterruptedException e) {
64                fail("Execution is interrupted: " + e);
65            }
66        }
67
68        @Override
69        public void onResult(T r) {
70            result = r;
71            mLatch.countDown();
72        }
73
74        @Override
75        public void onException(Throwable e) {
76            exception = e;
77            mLatch.countDown();
78        }
79    }
80
81    private class UiccCardHandlerThread extends HandlerThread {
82        private UiccCardHandlerThread(String name) {
83            super(name);
84        }
85
86        @Override
87        public void onLooperPrepared() {
88            mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, mMockIccCardStatus,
89                    0 /* phoneId */);
90            mHandler = new Handler(mTestHandlerThread.getLooper());
91            setReady(true);
92        }
93    }
94
95    @Mock
96    private CommandsInterface mMockCi;
97    @Mock
98    private IccCardStatus mMockIccCardStatus;
99
100    private UiccCardHandlerThread mTestHandlerThread;
101    private Handler mHandler;
102
103    private EuiccCard mEuiccCard;
104
105    @Before
106    public void setUp() throws Exception {
107        super.setUp(getClass().getSimpleName());
108
109        mMockIccCardStatus.mApplications = new IccCardApplicationStatus[]{};
110        mMockIccCardStatus.mCdmaSubscriptionAppIndex =
111                mMockIccCardStatus.mImsSubscriptionAppIndex =
112                        mMockIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1;
113        mMockIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
114
115        mTestHandlerThread = new UiccCardHandlerThread(getClass().getSimpleName());
116        mTestHandlerThread.start();
117
118        waitUntilReady();
119    }
120
121    @After
122    public void tearDown() throws Exception {
123        mTestHandlerThread.quit();
124        super.tearDown();
125    }
126
127    private void assertUnexpectedException(Throwable e) {
128        if (e != null) {
129            fail("Unexpected exception: " + ExceptionUtils.getCompleteMessage(e) + "\n-----\n"
130                    + Log.getStackTraceString(e.getCause()) + "-----");
131        }
132    }
133
134    @Test
135    public void testGetAllProfiles() {
136        int channel = mockLogicalChannelResponses(
137                "BF2D14A012E3105A0A896700000000004523019F7001019000");
138
139        ResultCaptor<EuiccProfileInfo[]> resultCaptor = new ResultCaptor<>();
140        mEuiccCard.getAllProfiles(resultCaptor, mHandler);
141        resultCaptor.await();
142
143        assertUnexpectedException(resultCaptor.exception);
144        EuiccProfileInfo[] profiles = resultCaptor.result;
145        assertEquals(1, profiles.length);
146        assertEquals("98760000000000543210", profiles[0].getIccid());
147        assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profiles[0].getState());
148        verifyStoreData(channel, "BF2D0D5C0B5A909192B79F709599BF76");
149    }
150
151    @Test
152    public void testFSuffix() {
153        // iccID is 987600000000005432FF.
154        int channel = mockLogicalChannelResponses(
155                "BF2D14A012E3105A0A896700000000004523FF9F7001019000");
156
157        ResultCaptor<EuiccProfileInfo[]> resultCaptor = new ResultCaptor<>();
158        mEuiccCard.getAllProfiles(resultCaptor, mHandler);
159        resultCaptor.await();
160
161        assertUnexpectedException(resultCaptor.exception);
162        EuiccProfileInfo[] profiles = resultCaptor.result;
163        assertEquals(1, profiles.length);
164        assertEquals("987600000000005432", profiles[0].getIccid());
165        assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profiles[0].getState());
166        verifyStoreData(channel, "BF2D0D5C0B5A909192B79F709599BF76");
167    }
168
169    @Test
170    public void testDisableProfile() {
171        int channel = mockLogicalChannelResponses("BF32038001009000");
172
173        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
174        mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler);
175        resultCaptor.await();
176
177        assertUnexpectedException(resultCaptor.exception);
178        verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF");
179    }
180
181    @Test
182    public void testDisableProfile_SimRefresh() {
183        int channel = mockLogicalChannelResponses("6106", "6f00");
184
185        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
186        mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler);
187        resultCaptor.await();
188
189        assertUnexpectedException(resultCaptor.exception);
190        verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF");
191    }
192
193    @Test
194    public void testDisableProfile_Error() {
195        int channel = mockLogicalChannelResponses("BF32038001039000");
196
197        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
198        mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler);
199        resultCaptor.await();
200
201        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
202        verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF");
203    }
204
205    private void verifyStoreData(int channel, String command) {
206        verify(mMockCi, times(1))
207                .iccTransmitApduLogicalChannel(eq(channel), eq(0x80 | channel), eq(0xE2), eq(0x91),
208                        eq(0), eq(command.length() / 2), eq(command), any());
209    }
210
211    private int mockLogicalChannelResponses(Object... responses) {
212        int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi,
213                "E00582030200009000");
214        LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, responses);
215        LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel);
216        return channel;
217    }
218}
219