1 /*
2  * Copyright (C) 2017 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;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.platform.test.annotations.Presubmit;
22 
23 import androidx.test.filters.SmallTest;
24 import androidx.test.runner.AndroidJUnit4;
25 
26 import com.google.android.collect.Sets;
27 
28 import org.junit.Before;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.junit.rules.TemporaryFolder;
32 import org.junit.runner.RunWith;
33 import org.mockito.MockitoAnnotations;
34 
35 import java.io.DataInputStream;
36 import java.io.DataOutputStream;
37 import java.io.File;
38 import java.io.FileInputStream;
39 import java.io.FileNotFoundException;
40 import java.io.FileOutputStream;
41 import java.util.HashSet;
42 import java.util.Set;
43 
44 @SmallTest
45 @Presubmit
46 @RunWith(AndroidJUnit4.class)
47 public class ProcessedPackagesJournalTest {
48     private static final String JOURNAL_FILE_NAME = "processed";
49 
50     private static final String GOOGLE_PHOTOS = "com.google.photos";
51     private static final String GMAIL = "com.google.gmail";
52     private static final String GOOGLE_PLUS = "com.google.plus";
53 
54     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
55 
56     private File mStateDirectory;
57     private ProcessedPackagesJournal mProcessedPackagesJournal;
58 
59     @Before
setUp()60     public void setUp() throws Exception {
61         MockitoAnnotations.initMocks(this);
62         mStateDirectory = mTemporaryFolder.newFolder();
63         mProcessedPackagesJournal = new ProcessedPackagesJournal(mStateDirectory);
64         mProcessedPackagesJournal.init();
65     }
66 
67     @Test
constructor_loadsAnyPreviousJournalFromDisk()68     public void constructor_loadsAnyPreviousJournalFromDisk() throws Exception {
69         writePermanentJournalPackages(Sets.newHashSet(GOOGLE_PHOTOS, GMAIL));
70 
71         ProcessedPackagesJournal journalFromDisk =
72                 new ProcessedPackagesJournal(mStateDirectory);
73         journalFromDisk.init();
74 
75         assertThat(journalFromDisk.hasBeenProcessed(GOOGLE_PHOTOS)).isTrue();
76         assertThat(journalFromDisk.hasBeenProcessed(GMAIL)).isTrue();
77     }
78 
79     @Test
hasBeenProcessed_isFalseForAnyPackageFromBlankInit()80     public void hasBeenProcessed_isFalseForAnyPackageFromBlankInit() {
81         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GOOGLE_PHOTOS)).isFalse();
82         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GMAIL)).isFalse();
83         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GOOGLE_PLUS)).isFalse();
84     }
85 
86     @Test
addPackage_addsPackageToObjectState()87     public void addPackage_addsPackageToObjectState() {
88         mProcessedPackagesJournal.addPackage(GOOGLE_PHOTOS);
89 
90         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GOOGLE_PHOTOS)).isTrue();
91     }
92 
93     @Test
addPackage_addsPackageToFileSystem()94     public void addPackage_addsPackageToFileSystem() throws Exception {
95         mProcessedPackagesJournal.addPackage(GOOGLE_PHOTOS);
96 
97         assertThat(readJournalPackages()).contains(GOOGLE_PHOTOS);
98     }
99 
100     @Test
getPackagesCopy_returnsTheCurrentState()101     public void getPackagesCopy_returnsTheCurrentState() throws Exception {
102         mProcessedPackagesJournal.addPackage(GOOGLE_PHOTOS);
103         mProcessedPackagesJournal.addPackage(GMAIL);
104 
105         assertThat(mProcessedPackagesJournal.getPackagesCopy())
106                 .isEqualTo(Sets.newHashSet(GOOGLE_PHOTOS, GMAIL));
107     }
108 
109     @Test
getPackagesCopy_returnsACopy()110     public void getPackagesCopy_returnsACopy() throws Exception {
111         mProcessedPackagesJournal.getPackagesCopy().add(GMAIL);
112 
113         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GMAIL)).isFalse();
114     }
115 
116     @Test
reset_removesAllPackagesFromObjectState()117     public void reset_removesAllPackagesFromObjectState() {
118         mProcessedPackagesJournal.addPackage(GOOGLE_PHOTOS);
119         mProcessedPackagesJournal.addPackage(GOOGLE_PLUS);
120         mProcessedPackagesJournal.addPackage(GMAIL);
121 
122         mProcessedPackagesJournal.reset();
123 
124         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GOOGLE_PHOTOS)).isFalse();
125         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GMAIL)).isFalse();
126         assertThat(mProcessedPackagesJournal.hasBeenProcessed(GOOGLE_PLUS)).isFalse();
127     }
128 
129     @Test
reset_removesAllPackagesFromFileSystem()130     public void reset_removesAllPackagesFromFileSystem() throws Exception {
131         mProcessedPackagesJournal.addPackage(GOOGLE_PHOTOS);
132         mProcessedPackagesJournal.addPackage(GOOGLE_PLUS);
133         mProcessedPackagesJournal.addPackage(GMAIL);
134 
135         mProcessedPackagesJournal.reset();
136 
137         assertThat(readJournalPackages()).isEmpty();
138     }
139 
readJournalPackages()140     private HashSet<String> readJournalPackages() throws Exception {
141         File journal = new File(mStateDirectory, JOURNAL_FILE_NAME);
142         HashSet<String> packages = new HashSet<>();
143 
144         try (FileInputStream fis = new FileInputStream(journal);
145              DataInputStream dis = new DataInputStream(fis)) {
146             while (dis.available() > 0) {
147                 packages.add(dis.readUTF());
148             }
149         } catch (FileNotFoundException e) {
150             return new HashSet<>();
151         }
152 
153         return packages;
154     }
155 
writePermanentJournalPackages(Set<String> packages)156     private void writePermanentJournalPackages(Set<String> packages) throws Exception {
157         File journal = new File(mStateDirectory, JOURNAL_FILE_NAME);
158 
159         try (FileOutputStream fos = new FileOutputStream(journal);
160              DataOutputStream dos = new DataOutputStream(fos)) {
161             for (String packageName : packages) {
162                 dos.writeUTF(packageName);
163             }
164         }
165     }
166 }
167