• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
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 package com.google.android.libraries.mobiledatadownload.file.common.testing;
17 
18 import static org.mockito.AdditionalAnswers.returnsSecondArg;
19 import static org.mockito.ArgumentMatchers.any;
20 import static org.mockito.Mockito.when;
21 
22 import android.net.Uri;
23 import android.util.Pair;
24 import com.google.android.libraries.mobiledatadownload.file.spi.Backend;
25 import com.google.android.libraries.mobiledatadownload.file.spi.Monitor;
26 import com.google.android.libraries.mobiledatadownload.file.spi.Transform;
27 import java.io.ByteArrayInputStream;
28 import java.io.ByteArrayOutputStream;
29 import java.io.Closeable;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import org.junit.Before;
34 import org.junit.Rule;
35 import org.mockito.Mock;
36 import org.mockito.junit.MockitoJUnit;
37 import org.mockito.junit.MockitoRule;
38 
39 /**
40  * Base class with common code for file storage tests.
41  *
42  * <p>Mocks use "file", "cns", "compress" and "encrypt" to make the tests easier to follow, but they
43  * do not implement any of said behaviors.
44  */
45 public abstract class FileStorageTestBase {
46 
47   @Rule public final MockitoRule mockito = MockitoJUnit.rule();
48 
49   protected final Uri file1Uri;
50   protected final Uri file2Uri;
51   protected final Uri file3Uri;
52   protected final Uri dir1Uri;
53   protected final String file1Filename;
54   protected final String file2Filename;
55   protected final Uri cnsUri;
56   protected final Uri file1CompressUri;
57   protected final Uri file1CompressUriWithEncoded;
58   protected final Uri file2CompressEncryptUri;
59   protected final Uri file3IdentityUri;
60   protected final Uri dir2CompressUri;
61   protected final Uri uriWithCompressParam;
62   protected final Uri uriWithCompressParamWithEncoded;
63   protected final Uri uriWithEncryptParam;
64   protected final Uri uriWithIdentityParam;
65 
66   private static final InputStream EMPTY_INPUT = new ByteArrayInputStream(new byte[] {});
67   private static final OutputStream NULL_OUTPUT =
68       new OutputStream() {
69         @Override
70         public void write(int i) throws IOException {
71           // ignore
72         }
73       };
74 
75   @Mock protected Backend fileBackend;
76   @Mock protected Backend cnsBackend;
77   @Mock protected Transform compressTransform;
78   @Mock protected Transform encryptTransform;
79   @Mock protected Monitor countingMonitor;
80 
81   protected InputStream compressInputStream = new ByteArrayInputStream(new byte[] {});
82   protected InputStream encryptInputStream = new ByteArrayInputStream(new byte[] {});
83   protected OutputStream compressOutputStream = new ByteArrayOutputStream();
84   protected OutputStream encryptOutputStream = new ByteArrayOutputStream();
85   protected Closeable closeable = () -> {};
86 
87   protected final Transform identityTransform =
88       new Transform() {
89         @Override
90         public String name() {
91           return "identity";
92         }
93       };
94 
FileStorageTestBase()95   protected FileStorageTestBase() {
96     // Robolectric doesn't seem to work with static initializers.
97     file1Uri = Uri.parse("file:///file1");
98     file2Uri = Uri.parse("file:///file2");
99     file3Uri = Uri.parse("file:///file3");
100     dir1Uri = Uri.parse("file:///dir1/");
101     file1Filename = "file1";
102     file2Filename = "file2";
103     cnsUri = Uri.parse("cns:///1");
104     file1CompressUri = Uri.parse("file:///file1#transform=compress");
105     // Percent encoding of fragment params is not in our spec (<internal>), but
106     // implemented anyway.
107     file1CompressUriWithEncoded = Uri.parse("file:///file1#transform=compress(k%3D=%28v%29)");
108     file2CompressEncryptUri = Uri.parse("file:///file2#transform=compress+encrypt");
109     file3IdentityUri = Uri.parse("file:///file3#transform=identity");
110     dir2CompressUri = Uri.parse("file:///dir2/#transform=compress");
111     uriWithCompressParam = Uri.parse("#transform=compress");
112     uriWithCompressParamWithEncoded = Uri.parse("#transform=compress(k%3D=%28v%29)");
113     uriWithEncryptParam = Uri.parse("#transform=encrypt");
114     uriWithIdentityParam = Uri.parse("#transform=identity");
115   }
116 
117   @Before
initMocksAndCreateFileStorage()118   public void initMocksAndCreateFileStorage() throws Exception {
119     when(fileBackend.name()).thenReturn("file");
120     when(fileBackend.openForRead(any())).thenReturn(EMPTY_INPUT);
121     when(fileBackend.openForWrite(any())).thenReturn(NULL_OUTPUT);
122     when(fileBackend.openForAppend(any())).thenReturn(NULL_OUTPUT);
123     when(cnsBackend.openForRead(any())).thenReturn(EMPTY_INPUT);
124     when(cnsBackend.openForWrite(any())).thenReturn(NULL_OUTPUT);
125     when(cnsBackend.openForAppend(any())).thenReturn(NULL_OUTPUT);
126     when(cnsBackend.name()).thenReturn("cns");
127     when(compressTransform.name()).thenReturn("compress");
128     when(compressTransform.encode(any(), any())).then(returnsSecondArg());
129     when(compressTransform.decode(any(), any())).then(returnsSecondArg());
130     when(encryptTransform.name()).thenReturn("encrypt");
131     when(encryptTransform.encode(any(), any())).then(returnsSecondArg());
132     when(encryptTransform.decode(any(), any())).then(returnsSecondArg());
133     when(fileBackend.openForNativeRead(any()))
134         .thenReturn(Pair.create(Uri.parse("fd:123"), closeable));
135     when(cnsBackend.openForNativeRead(any()))
136         .thenReturn(Pair.create(Uri.parse("fd:456"), closeable));
137     initStorage();
138   }
139 
140   // Called after mocks are initialized to create the FileStorage instance.
141   // Required b/c order of @Befores is non-deterministic.
initStorage()142   protected abstract void initStorage();
143 }
144