1 /*
2  * Copyright (C) 2012 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 android.filesystem.cts;
18 
19 import static androidx.test.InstrumentationRegistry.getContext;
20 import static androidx.test.InstrumentationRegistry.getInstrumentation;
21 
22 import android.util.Log;
23 
24 import androidx.test.runner.AndroidJUnit4;
25 
26 import com.android.compatibility.common.util.DeviceReportLog;
27 import com.android.compatibility.common.util.SystemUtil;
28 
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.junit.runner.RunWith;
33 
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicInteger;
36 
37 @RunWith(AndroidJUnit4.class)
38 public class AlmostFullTest {
39     private static final String DIR_INITIAL_FILL = "INITIAL_FILL";
40     private static final String DIR_SEQ_UPDATE = "SEQ_UPDATE";
41     private static final String DIR_RANDOM_WR = "RANDOM_WR";
42     private static final String DIR_RANDOM_RD = "RANDOM_RD";
43     private static final String TAG = "AlmostFullTest";
44     private static final String REPORT_LOG_NAME = "CtsFileSystemTestCases";
45 
46     private static final long FREE_SPACE_FINAL = 1000L * 1024 * 1024L;
47 
48     // test runner creates multiple instances at the begging.
49     // use that to fill disk only once.
50     // set as final to initialize it only once
51     private static final AtomicInteger mRefCounter = new AtomicInteger(0);
52     private static final AtomicBoolean mDiskFilled = new AtomicBoolean(false);
53 
AlmostFullTest()54     public AlmostFullTest() {
55         int currentCounter = mRefCounter.incrementAndGet();
56         Log.i(TAG, "++currentCounter: " + currentCounter);
57     }
58 
59     @Before
setUp()60     public void setUp() throws Exception {
61         if (mDiskFilled.compareAndSet(false, true)) {
62             Log.i(TAG, "Filling disk");
63             // initial fill done in two stage as disk can be filled by other
64             // components
65             long freeDisk = SystemUtil.getFreeDiskSize(getContext());
66             long diskToFill = freeDisk - FREE_SPACE_FINAL;
67             if (diskToFill >= 0) {
68                 Log.i(TAG, "free disk " + freeDisk + ", to fill " + diskToFill);
69             } else {
70                 Log.i(TAG, "free disk " + freeDisk + " too small, needs " + FREE_SPACE_FINAL);
71                 return;
72             }
73             // Ensure MAX_SIZE_TO_FILL is an integral multiple of FileUtil.BUFFER_SIZE to avoid
74             // rounding errors caused by FileUtil.createNewFilledFile. See b/63535343.
75             final long MAX_FILE_SIZE_TO_FILL = FileUtil.BUFFER_SIZE * 100L;
76             long filled = 0;
77             while (filled < diskToFill) {
78                 long toFill = diskToFill - filled;
79                 if (toFill > MAX_FILE_SIZE_TO_FILL) {
80                     toFill = MAX_FILE_SIZE_TO_FILL;
81                 }
82                 Log.i(TAG, "Generating file " + toFill);
83                 FileUtil.createNewFilledFile(getContext(),
84                         DIR_INITIAL_FILL, toFill);
85                 filled += toFill;
86             }
87         }
88         Log.i(TAG, "free disk " + SystemUtil.getFreeDiskSize(getContext()));
89     }
90 
91     @After
tearDown()92     public void tearDown() throws Exception {
93         Log.i(TAG, "tearDown free disk " + SystemUtil.getFreeDiskSize(getContext()));
94         int currentCounter = mRefCounter.decrementAndGet();
95         Log.i(TAG, "--currentCounter: " + currentCounter);
96         if (currentCounter == 0) {
97             FileUtil.removeFileOrDir(getContext(), DIR_INITIAL_FILL);
98         }
99         FileUtil.removeFileOrDir(getContext(), DIR_SEQ_UPDATE);
100         FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_WR);
101         FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_RD);
102         Log.i(TAG, "tearDown free disk " + SystemUtil.getFreeDiskSize(getContext()));
103     }
104 
105     @Test
testSequentialUpdate()106     public void testSequentialUpdate() throws Exception {
107         // now about freeSpaceToLeave should be left
108         // and try updating exceeding the free space size
109         final long FILE_SIZE = 400L * 1024L * 1024L;
110         long freeDisk = SystemUtil.getFreeDiskSize(getContext());
111         Log.i(TAG, "Now free space is " + freeDisk);
112         if (freeDisk < FILE_SIZE) {
113             Log.w(TAG, "too little space: " + freeDisk);
114             return;
115         }
116         final int BUFFER_SIZE = 10 * 1024 * 1024;
117         final int NUMBER_REPETITION = 10;
118         String streamName = "test_sequential_update";
119         FileUtil.doSequentialUpdateTest(getContext(), DIR_SEQ_UPDATE, FILE_SIZE, BUFFER_SIZE,
120                 NUMBER_REPETITION, REPORT_LOG_NAME, streamName);
121     }
122 
123     // TODO: file size too small and caching will give wrong better result.
124     // needs to flush cache by reading big files per each read.
125     @Test
testRandomRead()126     public void testRandomRead() throws Exception {
127         final int BUFFER_SIZE = 4 * 1024;
128         final long fileSize = 400L * 1024L * 1024L;
129         long freeDisk = SystemUtil.getFreeDiskSize(getContext());
130         if (freeDisk < fileSize) {
131             Log.w(TAG, "too little space: " + freeDisk);
132             return;
133         }
134         String streamName = "test_random_read";
135         DeviceReportLog report = new DeviceReportLog(REPORT_LOG_NAME, streamName);
136         FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, report, fileSize, BUFFER_SIZE);
137         report.submit(getInstrumentation());
138     }
139 
140     @Test
testRandomUpdate()141     public void testRandomUpdate() throws Exception {
142         final int BUFFER_SIZE = 4 * 1024;
143         final long fileSize = 256L * 1024L * 1024L;
144         long freeDisk = SystemUtil.getFreeDiskSize(getContext());
145         if (freeDisk < fileSize) {
146             Log.w(TAG, "too little space: " + freeDisk);
147             return;
148         }
149         String streamName = "test_random_update";
150         DeviceReportLog report = new DeviceReportLog(REPORT_LOG_NAME, streamName);
151         FileUtil.doRandomWriteTest(getContext(), DIR_RANDOM_WR, report, fileSize, BUFFER_SIZE);
152         report.submit(getInstrumentation());
153     }
154 }
155