1 /*
2  * Copyright 2016, 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 
17 package com.android.managedprovisioning.task;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
20 
21 import static com.android.managedprovisioning.task.DownloadPackageTask.ERROR_DOWNLOAD_FAILED;
22 import static com.android.managedprovisioning.task.DownloadPackageTask.ERROR_OTHER;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.mockito.Matchers.any;
26 import static org.mockito.Matchers.nullable;
27 import static org.mockito.Mockito.doReturn;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.verifyNoMoreInteractions;
31 import static org.mockito.Mockito.when;
32 
33 import android.app.DownloadManager;
34 import android.app.DownloadManager.Query;
35 import android.app.DownloadManager.Request;
36 import android.content.BroadcastReceiver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.database.MatrixCursor;
41 import android.os.Handler;
42 import android.os.Looper;
43 
44 import androidx.test.filters.FlakyTest;
45 import androidx.test.filters.SmallTest;
46 
47 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
48 import com.android.managedprovisioning.common.Utils;
49 import com.android.managedprovisioning.model.PackageDownloadInfo;
50 import com.android.managedprovisioning.model.ProvisioningParams;
51 
52 import org.junit.Before;
53 import org.junit.Ignore;
54 import org.junit.Test;
55 import org.mockito.ArgumentCaptor;
56 import org.mockito.Mock;
57 import org.mockito.MockitoAnnotations;
58 
59 @SmallTest
60 @FlakyTest // TODO: http://b/34117742
61 public class DownloadPackageTaskTest {
62     @Mock private Context mContext;
63     @Mock private AbstractProvisioningTask.Callback mCallback;
64     @Mock private DownloadManager mDownloadManager;
65     @Mock private Utils mUtils;
66 
67     private static final String TEST_PACKAGE_NAME = "sample.package.name";
68     private static final String TEST_PACKAGE_LOCATION = "http://www.some.uri.com";
69     private static final String TEST_LOCAL_FILENAME = "/local/filename";
70     private static final int TEST_USER_ID = 123;
71     private static final byte[] TEST_SIGNATURE = new byte[] {'a', 'b', 'c', 'd'};
72 
73     private static final long TEST_DOWNLOAD_ID = 1234;
74     private static final int PACKAGE_VERSION = 43;
75     private static final PackageDownloadInfo TEST_DOWNLOAD_INFO = new PackageDownloadInfo.Builder()
76             .setLocation(TEST_PACKAGE_LOCATION)
77             .setSignatureChecksum(TEST_SIGNATURE)
78             .setMinVersion(PACKAGE_VERSION)
79             .build();
80     private static final ProvisioningParams PARAMS = new ProvisioningParams.Builder()
81             .setDeviceAdminPackageName(TEST_PACKAGE_NAME)
82             .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
83             .setDeviceAdminDownloadInfo(TEST_DOWNLOAD_INFO)
84             .build();
85 
86     private DownloadPackageTask mTask;
87 
88     @Before
setUp()89     public void setUp() throws Exception {
90         MockitoAnnotations.initMocks(this);
91 
92         when(mContext.getSystemService(Context.DOWNLOAD_SERVICE)).thenReturn(mDownloadManager);
93         when(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME, PACKAGE_VERSION, mContext))
94                 .thenReturn(true);
95 
96         mTask = new DownloadPackageTask(
97                 mUtils,
98                 mContext,
99                 PARAMS,
100                 TEST_DOWNLOAD_INFO,
101                 mCallback,
102                 mock(ProvisioningAnalyticsTracker.class));
103     }
104 
105     @Test
testAlreadyInstalled()106     public void testAlreadyInstalled() throws Exception {
107         // GIVEN the package is already installed, with the right version
108         when(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME, PACKAGE_VERSION, mContext))
109                 .thenReturn(false);
110 
111         // WHEN running the download package task
112         runTask();
113 
114         // THEN we get a success callback directly
115         verifyOnTaskFinished(null);
116         verifyNoMoreInteractions(mCallback);
117     }
118 
119     @Test
testNotConnected()120     public void testNotConnected() throws Exception {
121         // GIVEN we're not connected to a network
122         doReturn(false).when(mUtils).isConnectedToNetwork(mContext);
123 
124         // WHEN running the download package task
125         runTask();
126 
127         // THEN we get an error callback
128         verify(mCallback).onError(mTask, ERROR_OTHER, /* errorMessage= */ null);
129         verifyNoMoreInteractions(mCallback);
130     }
131 
132     @Ignore("b/171307633")
133     @Test
testDownloadFailed()134     public void testDownloadFailed() throws Exception {
135         // GIVEN the download succeeds
136         mockSuccessfulDownload(DownloadManager.STATUS_FAILED);
137 
138         // WHEN running the download package task
139         runTask();
140 
141         // THEN a download receiver was registered
142         BroadcastReceiver receiver = verifyDownloadReceiver();
143 
144         // WHEN invoking download complete
145         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
146 
147         // THEN we get a success callback
148         verify(mCallback).onError(mTask, ERROR_DOWNLOAD_FAILED, /* errorMessage= */ null);
149         verifyNoMoreInteractions(mCallback);
150     }
151 
152     @Ignore("b/171307633")
153     @Test
testDownloadSucceeded()154     public void testDownloadSucceeded() throws Exception {
155         // GIVEN the download succeeds
156         mockSuccessfulDownload(DownloadManager.STATUS_SUCCESSFUL);
157 
158         // WHEN running the download package task
159         runTask();
160 
161         // THEN a download receiver was registered
162         BroadcastReceiver receiver = verifyDownloadReceiver();
163 
164         // WHEN invoking download complete
165         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
166 
167         // THEN we get a success callback
168         verifyOnTaskFinished(TEST_LOCAL_FILENAME);
169         verifyNoMoreInteractions(mCallback);
170     }
171 
172     /** Test that it works fine even if DownloadManager sends the broadcast twice */
173     @Ignore("b/171307633")
174     @Test
testSendBroadcastTwice()175     public void testSendBroadcastTwice() throws Exception {
176         // GIVEN the download succeeds
177         mockSuccessfulDownload(DownloadManager.STATUS_SUCCESSFUL);
178 
179         // WHEN running the download package task
180         runTask();
181 
182         // THEN a download receiver was registered
183         BroadcastReceiver receiver = verifyDownloadReceiver();
184 
185         // WHEN invoking download complete twice
186         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
187         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
188 
189         // THEN we still get only one success callback
190         verifyOnTaskFinished(TEST_LOCAL_FILENAME);
191         verifyNoMoreInteractions(mCallback);
192     }
193 
mockSuccessfulDownload(int downloadStatus)194     private void mockSuccessfulDownload(int downloadStatus) {
195         doReturn(true).when(mUtils).isConnectedToNetwork(any(Context.class));
196         when(mDownloadManager.enqueue(any(Request.class))).thenReturn(TEST_DOWNLOAD_ID);
197         MatrixCursor cursor = new MatrixCursor(new String[]{
198                 DownloadManager.COLUMN_STATUS,
199                 DownloadManager.COLUMN_LOCAL_FILENAME});
200         cursor.addRow(new Object[]{downloadStatus, TEST_LOCAL_FILENAME});
201         when(mDownloadManager.query(any(Query.class))).thenReturn(cursor);
202     }
203 
verifyDownloadReceiver()204     private BroadcastReceiver verifyDownloadReceiver() {
205         verify(mDownloadManager).setAccessFilename(true);
206         ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(
207                 BroadcastReceiver.class);
208         ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(
209                 IntentFilter.class);
210         verify(mContext).registerReceiver(
211                 receiverCaptor.capture(),
212                 filterCaptor.capture(),
213                 nullable(String.class),
214                 any(Handler.class));
215         assertEquals(filterCaptor.getValue().getAction(0),
216                 DownloadManager.ACTION_DOWNLOAD_COMPLETE);
217         return receiverCaptor.getValue();
218     }
219 
verifyOnTaskFinished(String location)220     private void verifyOnTaskFinished(String location) {
221         verify(mCallback).onSuccess(mTask);
222         assertEquals(location, mTask.getPackageLocation());
223     }
224 
runTask()225     private void runTask() {
226         if (Looper.myLooper() == null) {
227             Looper.prepare();
228         }
229         mTask.run(TEST_USER_ID);
230     }
231 }
232