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
17package com.android.server;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.content.Intent;
22import android.os.DropBoxManager;
23import android.os.Parcel;
24import android.os.Parcelable;
25import android.os.ParcelFileDescriptor;
26import android.os.Process;
27import android.os.ServiceManager;
28import android.os.StatFs;
29import android.provider.Settings;
30import android.test.AndroidTestCase;
31
32import com.android.server.DropBoxManagerService;
33
34import java.io.BufferedReader;
35import java.io.File;
36import java.io.FileOutputStream;
37import java.io.FileWriter;
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.InputStreamReader;
41import java.util.Random;
42import java.util.zip.GZIPOutputStream;
43
44/** Test {@link DropBoxManager} functionality. */
45public class DropBoxTest extends AndroidTestCase {
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
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
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
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
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
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
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
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
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
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
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