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.server.backup.testing; 18 19import static com.android.server.backup.testing.TestUtils.uncheck; 20 21import static org.junit.Assert.fail; 22import static org.mockito.ArgumentMatchers.any; 23import static org.mockito.ArgumentMatchers.eq; 24import static org.mockito.Mockito.mock; 25import static org.mockito.Mockito.when; 26 27import static java.util.stream.Collectors.toList; 28 29import android.annotation.Nullable; 30import android.content.ComponentName; 31import android.content.Intent; 32import android.content.pm.ResolveInfo; 33import android.content.pm.ServiceInfo; 34import android.os.RemoteException; 35import android.support.annotation.IntDef; 36 37import com.android.internal.backup.IBackupTransport; 38import com.android.server.backup.TransportManager; 39import com.android.server.backup.transport.TransportClient; 40import com.android.server.backup.transport.TransportNotAvailableException; 41import com.android.server.backup.transport.TransportNotRegisteredException; 42 43import org.robolectric.shadows.ShadowPackageManager; 44 45import java.util.List; 46import java.util.stream.Stream; 47 48public 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