Home | History | Annotate | Download | only in testing
      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 
     17 package com.android.server.backup.testing;
     18 
     19 import static com.android.server.backup.testing.TestUtils.uncheck;
     20 
     21 import static org.junit.Assert.fail;
     22 import static org.mockito.ArgumentMatchers.any;
     23 import static org.mockito.ArgumentMatchers.eq;
     24 import static org.mockito.Mockito.mock;
     25 import static org.mockito.Mockito.when;
     26 
     27 import static java.util.stream.Collectors.toList;
     28 
     29 import android.annotation.Nullable;
     30 import android.content.ComponentName;
     31 import android.content.Intent;
     32 import android.content.pm.ResolveInfo;
     33 import android.content.pm.ServiceInfo;
     34 import android.os.RemoteException;
     35 import android.support.annotation.IntDef;
     36 
     37 import com.android.internal.backup.IBackupTransport;
     38 import com.android.server.backup.TransportManager;
     39 import com.android.server.backup.transport.TransportClient;
     40 import com.android.server.backup.transport.TransportNotAvailableException;
     41 import com.android.server.backup.transport.TransportNotRegisteredException;
     42 
     43 import org.robolectric.shadows.ShadowPackageManager;
     44 
     45 import java.util.List;
     46 import java.util.stream.Stream;
     47 
     48 public class TransportTestUtils {
     49     /**
     50      * Differently from {@link #setUpTransports(TransportManager, TransportData...)}, which
     51      * configures {@link TransportManager}, this is meant to mock the environment for a real
     52      * TransportManager.
     53      */
     54     public static void setUpTransportsForTransportManager(
     55             ShadowPackageManager shadowPackageManager, TransportData... transports)
     56             throws Exception {
     57         for (TransportData transport : transports) {
     58             ComponentName transportComponent = transport.getTransportComponent();
     59             String packageName = transportComponent.getPackageName();
     60             ResolveInfo resolveInfo = resolveInfo(transportComponent);
     61             shadowPackageManager.addResolveInfoForIntent(transportIntent(), resolveInfo);
     62             shadowPackageManager.addResolveInfoForIntent(
     63                     transportIntent().setPackage(packageName), resolveInfo);
     64         }
     65     }
     66 
     67     private static Intent transportIntent() {
     68         return new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
     69     }
     70 
     71     private static ResolveInfo resolveInfo(ComponentName transportComponent) {
     72         ResolveInfo resolveInfo = new ResolveInfo();
     73         resolveInfo.serviceInfo = new ServiceInfo();
     74         resolveInfo.serviceInfo.packageName = transportComponent.getPackageName();
     75         resolveInfo.serviceInfo.name = transportComponent.getClassName();
     76         return resolveInfo;
     77     }
     78 
     79     /** {@code transportName} has to be in the {@link ComponentName} format (with '/') */
     80     public static TransportMock setUpCurrentTransport(
     81             TransportManager transportManager, TransportData transport) throws Exception {
     82         TransportMock transportMock = setUpTransports(transportManager, transport).get(0);
     83         if (transportMock.transportClient != null) {
     84             when(transportManager.getCurrentTransportClient(any()))
     85                     .thenReturn(transportMock.transportClient);
     86         }
     87         return transportMock;
     88     }
     89 
     90     /** @see #setUpTransport(TransportManager, TransportData) */
     91     public static List<TransportMock> setUpTransports(
     92             TransportManager transportManager, TransportData... transports) throws Exception {
     93         return Stream.of(transports)
     94                 .map(transport -> uncheck(() -> setUpTransport(transportManager, transport)))
     95                 .collect(toList());
     96     }
     97 
     98     public static TransportMock setUpTransport(
     99             TransportManager transportManager, TransportData transport) throws Exception {
    100         int status = transport.transportStatus;
    101         String transportName = transport.transportName;
    102         ComponentName transportComponent = transport.getTransportComponent();
    103         String transportDirName = transport.transportDirName;
    104 
    105         TransportMock transportMock = mockTransport(transport);
    106         if (status == TransportStatus.REGISTERED_AVAILABLE
    107                 || status == TransportStatus.REGISTERED_UNAVAILABLE) {
    108             // Transport registered
    109             when(transportManager.getTransportClient(eq(transportName), any()))
    110                     .thenReturn(transportMock.transportClient);
    111             when(transportManager.getTransportClientOrThrow(eq(transportName), any()))
    112                     .thenReturn(transportMock.transportClient);
    113             when(transportManager.getTransportName(transportComponent)).thenReturn(transportName);
    114             when(transportManager.getTransportDirName(eq(transportName)))
    115                     .thenReturn(transportDirName);
    116             when(transportManager.getTransportDirName(eq(transportComponent)))
    117                     .thenReturn(transportDirName);
    118             when(transportManager.isTransportRegistered(eq(transportName))).thenReturn(true);
    119             // TODO: Mock rest of description methods
    120         } else {
    121             // Transport not registered
    122             when(transportManager.getTransportClient(eq(transportName), any())).thenReturn(null);
    123             when(transportManager.getTransportClientOrThrow(eq(transportName), any()))
    124                     .thenThrow(TransportNotRegisteredException.class);
    125             when(transportManager.getTransportName(transportComponent))
    126                     .thenThrow(TransportNotRegisteredException.class);
    127             when(transportManager.getTransportDirName(eq(transportName)))
    128                     .thenThrow(TransportNotRegisteredException.class);
    129             when(transportManager.getTransportDirName(eq(transportComponent)))
    130                     .thenThrow(TransportNotRegisteredException.class);
    131             when(transportManager.isTransportRegistered(eq(transportName))).thenReturn(false);
    132         }
    133         return transportMock;
    134     }
    135 
    136     public static TransportMock mockTransport(TransportData transport) throws Exception {
    137         final TransportClient transportClientMock;
    138         int status = transport.transportStatus;
    139         ComponentName transportComponent = transport.getTransportComponent();
    140         if (status == TransportStatus.REGISTERED_AVAILABLE
    141                 || status == TransportStatus.REGISTERED_UNAVAILABLE) {
    142             // Transport registered
    143             transportClientMock = mock(TransportClient.class);
    144             when(transportClientMock.getTransportComponent()).thenReturn(transportComponent);
    145             if (status == TransportStatus.REGISTERED_AVAILABLE) {
    146                 // Transport registered and available
    147                 IBackupTransport transportMock = mockTransportBinder(transport);
    148                 when(transportClientMock.connectOrThrow(any())).thenReturn(transportMock);
    149                 when(transportClientMock.connect(any())).thenReturn(transportMock);
    150 
    151                 return new TransportMock(transportClientMock, transportMock);
    152             } else {
    153                 // Transport registered but unavailable
    154                 when(transportClientMock.connectOrThrow(any()))
    155                         .thenThrow(TransportNotAvailableException.class);
    156                 when(transportClientMock.connect(any())).thenReturn(null);
    157 
    158                 return new TransportMock(transportClientMock, null);
    159             }
    160         } else {
    161             // Transport not registered
    162             return new TransportMock(null, null);
    163         }
    164     }
    165 
    166     private static IBackupTransport mockTransportBinder(TransportData transport) throws Exception {
    167         IBackupTransport transportBinder = mock(IBackupTransport.class);
    168         try {
    169             when(transportBinder.name()).thenReturn(transport.transportName);
    170             when(transportBinder.transportDirName()).thenReturn(transport.transportDirName);
    171             when(transportBinder.configurationIntent()).thenReturn(transport.configurationIntent);
    172             when(transportBinder.currentDestinationString())
    173                     .thenReturn(transport.currentDestinationString);
    174             when(transportBinder.dataManagementIntent()).thenReturn(transport.dataManagementIntent);
    175             when(transportBinder.dataManagementLabel()).thenReturn(transport.dataManagementLabel);
    176         } catch (RemoteException e) {
    177             fail("RemoteException?");
    178         }
    179         return transportBinder;
    180     }
    181 
    182     public static class TransportMock {
    183         @Nullable public final TransportClient transportClient;
    184         @Nullable public final IBackupTransport transport;
    185 
    186         private TransportMock(
    187                 @Nullable TransportClient transportClient, @Nullable IBackupTransport transport) {
    188             this.transportClient = transportClient;
    189             this.transport = transport;
    190         }
    191     }
    192 
    193     @IntDef({
    194         TransportStatus.REGISTERED_AVAILABLE,
    195         TransportStatus.REGISTERED_UNAVAILABLE,
    196         TransportStatus.UNREGISTERED
    197     })
    198     public @interface TransportStatus {
    199         int REGISTERED_AVAILABLE = 0;
    200         int REGISTERED_UNAVAILABLE = 1;
    201         int UNREGISTERED = 2;
    202     }
    203 
    204     private TransportTestUtils() {}
    205 }
    206