• 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.openers;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static org.junit.Assert.assertThrows;
20 import static org.mockito.Mockito.doThrow;
21 import static org.mockito.Mockito.spy;
22 
23 import android.net.Uri;
24 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
25 import com.google.android.libraries.mobiledatadownload.file.backends.JavaFileBackend;
26 import com.google.android.libraries.mobiledatadownload.file.common.testing.FakeFileBackend;
27 import com.google.android.libraries.mobiledatadownload.file.common.testing.TemporaryUri;
28 import com.google.android.libraries.mobiledatadownload.file.spi.Backend;
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33 import org.junit.Rule;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.robolectric.RobolectricTestRunner;
37 import org.robolectric.annotation.Config;
38 
39 @RunWith(RobolectricTestRunner.class)
40 public final class RecursiveDeleteOpenerTest {
41 
42   @Rule public TemporaryUri tmpUri = new TemporaryUri();
43 
44   private final SynchronousFileStorage storage =
45       new SynchronousFileStorage(Arrays.asList(new JavaFileBackend()));
46 
47   @Test
open_nonExistentUri_throwsException()48   public void open_nonExistentUri_throwsException() throws IOException {
49     Uri dir = tmpUri.newDirectoryUri();
50     Uri missing = Uri.withAppendedPath(dir, "a");
51     assertThrows(IOException.class, () -> storage.open(missing, RecursiveDeleteOpener.create()));
52   }
53 
54   @Test
open_file_deletesFile()55   public void open_file_deletesFile() throws IOException {
56     Uri file = tmpUri.newUri();
57     storage.open(file, WriteStringOpener.create("junk"));
58 
59     storage.open(file, RecursiveDeleteOpener.create());
60 
61     assertThat(storage.exists(file)).isFalse();
62   }
63 
64   @Test
open_emptyDirectory_deletesDirectory()65   public void open_emptyDirectory_deletesDirectory() throws IOException {
66     Uri dir = tmpUri.newDirectoryUri();
67 
68     storage.open(dir, RecursiveDeleteOpener.create());
69 
70     assertThat(storage.exists(dir)).isFalse();
71   }
72 
73   @Test
open_nonEmptyDirectory_deletesChildrenThenDirectory()74   public void open_nonEmptyDirectory_deletesChildrenThenDirectory() throws IOException {
75     Uri dir = tmpUri.newDirectoryUri();
76 
77     // TODO: consider adding FileUri.fromFileUri to make this cleaner
78     Uri file0 = Uri.withAppendedPath(dir, "a");
79     Uri file1 = Uri.withAppendedPath(dir, "b");
80     storage.open(file0, WriteStringOpener.create("junk"));
81     storage.open(file1, WriteStringOpener.create("junk"));
82 
83     storage.open(dir, RecursiveDeleteOpener.create());
84 
85     assertThat(storage.exists(file0)).isFalse();
86     assertThat(storage.exists(file1)).isFalse();
87     assertThat(storage.exists(dir)).isFalse();
88   }
89 
90   @Test
open_directoryTree_recursesMultipleLevels()91   public void open_directoryTree_recursesMultipleLevels() throws IOException {
92     Uri dir = tmpUri.newDirectoryUri();
93 
94     Uri subDir = Uri.withAppendedPath(dir, "subDir");
95     Uri subSubDir = Uri.withAppendedPath(subDir, "subSubDir");
96     Uri emptySubDir = Uri.withAppendedPath(dir, "emptySubDir");
97     storage.createDirectory(subDir);
98     storage.createDirectory(subSubDir);
99     storage.createDirectory(emptySubDir);
100 
101     List<Uri> fileUris = new ArrayList<>();
102     for (int i = 0; i != 5; i++) {
103       Uri uri = Uri.withAppendedPath(dir, Integer.toString(i));
104       storage.open(uri, WriteStringOpener.create(Integer.toString(i)));
105       fileUris.add(uri);
106     }
107 
108     storage.open(dir, RecursiveDeleteOpener.create());
109 
110     assertThat(storage.exists(dir)).isFalse();
111     assertThat(storage.exists(subDir)).isFalse();
112     assertThat(storage.exists(subSubDir)).isFalse();
113     assertThat(storage.exists(emptySubDir)).isFalse();
114     for (Uri uri : fileUris) {
115       assertThat(storage.exists(uri)).isFalse();
116     }
117   }
118 
119   @Test
120   @Config(sdk = 19) // addSuppressed is only available on SDK 19+
open_suppressesExceptionsUntilEnd()121   public void open_suppressesExceptionsUntilEnd() throws Exception {
122     Backend spyBackend = spy(new FakeFileBackend());
123     SynchronousFileStorage storage = new SynchronousFileStorage(Arrays.asList(spyBackend));
124 
125     Uri dir = tmpUri.newDirectoryUri();
126 
127     Uri deletableFile0 = Uri.withAppendedPath(dir, "a");
128     Uri undeletableFile = Uri.withAppendedPath(dir, "subDir/b");
129     Uri deletableFile1 = Uri.withAppendedPath(dir, "subDir/subSubDir/c");
130     storage.open(undeletableFile, WriteStringOpener.create("a"));
131     storage.open(deletableFile0, WriteStringOpener.create("b"));
132     storage.open(deletableFile1, WriteStringOpener.create("c"));
133 
134     doThrow(IOException.class).when(spyBackend).deleteFile(undeletableFile);
135 
136     IOException expected =
137         assertThrows(IOException.class, () -> storage.open(dir, RecursiveDeleteOpener.create()));
138 
139     assertThat(expected.getSuppressed()).hasLength(3); // one for the file, two for the directories
140 
141     assertThat(storage.exists(deletableFile0)).isFalse();
142     assertThat(storage.exists(deletableFile1)).isFalse();
143     assertThat(storage.exists(undeletableFile)).isTrue();
144     assertThat(storage.exists(dir)).isTrue();
145   }
146 }
147