• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.apphibernation;
18 
19 import static org.junit.Assert.assertEquals;
20 
21 import android.os.FileUtils;
22 import android.platform.test.annotations.Presubmit;
23 import android.util.proto.ProtoInputStream;
24 import android.util.proto.ProtoOutputStream;
25 
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.test.InstrumentationRegistry;
29 import androidx.test.filters.SmallTest;
30 
31 import org.junit.After;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.mockito.Mockito;
35 
36 import java.io.File;
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.List;
42 import java.util.concurrent.Callable;
43 import java.util.concurrent.ExecutionException;
44 import java.util.concurrent.Future;
45 import java.util.concurrent.ScheduledExecutorService;
46 import java.util.concurrent.ScheduledFuture;
47 import java.util.concurrent.TimeUnit;
48 import java.util.concurrent.TimeoutException;
49 
50 
51 @SmallTest
52 @Presubmit
53 public class HibernationStateDiskStoreTest {
54     private static final String STATES_FILE_NAME = "states";
55     private final MockScheduledExecutorService mMockScheduledExecutorService =
56             new MockScheduledExecutorService();
57 
58     private File mFile;
59     private HibernationStateDiskStore<String> mHibernationStateDiskStore;
60 
61 
62     @Before
setUp()63     public void setUp() {
64         mFile = new File(InstrumentationRegistry.getContext().getCacheDir(), "test");
65         mHibernationStateDiskStore = new HibernationStateDiskStore<>(mFile,
66                 new MockProtoReadWriter(), mMockScheduledExecutorService, STATES_FILE_NAME);
67     }
68 
69     @After
tearDown()70     public void tearDown() {
71         FileUtils.deleteContentsAndDir(mFile);
72     }
73 
74     @Test
testScheduleWriteHibernationStates_writesDataThatCanBeRead()75     public void testScheduleWriteHibernationStates_writesDataThatCanBeRead() {
76         // GIVEN some data to be written
77         List<String> toWrite = new ArrayList<>(Arrays.asList("A", "B"));
78 
79         // WHEN the data is written
80         mHibernationStateDiskStore.scheduleWriteHibernationStates(toWrite);
81         mMockScheduledExecutorService.executeScheduledTask();
82 
83         // THEN the read data is equal to what was written
84         List<String> storedStrings = mHibernationStateDiskStore.readHibernationStates();
85         for (int i = 0; i < toWrite.size(); i++) {
86             assertEquals(toWrite.get(i), storedStrings.get(i));
87         }
88     }
89 
90     @Test
testScheduleWriteHibernationStates_laterWritesOverwritePrevious()91     public void testScheduleWriteHibernationStates_laterWritesOverwritePrevious() {
92         // GIVEN store has some data it is scheduled to write
93         mHibernationStateDiskStore.scheduleWriteHibernationStates(
94                 new ArrayList<>(Arrays.asList("C", "D")));
95 
96         // WHEN a write is scheduled with new data
97         List<String> toWrite = new ArrayList<>(Arrays.asList("A", "B"));
98         mHibernationStateDiskStore.scheduleWriteHibernationStates(toWrite);
99         mMockScheduledExecutorService.executeScheduledTask();
100 
101         // THEN the written data is the last scheduled data
102         List<String> storedStrings = mHibernationStateDiskStore.readHibernationStates();
103         for (int i = 0; i < toWrite.size(); i++) {
104             assertEquals(toWrite.get(i), storedStrings.get(i));
105         }
106     }
107 
108     /**
109      * Mock proto read / writer that just writes and reads a list of String data.
110      */
111     private final class MockProtoReadWriter implements ProtoReadWriter<List<String>> {
112         private static final long FIELD_ID = 1;
113 
114         @Override
writeToProto(@onNull ProtoOutputStream stream, @NonNull List<String> data)115         public void writeToProto(@NonNull ProtoOutputStream stream,
116                 @NonNull List<String> data) {
117             for (int i = 0, size = data.size(); i < size; i++) {
118                 stream.write(FIELD_ID, data.get(i));
119             }
120         }
121 
122         @Nullable
123         @Override
readFromProto(@onNull ProtoInputStream stream)124         public List<String> readFromProto(@NonNull ProtoInputStream stream)
125                 throws IOException {
126             ArrayList<String> list = new ArrayList<>();
127             while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
128                 list.add(stream.readString(FIELD_ID));
129             }
130             return list;
131         }
132     }
133 
134     /**
135      * Mock scheduled executor service that has minimum implementation and can synchronously
136      * execute scheduled tasks.
137      */
138     private final class MockScheduledExecutorService implements ScheduledExecutorService {
139 
140         Runnable mScheduledRunnable = null;
141 
142         @Override
schedule(Runnable command, long delay, TimeUnit unit)143         public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
144             mScheduledRunnable = command;
145             return Mockito.mock(ScheduledFuture.class);
146         }
147 
148         @Override
schedule(Callable<V> callable, long delay, TimeUnit unit)149         public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
150             throw new UnsupportedOperationException();
151         }
152 
153         @Override
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)154         public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
155                 long period, TimeUnit unit) {
156             throw new UnsupportedOperationException();
157         }
158 
159         @Override
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)160         public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
161                 long delay, TimeUnit unit) {
162             throw new UnsupportedOperationException();
163         }
164 
165         @Override
shutdown()166         public void shutdown() {
167             throw new UnsupportedOperationException();
168         }
169 
170         @Override
shutdownNow()171         public List<Runnable> shutdownNow() {
172             throw new UnsupportedOperationException();
173         }
174 
175         @Override
isShutdown()176         public boolean isShutdown() {
177             return false;
178         }
179 
180         @Override
isTerminated()181         public boolean isTerminated() {
182             return false;
183         }
184 
185         @Override
awaitTermination(long timeout, TimeUnit unit)186         public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
187             throw new UnsupportedOperationException();
188         }
189 
190         @Override
submit(Callable<T> task)191         public <T> Future<T> submit(Callable<T> task) {
192             throw new UnsupportedOperationException();
193         }
194 
195         @Override
submit(Runnable task, T result)196         public <T> Future<T> submit(Runnable task, T result) {
197             throw new UnsupportedOperationException();
198         }
199 
200         @Override
submit(Runnable task)201         public Future<?> submit(Runnable task) {
202             throw new UnsupportedOperationException();
203         }
204 
205         @Override
invokeAll(Collection<? extends Callable<T>> tasks)206         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
207                 throws InterruptedException {
208             throw new UnsupportedOperationException();
209         }
210 
211         @Override
invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)212         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
213                 TimeUnit unit) throws InterruptedException {
214             throw new UnsupportedOperationException();
215         }
216 
217         @Override
invokeAny(Collection<? extends Callable<T>> tasks)218         public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
219                 throws InterruptedException, ExecutionException {
220             throw new UnsupportedOperationException();
221         }
222 
223         @Override
invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)224         public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
225                 throws InterruptedException, ExecutionException, TimeoutException {
226             throw new UnsupportedOperationException();
227         }
228 
229         @Override
execute(Runnable command)230         public void execute(Runnable command) {
231             throw new UnsupportedOperationException();
232         }
233 
executeScheduledTask()234         void executeScheduledTask() {
235             mScheduledRunnable.run();
236         }
237     }
238 }
239