blob: 0affacd114bf36611457aa2916e6b2a94b552dd3 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.backup.encryption.tasks;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static java.util.stream.Collectors.toList;
import com.android.server.backup.encryption.FullRestoreDownloader;
import com.google.common.io.Files;
import com.google.common.primitives.Bytes;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@RunWith(RobolectricTestRunner.class)
public class EncryptedFullRestoreTaskTest {
private static final int TEST_BUFFER_SIZE = 10;
private static final byte[] TEST_ENCRYPTED_DATA = {1, 2, 3, 4, 5, 6};
private static final byte[] TEST_DECRYPTED_DATA = fakeDecrypt(TEST_ENCRYPTED_DATA);
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Mock private BackupFileDecryptorTask mDecryptorTask;
private File mFolder;
private FakeFullRestoreDownloader mFullRestorePackageWrapper;
private EncryptedFullRestoreTask mTask;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mFolder = temporaryFolder.newFolder();
mFullRestorePackageWrapper = new FakeFullRestoreDownloader(TEST_ENCRYPTED_DATA);
doAnswer(
invocation -> {
File source = invocation.getArgument(0);
DecryptedChunkOutput target = invocation.getArgument(1);
byte[] decrypted = fakeDecrypt(Files.toByteArray(source));
target.open();
target.processChunk(decrypted, decrypted.length);
target.close();
return null;
})
.when(mDecryptorTask)
.decryptFile(any(), any());
mTask = new EncryptedFullRestoreTask(mFolder, mFullRestorePackageWrapper, mDecryptorTask);
}
@Test
public void readNextChunk_downloadsAndDecryptsBackup() throws Exception {
ByteArrayOutputStream decryptedOutput = new ByteArrayOutputStream();
byte[] buffer = new byte[TEST_BUFFER_SIZE];
int bytesRead = mTask.readNextChunk(buffer);
while (bytesRead != -1) {
decryptedOutput.write(buffer, 0, bytesRead);
bytesRead = mTask.readNextChunk(buffer);
}
assertThat(decryptedOutput.toByteArray()).isEqualTo(TEST_DECRYPTED_DATA);
}
@Test
public void finish_deletesTemporaryFiles() throws Exception {
mTask.readNextChunk(new byte[10]);
mTask.finish(FullRestoreDownloader.FinishType.UNKNOWN_FINISH);
assertThat(mFolder.listFiles()).isEmpty();
}
/** Fake package wrapper which returns data from a byte array. */
private static class FakeFullRestoreDownloader extends FullRestoreDownloader {
private final ByteArrayInputStream mData;
FakeFullRestoreDownloader(byte[] data) {
// We override all methods of the superclass, so it does not require any collaborators.
super();
mData = new ByteArrayInputStream(data);
}
@Override
public int readNextChunk(byte[] buffer) throws IOException {
return mData.read(buffer);
}
@Override
public void finish(FinishType finishType) {
// Nothing to do.
}
}
/** Fake decrypts a byte array by subtracting 1 from each byte. */
private static byte[] fakeDecrypt(byte[] input) {
return Bytes.toArray(Bytes.asList(input).stream().map(b -> b + 1).collect(toList()));
}
}