1 /*
2  * Copyright (C) 2009 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;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.DropBoxManager;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.os.ParcelFileDescriptor;
26 import android.os.Process;
27 import android.os.ServiceManager;
28 import android.os.StatFs;
29 import android.provider.Settings;
30 import android.test.AndroidTestCase;
31 
32 import com.android.server.DropBoxManagerService;
33 
34 import java.io.BufferedReader;
35 import java.io.File;
36 import java.io.FileOutputStream;
37 import java.io.FileWriter;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.InputStreamReader;
41 import java.util.Random;
42 import java.util.zip.GZIPOutputStream;
43 
44 /** Test {@link DropBoxManager} functionality. */
45 public class DropBoxTest extends AndroidTestCase {
tearDown()46     public void tearDown() throws Exception {
47         ContentResolver cr = getContext().getContentResolver();
48         Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "");
49         Settings.Global.putString(cr, Settings.Global.DROPBOX_MAX_FILES, "");
50         Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, "");
51         Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
52     }
53 
testAddText()54     public void testAddText() throws Exception {
55         DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
56                 Context.DROPBOX_SERVICE);
57         long before = System.currentTimeMillis();
58         Thread.sleep(5);
59         dropbox.addText("DropBoxTest", "TEST0");
60         Thread.sleep(5);
61         long between = System.currentTimeMillis();
62         Thread.sleep(5);
63         dropbox.addText("DropBoxTest", "TEST1");
64         dropbox.addText("DropBoxTest", "TEST2");
65         Thread.sleep(5);
66         long after = System.currentTimeMillis();
67 
68         DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
69         DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
70         DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
71         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()));
72 
73         assertTrue(e0.getTimeMillis() > before);
74         assertTrue(e0.getTimeMillis() < between);
75         assertTrue(e1.getTimeMillis() > between);
76         assertTrue(e1.getTimeMillis() < e2.getTimeMillis());
77         assertTrue(e2.getTimeMillis() < after);
78 
79         assertEquals("TEST0", e0.getText(80));
80         assertEquals("TEST1", e1.getText(80));
81         assertEquals("TES", e2.getText(3));
82 
83         e0.close();
84         e1.close();
85         e2.close();
86     }
87 
88     public void testAddData() throws Exception {
89         DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
90                 Context.DROPBOX_SERVICE);
91         long before = System.currentTimeMillis();
92         dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
93         long after = System.currentTimeMillis();
94 
95         DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", before);
96         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
97 
98         assertEquals("DropBoxTest", e.getTag());
99         assertTrue(e.getTimeMillis() >= before);
100         assertEquals(0, e.getFlags());
101         assertTrue(null == e.getText(80));
102 
103         byte[] buf = new byte[80];
104         assertEquals("TEST", new String(buf, 0, e.getInputStream().read(buf)));
105 
106         e.close();
107     }
108 
109     public void testAddFile() throws Exception {
110         File dir = getEmptyDir("testAddFile");
111         long before = System.currentTimeMillis();
112 
113         File f0 = new File(dir, "f0.txt");
114         File f1 = new File(dir, "f1.txt.gz");
115         File f2 = new File(dir, "f2.dat");
116         File f3 = new File(dir, "f2.dat.gz");
117 
118         FileWriter w0 = new FileWriter(f0);
119         GZIPOutputStream gz1 = new GZIPOutputStream(new FileOutputStream(f1));
120         FileOutputStream os2 = new FileOutputStream(f2);
121         GZIPOutputStream gz3 = new GZIPOutputStream(new FileOutputStream(f3));
122 
123         w0.write("FILE0");
124         gz1.write("FILE1".getBytes());
125         os2.write("DATA2".getBytes());
126         gz3.write("DATA3".getBytes());
127 
128         w0.close();
129         gz1.close();
130         os2.close();
131         gz3.close();
132 
133         DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
134                 Context.DROPBOX_SERVICE);
135 
136         dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
137         dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
138         dropbox.addFile("DropBoxTest", f2, 0);
139         dropbox.addFile("DropBoxTest", f3, DropBoxManager.IS_GZIPPED);
140 
141         DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
142         DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
143         DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
144         DropBoxManager.Entry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis());
145         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
146 
147         assertTrue(e0.getTimeMillis() > before);
148         assertTrue(e1.getTimeMillis() > e0.getTimeMillis());
149         assertTrue(e2.getTimeMillis() > e1.getTimeMillis());
150         assertTrue(e3.getTimeMillis() > e2.getTimeMillis());
151 
152         assertEquals(DropBoxManager.IS_TEXT, e0.getFlags());
153         assertEquals(DropBoxManager.IS_TEXT, e1.getFlags());
154         assertEquals(0, e2.getFlags());
155         assertEquals(0, e3.getFlags());
156 
157         assertEquals("FILE0", e0.getText(80));
158 
159         byte[] buf1 = new byte[80];
160         assertEquals("FILE1", new String(buf1, 0, e1.getInputStream().read(buf1)));
161 
162         assertTrue(null == e2.getText(80));
163         byte[] buf2 = new byte[80];
164         assertEquals("DATA2", new String(buf2, 0, e2.getInputStream().read(buf2)));
165 
166         assertTrue(null == e3.getText(80));
167         byte[] buf3 = new byte[80];
168         assertEquals("DATA3", new String(buf3, 0, e3.getInputStream().read(buf3)));
169 
170         e0.close();
171         e1.close();
172         e2.close();
173         e3.close();
174     }
175 
testAddEntriesInTheFuture()176     public void testAddEntriesInTheFuture() throws Exception {
177         File dir = getEmptyDir("testAddEntriesInTheFuture");
178         long before = System.currentTimeMillis();
179 
180         // Near future: should be allowed to persist
181         FileWriter w0 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 5000) + ".txt"));
182         w0.write("FUTURE0");
183         w0.close();
184 
185         // Far future: should be collapsed
186         FileWriter w1 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 100000) + ".txt"));
187         w1.write("FUTURE1");
188         w1.close();
189 
190         // Another far future item, this one gzipped
191         File f2 = new File(dir, "DropBoxTest@" + (before + 100001) + ".txt.gz");
192         GZIPOutputStream gz2 = new GZIPOutputStream(new FileOutputStream(f2));
193         gz2.write("FUTURE2".getBytes());
194         gz2.close();
195 
196         // Tombstone in the far future
197         new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
198 
199         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
200         DropBoxManager dropbox = new DropBoxManager(service);
201 
202         // Until a write, the timestamps are taken at face value
203         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
204         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
205         DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
206         DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
207         assertTrue(null == dropbox.getNextEntry(null, e3.getTimeMillis()));
208 
209         assertEquals("FUTURE0", e0.getText(80));
210         assertEquals("FUTURE1", e1.getText(80));
211         assertEquals("FUTURE2", e2.getText(80));
212         assertEquals(null, e3.getText(80));
213 
214         assertEquals(before + 5000, e0.getTimeMillis());
215         assertEquals(before + 100000, e1.getTimeMillis());
216         assertEquals(before + 100001, e2.getTimeMillis());
217         assertEquals(before + 100002, e3.getTimeMillis());
218 
219         e0.close();
220         e1.close();
221         e2.close();
222         e3.close();
223 
224         // Write something to force a collapse
225         dropbox.addText("NotDropBoxTest", "FUTURE");
226         e0 = dropbox.getNextEntry(null, before);
227         e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
228         e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
229         e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
230         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
231 
232         assertEquals("FUTURE0", e0.getText(80));
233         assertEquals("FUTURE1", e1.getText(80));
234         assertEquals("FUTURE2", e2.getText(80));
235         assertEquals(null, e3.getText(80));
236 
237         assertEquals(before + 5000, e0.getTimeMillis());
238         assertEquals(before + 5001, e1.getTimeMillis());
239         assertEquals(before + 5002, e2.getTimeMillis());
240         assertEquals(before + 5003, e3.getTimeMillis());
241 
242         e0.close();
243         e1.close();
244         e2.close();
245         e3.close();
246         service.stop();
247     }
248 
testIsTagEnabled()249     public void testIsTagEnabled() throws Exception {
250         DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
251                 Context.DROPBOX_SERVICE);
252         long before = System.currentTimeMillis();
253         dropbox.addText("DropBoxTest", "TEST-ENABLED");
254         assertTrue(dropbox.isTagEnabled("DropBoxTest"));
255 
256         ContentResolver cr = getContext().getContentResolver();
257         Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest",
258                                   "disabled");
259 
260         dropbox.addText("DropBoxTest", "TEST-DISABLED");
261         assertFalse(dropbox.isTagEnabled("DropBoxTest"));
262 
263         Settings.Global.putString(cr, Settings.Global.DROPBOX_TAG_PREFIX + "DropBoxTest",
264                                   "");
265 
266         dropbox.addText("DropBoxTest", "TEST-ENABLED-AGAIN");
267         assertTrue(dropbox.isTagEnabled("DropBoxTest"));
268 
269         DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
270         DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
271         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()));
272 
273         assertEquals("TEST-ENABLED", e0.getText(80));
274         assertEquals("TEST-ENABLED-AGAIN", e1.getText(80));
275 
276         e0.close();
277         e1.close();
278     }
279 
testGetNextEntry()280     public void testGetNextEntry() throws Exception {
281         File dir = getEmptyDir("testGetNextEntry");
282         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
283         DropBoxManager dropbox = new DropBoxManager(service);
284 
285         long before = System.currentTimeMillis();
286         dropbox.addText("DropBoxTest.A", "A0");
287         dropbox.addText("DropBoxTest.B", "B0");
288         dropbox.addText("DropBoxTest.A", "A1");
289 
290         DropBoxManager.Entry a0 = dropbox.getNextEntry("DropBoxTest.A", before);
291         DropBoxManager.Entry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis());
292         assertTrue(null == dropbox.getNextEntry("DropBoxTest.A", a1.getTimeMillis()));
293 
294         DropBoxManager.Entry b0 = dropbox.getNextEntry("DropBoxTest.B", before);
295         assertTrue(null == dropbox.getNextEntry("DropBoxTest.B", b0.getTimeMillis()));
296 
297         DropBoxManager.Entry x0 = dropbox.getNextEntry(null, before);
298         DropBoxManager.Entry x1 = dropbox.getNextEntry(null, x0.getTimeMillis());
299         DropBoxManager.Entry x2 = dropbox.getNextEntry(null, x1.getTimeMillis());
300         assertTrue(null == dropbox.getNextEntry(null, x2.getTimeMillis()));
301 
302         assertEquals("DropBoxTest.A", a0.getTag());
303         assertEquals("DropBoxTest.A", a1.getTag());
304         assertEquals("A0", a0.getText(80));
305         assertEquals("A1", a1.getText(80));
306 
307         assertEquals("DropBoxTest.B", b0.getTag());
308         assertEquals("B0", b0.getText(80));
309 
310         assertEquals("DropBoxTest.A", x0.getTag());
311         assertEquals("DropBoxTest.B", x1.getTag());
312         assertEquals("DropBoxTest.A", x2.getTag());
313         assertEquals("A0", x0.getText(80));
314         assertEquals("B0", x1.getText(80));
315         assertEquals("A1", x2.getText(80));
316 
317         a0.close();
318         a1.close();
319         b0.close();
320         x0.close();
321         x1.close();
322         x2.close();
323         service.stop();
324     }
325 
testSizeLimits()326     public void testSizeLimits() throws Exception {
327         File dir = getEmptyDir("testSizeLimits");
328         int blockSize =  new StatFs(dir.getPath()).getBlockSize();
329 
330         // Limit storage to 10 blocks
331         int kb = blockSize * 10 / 1024;
332         ContentResolver cr = getContext().getContentResolver();
333         Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, Integer.toString(kb));
334 
335         // Three tags using a total of 12 blocks:
336         // DropBoxTest0 [ ][ ]
337         // DropBoxTest1 [x][ ][    ][ ][xxx(20 blocks)xxx]
338         // DropBoxTest2 [xxxxxxxxxx][ ][ ]
339         //
340         // The blocks marked "x" will be removed due to storage restrictions.
341         // Use random fill (so it doesn't compress), subtract a little for gzip overhead
342 
343         final int overhead = 64;
344         long before = System.currentTimeMillis();
345         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
346         DropBoxManager dropbox = new DropBoxManager(service);
347 
348         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
349         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
350 
351         addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
352         addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
353         addRandomEntry(dropbox, "DropBoxTest1", blockSize * 2 - overhead);
354         addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
355         addRandomEntry(dropbox, "DropBoxTest1", blockSize * 20 - overhead);
356 
357         addRandomEntry(dropbox, "DropBoxTest2", blockSize * 4 - overhead);
358         addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
359         addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
360 
361         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
362         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
363         DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
364         DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
365         DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
366         DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
367         DropBoxManager.Entry e6 = dropbox.getNextEntry(null, e5.getTimeMillis());
368         DropBoxManager.Entry e7 = dropbox.getNextEntry(null, e6.getTimeMillis());
369         DropBoxManager.Entry e8 = dropbox.getNextEntry(null, e7.getTimeMillis());
370         DropBoxManager.Entry e9 = dropbox.getNextEntry(null, e8.getTimeMillis());
371         assertTrue(null == dropbox.getNextEntry(null, e9.getTimeMillis()));
372 
373         assertEquals("DropBoxTest0", e0.getTag());
374         assertEquals("DropBoxTest0", e1.getTag());
375         assertEquals(blockSize - overhead, getEntrySize(e0));
376         assertEquals(blockSize - overhead, getEntrySize(e1));
377 
378         assertEquals("DropBoxTest1", e2.getTag());
379         assertEquals("DropBoxTest1", e3.getTag());
380         assertEquals("DropBoxTest1", e4.getTag());
381         assertEquals("DropBoxTest1", e5.getTag());
382         assertEquals("DropBoxTest1", e6.getTag());
383         assertEquals(-1, getEntrySize(e2));  // Tombstone
384         assertEquals(blockSize - overhead, getEntrySize(e3));
385         assertEquals(blockSize * 2 - overhead, getEntrySize(e4));
386         assertEquals(blockSize - overhead, getEntrySize(e5));
387         assertEquals(-1, getEntrySize(e6));
388 
389         assertEquals("DropBoxTest2", e7.getTag());
390         assertEquals("DropBoxTest2", e8.getTag());
391         assertEquals("DropBoxTest2", e9.getTag());
392         assertEquals(-1, getEntrySize(e7));  // Tombstone
393         assertEquals(blockSize - overhead, getEntrySize(e8));
394         assertEquals(blockSize - overhead, getEntrySize(e9));
395 
396         e0.close();
397         e1.close();
398         e2.close();
399         e3.close();
400         e4.close();
401         e5.close();
402         e6.close();
403         e7.close();
404         e8.close();
405         e9.close();
406 
407         // Specifying a tag name skips tombstone records.
408 
409         DropBoxManager.Entry t0 = dropbox.getNextEntry("DropBoxTest1", before);
410         DropBoxManager.Entry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis());
411         DropBoxManager.Entry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis());
412         assertTrue(null == dropbox.getNextEntry("DropBoxTest1", t2.getTimeMillis()));
413 
414         assertEquals("DropBoxTest1", t0.getTag());
415         assertEquals("DropBoxTest1", t1.getTag());
416         assertEquals("DropBoxTest1", t2.getTag());
417 
418         assertEquals(blockSize - overhead, getEntrySize(t0));
419         assertEquals(blockSize * 2 - overhead, getEntrySize(t1));
420         assertEquals(blockSize - overhead, getEntrySize(t2));
421 
422         t0.close();
423         t1.close();
424         t2.close();
425         service.stop();
426     }
427 
testAgeLimits()428     public void testAgeLimits() throws Exception {
429         File dir = getEmptyDir("testAgeLimits");
430         int blockSize = new StatFs(dir.getPath()).getBlockSize();
431 
432         // Limit storage to 10 blocks with an expiration of 1 second
433         int kb = blockSize * 10 / 1024;
434         ContentResolver cr = getContext().getContentResolver();
435         Settings.Global.putString(cr, Settings.Global.DROPBOX_AGE_SECONDS, "1");
436         Settings.Global.putString(cr, Settings.Global.DROPBOX_QUOTA_KB, Integer.toString(kb));
437 
438         // Write one normal entry and another so big that it is instantly tombstoned
439         long before = System.currentTimeMillis();
440         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
441         DropBoxManager dropbox = new DropBoxManager(service);
442 
443         dropbox.addText("DropBoxTest", "TEST");
444         addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
445 
446         // Verify that things are as expected
447         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
448         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
449         assertTrue(null == dropbox.getNextEntry(null, e1.getTimeMillis()));
450 
451         assertEquals("TEST", e0.getText(80));
452         assertEquals(null, e1.getText(80));
453         assertEquals(-1, getEntrySize(e1));
454 
455         e0.close();
456         e1.close();
457 
458         // Wait a second and write another entry -- old ones should be expunged
459         Thread.sleep(2000);
460         dropbox.addText("DropBoxTest", "TEST1");
461 
462         e0 = dropbox.getNextEntry(null, before);
463         assertTrue(null == dropbox.getNextEntry(null, e0.getTimeMillis()));
464         assertEquals("TEST1", e0.getText(80));
465         e0.close();
466     }
467 
testFileCountLimits()468     public void testFileCountLimits() throws Exception {
469         File dir = getEmptyDir("testFileCountLimits");
470 
471         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
472         DropBoxManager dropbox = new DropBoxManager(service);
473         dropbox.addText("DropBoxTest", "TEST0");
474         dropbox.addText("DropBoxTest", "TEST1");
475         dropbox.addText("DropBoxTest", "TEST2");
476         dropbox.addText("DropBoxTest", "TEST3");
477         dropbox.addText("DropBoxTest", "TEST4");
478         dropbox.addText("DropBoxTest", "TEST5");
479 
480         // Verify 6 files added
481         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, 0);
482         DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
483         DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
484         DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
485         DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
486         DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
487         assertTrue(null == dropbox.getNextEntry(null, e5.getTimeMillis()));
488         assertEquals("TEST0", e0.getText(80));
489         assertEquals("TEST5", e5.getText(80));
490 
491         e0.close();
492         e1.close();
493         e2.close();
494         e3.close();
495         e4.close();
496         e5.close();
497 
498         // Limit to 3 files and add one more entry
499         ContentResolver cr = getContext().getContentResolver();
500         Settings.Global.putString(cr, Settings.Global.DROPBOX_MAX_FILES, "3");
501         dropbox.addText("DropBoxTest", "TEST6");
502 
503         // Verify only 3 files left
504         DropBoxManager.Entry f0 = dropbox.getNextEntry(null, 0);
505         DropBoxManager.Entry f1 = dropbox.getNextEntry(null, f0.getTimeMillis());
506         DropBoxManager.Entry f2 = dropbox.getNextEntry(null, f1.getTimeMillis());
507         assertTrue(null == dropbox.getNextEntry(null, f2.getTimeMillis()));
508         assertEquals("TEST4", f0.getText(80));
509         assertEquals("TEST5", f1.getText(80));
510         assertEquals("TEST6", f2.getText(80));
511 
512         f0.close();
513         f1.close();
514         f2.close();
515     }
516 
testCreateDropBoxManagerWithInvalidDirectory()517     public void testCreateDropBoxManagerWithInvalidDirectory() throws Exception {
518         // If created with an invalid directory, the DropBoxManager should suffer quietly
519         // and fail all operations (this is how it survives a full disk).
520         // Once the directory becomes possible to create, it will start working.
521 
522         File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
523         new FileOutputStream(dir).close();  // Create an empty file
524         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
525         DropBoxManager dropbox = new DropBoxManager(service);
526 
527         dropbox.addText("DropBoxTest", "should be ignored");
528         dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
529         assertTrue(null == dropbox.getNextEntry("DropBoxTest", 0));
530 
531         dir.delete();  // Remove the file so a directory can be created
532         dropbox.addText("DropBoxTest", "TEST");
533         DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", 0);
534         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
535         assertEquals("DropBoxTest", e.getTag());
536         assertEquals("TEST", e.getText(80));
537         e.close();
538         service.stop();
539     }
540 
testDropBoxEntrySerialization()541     public void testDropBoxEntrySerialization() throws Exception {
542         // Make sure DropBoxManager.Entry can be serialized to a Parcel and back
543         // under a variety of conditions.
544 
545         Parcel parcel = Parcel.obtain();
546         File dir = getEmptyDir("testDropBoxEntrySerialization");
547 
548         new DropBoxManager.Entry("empty", 1000000).writeToParcel(parcel, 0);
549         new DropBoxManager.Entry("string", 2000000, "String Value").writeToParcel(parcel, 0);
550         new DropBoxManager.Entry("bytes", 3000000, "Bytes Value".getBytes(),
551                 DropBoxManager.IS_TEXT).writeToParcel(parcel, 0);
552         new DropBoxManager.Entry("zerobytes", 4000000, new byte[0], 0).writeToParcel(parcel, 0);
553         new DropBoxManager.Entry("emptybytes", 5000000, (byte[]) null,
554                 DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
555 
556         try {
557             new DropBoxManager.Entry("badbytes", 99999,
558                     "Bad Bytes Value".getBytes(),
559                     DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
560             fail("IllegalArgumentException expected for non-null byte[] and IS_EMPTY flags");
561         } catch (IllegalArgumentException e) {
562             // expected
563         }
564 
565         try {
566             new DropBoxManager.Entry("badbytes", 99999, (byte[]) null, 0).writeToParcel(parcel, 0);
567             fail("IllegalArgumentException expected for null byte[] and non-IS_EMPTY flags");
568         } catch (IllegalArgumentException e) {
569             // expected
570         }
571 
572         File f = new File(dir, "file.dat");
573         FileOutputStream os = new FileOutputStream(f);
574         os.write("File Value".getBytes());
575         os.close();
576 
577         new DropBoxManager.Entry("file", 6000000, f, DropBoxManager.IS_TEXT).writeToParcel(
578                 parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
579         new DropBoxManager.Entry("binfile", 7000000, f, 0).writeToParcel(
580                 parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
581         new DropBoxManager.Entry("emptyfile", 8000000, (ParcelFileDescriptor) null,
582                 DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
583 
584         try {
585             new DropBoxManager.Entry("badfile", 99999, new File(dir, "nonexist.dat"), 0);
586             fail("IOException expected for nonexistent file");
587         } catch (IOException e) {
588             // expected
589         }
590 
591         try {
592             new DropBoxManager.Entry("badfile", 99999, f, DropBoxManager.IS_EMPTY).writeToParcel(
593                     parcel, 0);
594             fail("IllegalArgumentException expected for non-null file and IS_EMPTY flags");
595         } catch (IllegalArgumentException e) {
596             // expected
597         }
598 
599         try {
600             new DropBoxManager.Entry("badfile", 99999, (ParcelFileDescriptor) null, 0);
601             fail("IllegalArgumentException expected for null PFD and non-IS_EMPTY flags");
602         } catch (IllegalArgumentException e) {
603             // expected
604         }
605 
606         File gz = new File(dir, "file.gz");
607         GZIPOutputStream gzout = new GZIPOutputStream(new FileOutputStream(gz));
608         gzout.write("Gzip File Value".getBytes());
609         gzout.close();
610 
611         new DropBoxManager.Entry("gzipfile", 9000000, gz,
612                 DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED).writeToParcel(
613                     parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
614         new DropBoxManager.Entry("gzipbinfile", 10000000, gz,
615                 DropBoxManager.IS_GZIPPED).writeToParcel(
616                     parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
617 
618         //
619         // Switch from writing to reading
620         //
621 
622         parcel.setDataPosition(0);
623         DropBoxManager.Entry e;
624 
625         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
626         assertEquals("empty", e.getTag());
627         assertEquals(1000000, e.getTimeMillis());
628         assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
629         assertEquals(null, e.getText(100));
630         assertEquals(null, e.getInputStream());
631         e.close();
632 
633         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
634         assertEquals("string", e.getTag());
635         assertEquals(2000000, e.getTimeMillis());
636         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
637         assertEquals("String Value", e.getText(100));
638         assertEquals("String Value",
639                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
640         e.close();
641 
642         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
643         assertEquals("bytes", e.getTag());
644         assertEquals(3000000, e.getTimeMillis());
645         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
646         assertEquals("Bytes Value", e.getText(100));
647         e.close();
648 
649         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
650         assertEquals("zerobytes", e.getTag());
651         assertEquals(4000000, e.getTimeMillis());
652         assertEquals(0, e.getFlags());
653         assertEquals(null, e.getText(100));
654         assertEquals(null,
655                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
656         e.close();
657 
658         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
659         assertEquals("emptybytes", e.getTag());
660         assertEquals(5000000, e.getTimeMillis());
661         assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
662         assertEquals(null, e.getText(100));
663         assertEquals(null, e.getInputStream());
664         e.close();
665 
666         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
667         assertEquals("file", e.getTag());
668         assertEquals(6000000, e.getTimeMillis());
669         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
670         assertEquals("File Value", e.getText(100));
671         e.close();
672 
673         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
674         assertEquals("binfile", e.getTag());
675         assertEquals(7000000, e.getTimeMillis());
676         assertEquals(0, e.getFlags());
677         assertEquals(null, e.getText(100));
678         assertEquals("File Value",
679                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
680         e.close();
681 
682         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
683         assertEquals("emptyfile", e.getTag());
684         assertEquals(8000000, e.getTimeMillis());
685         assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
686         assertEquals(null, e.getText(100));
687         assertEquals(null, e.getInputStream());
688         e.close();
689 
690         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
691         assertEquals("gzipfile", e.getTag());
692         assertEquals(9000000, e.getTimeMillis());
693         assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
694         assertEquals("Gzip File Value", e.getText(100));
695         e.close();
696 
697         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
698         assertEquals("gzipbinfile", e.getTag());
699         assertEquals(10000000, e.getTimeMillis());
700         assertEquals(0, e.getFlags());
701         assertEquals(null, e.getText(100));
702         assertEquals("Gzip File Value",
703                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
704         e.close();
705 
706         assertEquals(0, parcel.dataAvail());
707         parcel.recycle();
708     }
709 
testDropBoxEntrySerializationDoesntLeakFileDescriptors()710     public void testDropBoxEntrySerializationDoesntLeakFileDescriptors() throws Exception {
711         File dir = getEmptyDir("testDropBoxEntrySerialization");
712         File f = new File(dir, "file.dat");
713         FileOutputStream os = new FileOutputStream(f);
714         os.write("File Value".getBytes());
715         os.close();
716 
717         int before = countOpenFiles();
718         assertTrue(before > 0);
719 
720         for (int i = 0; i < 1000; i++) {
721             Parcel parcel = Parcel.obtain();
722             new DropBoxManager.Entry("file", 1000000, f, 0).writeToParcel(
723                     parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
724 
725             parcel.setDataPosition(0);
726             DropBoxManager.Entry e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
727             assertEquals("file", e.getTag());
728             e.close();
729 
730             parcel.recycle();
731         }
732 
733         int after = countOpenFiles();
734         assertTrue(after > 0);
735         assertTrue(after < before + 20);
736     }
737 
738     private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
739         byte[] bytes = new byte[size];
740         new Random(System.currentTimeMillis()).nextBytes(bytes);
741 
742         File f = new File(getEmptyDir("addRandomEntry"), "random.dat");
743         FileOutputStream os = new FileOutputStream(f);
744         os.write(bytes);
745         os.close();
746 
747         dropbox.addFile(tag, f, 0);
748     }
749 
750     private int getEntrySize(DropBoxManager.Entry e) throws Exception {
751         InputStream is = e.getInputStream();
752         if (is == null) return -1;
753         int length = 0;
754         while (is.read() != -1) length++;
755         return length;
756     }
757 
758     private void recursiveDelete(File file) {
759         if (!file.delete() && file.isDirectory()) {
760             for (File f : file.listFiles()) recursiveDelete(f);
761             file.delete();
762         }
763     }
764 
765     private File getEmptyDir(String name) {
766         File dir = getContext().getDir("DropBoxTest." + name, 0);
767         for (File f : dir.listFiles()) recursiveDelete(f);
768         assertTrue(dir.listFiles().length == 0);
769         return dir;
770     }
771 
772     private int countOpenFiles() {
773         return new File("/proc/" + Process.myPid() + "/fd").listFiles().length;
774     }
775 }
776