1 /*
2  * Copyright (C) 2022 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.systemui.settings
18 
19 import android.content.BroadcastReceiver
20 import android.content.Context
21 import android.content.IntentFilter
22 import android.os.Environment
23 import android.os.UserManager
24 import android.testing.AndroidTestingRunner
25 import androidx.test.filters.SmallTest
26 import com.android.systemui.SysuiTestCase
27 import com.android.systemui.broadcast.BroadcastDispatcher
28 import com.android.systemui.util.concurrency.FakeExecutor
29 import com.android.systemui.util.mockito.any
30 import com.android.systemui.util.mockito.eq
31 import com.android.systemui.util.time.FakeSystemClock
32 import com.google.common.truth.Truth.assertThat
33 import java.io.File
34 import java.nio.file.Files
35 import java.util.concurrent.Executor
36 import org.junit.Before
37 import org.junit.Test
38 import org.junit.runner.RunWith
39 import org.mockito.Mock
40 import org.mockito.Mockito.atLeastOnce
41 import org.mockito.Mockito.isNull
42 import org.mockito.Mockito.spy
43 import org.mockito.Mockito.verify
44 import org.mockito.MockitoAnnotations
45 
46 @SmallTest
47 @RunWith(AndroidTestingRunner::class)
48 class UserFileManagerImplTest : SysuiTestCase() {
49     companion object {
50         const val TEST_FILE_NAME = "abc.txt"
51     }
52 
53     lateinit var userFileManager: UserFileManagerImpl
54     lateinit var backgroundExecutor: FakeExecutor
55     @Mock lateinit var userManager: UserManager
56     @Mock lateinit var broadcastDispatcher: BroadcastDispatcher
57 
58     @Before
59     fun setUp() {
60         MockitoAnnotations.initMocks(this)
61         backgroundExecutor = FakeExecutor(FakeSystemClock())
62         userFileManager =
63             UserFileManagerImpl(context, userManager, broadcastDispatcher, backgroundExecutor)
64     }
65 
66     @Test
67     fun testGetFile() {
68         assertThat(userFileManager.getFile(TEST_FILE_NAME, 0).path)
69             .isEqualTo("${context.filesDir}/$TEST_FILE_NAME")
70         assertThat(userFileManager.getFile(TEST_FILE_NAME, 11).path)
71             .isEqualTo("${context.filesDir}/__USER_11_$TEST_FILE_NAME")
72     }
73 
74     @Test
75     fun testGetSharedPreferences() {
76         val primarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0)
77         val secondarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11)
78 
79         assertThat(primarySharedPref).isNotEqualTo(secondarySharedPref)
80 
81         // Make sure these are different files
82         primarySharedPref.edit().putString("TEST", "ABC").commit()
83         assertThat(secondarySharedPref.getString("TEST", null)).isNull()
84 
85         context.deleteSharedPreferences("TEST")
86         context.deleteSharedPreferences("__USER_11_TEST")
87     }
88 
89     @Test
90     fun testMigrateFile() {
91         val userId = 12
92         val fileName = "myFile.txt"
93         val fileContents = "TestingFile"
94         val legacyFile =
95             UserFileManagerImpl.createLegacyFile(
96                 context,
97                 UserFileManagerImpl.FILES,
98                 fileName,
99                 userId
100             )!!
101 
102         // Write file to legacy area
103         Files.createDirectories(legacyFile.getParentFile().toPath())
104         Files.write(legacyFile.toPath(), fileContents.toByteArray())
105         assertThat(legacyFile.exists()).isTrue()
106 
107         // getFile() should migrate the legacy file to the new location
108         val file = userFileManager.getFile(fileName, userId)
109         val newContents = String(Files.readAllBytes(file.toPath()))
110 
111         assertThat(newContents).isEqualTo(fileContents)
112         assertThat(legacyFile.exists()).isFalse()
113         assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse()
114     }
115 
116     @Test
117     fun testMigrateSharedPrefs() {
118         val userId = 13
119         val fileName = "myFile"
120         val contents = "TestingSharedPrefs"
121         val legacyFile =
122             UserFileManagerImpl.createLegacyFile(
123                 context,
124                 UserFileManagerImpl.SHARED_PREFS,
125                 "$fileName.xml",
126                 userId
127             )!!
128 
129         // Write a valid shared prefs xml file to legacy area
130         val tmpPrefs = context.getSharedPreferences("tmp", Context.MODE_PRIVATE)
131         tmpPrefs.edit().putString(contents, contents).commit()
132         Files.createDirectories(legacyFile.getParentFile().toPath())
133         val tmpFile =
134             Environment.buildPath(context.dataDir, UserFileManagerImpl.SHARED_PREFS, "tmp.xml")
135         tmpFile.renameTo(legacyFile)
136         assertThat(legacyFile.exists()).isTrue()
137 
138         // getSharedpreferences() should migrate the legacy file to the new location
139         val prefs = userFileManager.getSharedPreferences(fileName, Context.MODE_PRIVATE, userId)
140         assertThat(prefs.getString(contents, "")).isEqualTo(contents)
141         assertThat(legacyFile.exists()).isFalse()
142         assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse()
143     }
144 
145     @Test
146     fun testUserFileManagerStart() {
147         val userFileManager = spy(userFileManager)
148         userFileManager.start()
149         verify(userFileManager).clearDeletedUserData()
150         verify(broadcastDispatcher)
151             .registerReceiver(
152                 any(BroadcastReceiver::class.java),
153                 any(IntentFilter::class.java),
154                 any(Executor::class.java),
155                 isNull(),
156                 eq(Context.RECEIVER_EXPORTED),
157                 isNull()
158             )
159     }
160 
161     @Test
162     fun testClearDeletedUserData() {
163         val file = userFileManager.getFile(TEST_FILE_NAME, 11)
164         file.createNewFile()
165 
166         assertThat(file.exists()).isTrue()
167         userFileManager.clearDeletedUserData()
168         assertThat(backgroundExecutor.runAllReady()).isGreaterThan(0)
169         verify(userManager, atLeastOnce()).aliveUsers
170 
171         assertThat(file.exists()).isFalse()
172     }
173 }
174