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                 mCallback,
101                 mock(ProvisioningAnalyticsTracker.class));
102     }
103 
104     @Test
testAlreadyInstalled()105     public void testAlreadyInstalled() throws Exception {
106         // GIVEN the package is already installed, with the right version
107         when(mUtils.packageRequiresUpdate(TEST_PACKAGE_NAME, PACKAGE_VERSION, mContext))
108                 .thenReturn(false);
109 
110         // WHEN running the download package task
111         runTask();
112 
113         // THEN we get a success callback directly
114         verifyOnTaskFinished(null);
115         verifyNoMoreInteractions(mCallback);
116     }
117 
118     @Test
testNotConnected()119     public void testNotConnected() throws Exception {
120         // GIVEN we're not connected to a network
121         doReturn(false).when(mUtils).isConnectedToNetwork(mContext);
122 
123         // WHEN running the download package task
124         runTask();
125 
126         // THEN we get an error callback
127         verify(mCallback).onError(mTask, ERROR_OTHER);
128         verifyNoMoreInteractions(mCallback);
129     }
130 
131     @Ignore("b/171307633")
132     @Test
testDownloadFailed()133     public void testDownloadFailed() throws Exception {
134         // GIVEN the download succeeds
135         mockSuccessfulDownload(DownloadManager.STATUS_FAILED);
136 
137         // WHEN running the download package task
138         runTask();
139 
140         // THEN a download receiver was registered
141         BroadcastReceiver receiver = verifyDownloadReceiver();
142 
143         // WHEN invoking download complete
144         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
145 
146         // THEN we get a success callback
147         verify(mCallback).onError(mTask, ERROR_DOWNLOAD_FAILED);
148         verifyNoMoreInteractions(mCallback);
149     }
150 
151     @Ignore("b/171307633")
152     @Test
testDownloadSucceeded()153     public void testDownloadSucceeded() throws Exception {
154         // GIVEN the download succeeds
155         mockSuccessfulDownload(DownloadManager.STATUS_SUCCESSFUL);
156 
157         // WHEN running the download package task
158         runTask();
159 
160         // THEN a download receiver was registered
161         BroadcastReceiver receiver = verifyDownloadReceiver();
162 
163         // WHEN invoking download complete
164         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
165 
166         // THEN we get a success callback
167         verifyOnTaskFinished(TEST_LOCAL_FILENAME);
168         verifyNoMoreInteractions(mCallback);
169     }
170 
171     /** Test that it works fine even if DownloadManager sends the broadcast twice */
172     @Ignore("b/171307633")
173     @Test
testSendBroadcastTwice()174     public void testSendBroadcastTwice() throws Exception {
175         // GIVEN the download succeeds
176         mockSuccessfulDownload(DownloadManager.STATUS_SUCCESSFUL);
177 
178         // WHEN running the download package task
179         runTask();
180 
181         // THEN a download receiver was registered
182         BroadcastReceiver receiver = verifyDownloadReceiver();
183 
184         // WHEN invoking download complete twice
185         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
186         receiver.onReceive(mContext, new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
187 
188         // THEN we still get only one success callback
189         verifyOnTaskFinished(TEST_LOCAL_FILENAME);
190         verifyNoMoreInteractions(mCallback);
191     }
192 
mockSuccessfulDownload(int downloadStatus)193     private void mockSuccessfulDownload(int downloadStatus) {
194         doReturn(true).when(mUtils).isConnectedToNetwork(any(Context.class));
195         when(mDownloadManager.enqueue(any(Request.class))).thenReturn(TEST_DOWNLOAD_ID);
196         MatrixCursor cursor = new MatrixCursor(new String[]{
197                 DownloadManager.COLUMN_STATUS,
198                 DownloadManager.COLUMN_LOCAL_FILENAME});
199         cursor.addRow(new Object[]{downloadStatus, TEST_LOCAL_FILENAME});
200         when(mDownloadManager.query(any(Query.class))).thenReturn(cursor);
201     }
202 
verifyDownloadReceiver()203     private BroadcastReceiver verifyDownloadReceiver() {
204         verify(mDownloadManager).setAccessFilename(true);
205         ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(
206                 BroadcastReceiver.class);
207         ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(
208                 IntentFilter.class);
209         verify(mContext).registerReceiver(
210                 receiverCaptor.capture(),
211                 filterCaptor.capture(),
212                 nullable(String.class),
213                 any(Handler.class));
214         assertEquals(filterCaptor.getValue().getAction(0),
215                 DownloadManager.ACTION_DOWNLOAD_COMPLETE);
216         return receiverCaptor.getValue();
217     }
218 
verifyOnTaskFinished(String location)219     private void verifyOnTaskFinished(String location) {
220         verify(mCallback).onSuccess(mTask);
221         assertEquals(location, mTask.getPackageLocation());
222     }
223 
runTask()224     private void runTask() {
225         if (Looper.myLooper() == null) {
226             Looper.prepare();
227         }
228         mTask.run(TEST_USER_ID);
229     }
230 }
231