DropBoxTest.java revision 1a44d5dcabc18cd5ef111f732ccff91683a1a093
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.ServiceManager;
24import android.os.StatFs;
25import android.provider.Settings;
26import android.test.AndroidTestCase;
27
28import com.android.server.DropBoxManagerService;
29
30import java.io.File;
31import java.io.FileOutputStream;
32import java.io.FileWriter;
33import java.io.InputStream;
34import java.util.Random;
35import java.util.zip.GZIPOutputStream;
36
37/** Test {@link DropBoxManager} functionality. */
38public class DropBoxTest extends AndroidTestCase {
39    public void tearDown() throws Exception {
40        ContentResolver cr = getContext().getContentResolver();
41        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_AGE_SECONDS, "");
42        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, "");
43        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
44    }
45
46    public void testAddText() throws Exception {
47        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
48                Context.DROPBOX_SERVICE);
49        long before = System.currentTimeMillis();
50        Thread.sleep(5);
51        dropbox.addText("DropBoxTest", "TEST0");
52        Thread.sleep(5);
53        long between = System.currentTimeMillis();
54        Thread.sleep(5);
55        dropbox.addText("DropBoxTest", "TEST1");
56        dropbox.addText("DropBoxTest", "TEST2");
57        Thread.sleep(5);
58        long after = System.currentTimeMillis();
59
60        DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
61        DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
62        DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
63        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()));
64
65        assertTrue(e0.getTimeMillis() > before);
66        assertTrue(e0.getTimeMillis() < between);
67        assertTrue(e1.getTimeMillis() > between);
68        assertTrue(e1.getTimeMillis() < e2.getTimeMillis());
69        assertTrue(e2.getTimeMillis() < after);
70
71        assertEquals("TEST0", e0.getText(80));
72        assertEquals("TEST1", e1.getText(80));
73        assertEquals("TES", e2.getText(3));
74
75        e0.close();
76        e1.close();
77        e2.close();
78    }
79
80    public void testAddData() throws Exception {
81        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
82                Context.DROPBOX_SERVICE);
83        long before = System.currentTimeMillis();
84        dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
85        long after = System.currentTimeMillis();
86
87        DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", before);
88        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
89
90        assertEquals("DropBoxTest", e.getTag());
91        assertTrue(e.getTimeMillis() >= before);
92        assertEquals(0, e.getFlags());
93        assertTrue(null == e.getText(80));
94
95        byte[] buf = new byte[80];
96        assertEquals("TEST", new String(buf, 0, e.getInputStream().read(buf)));
97
98        e.close();
99    }
100
101    public void testAddFile() throws Exception {
102        File dir = getEmptyDir("testAddFile");
103        long before = System.currentTimeMillis();
104
105        File f0 = new File(dir, "f0.txt");
106        File f1 = new File(dir, "f1.txt.gz");
107        File f2 = new File(dir, "f2.dat");
108        File f3 = new File(dir, "f2.dat.gz");
109
110        FileWriter w0 = new FileWriter(f0);
111        GZIPOutputStream gz1 = new GZIPOutputStream(new FileOutputStream(f1));
112        FileOutputStream os2 = new FileOutputStream(f2);
113        GZIPOutputStream gz3 = new GZIPOutputStream(new FileOutputStream(f3));
114
115        w0.write("FILE0");
116        gz1.write("FILE1".getBytes());
117        os2.write("DATA2".getBytes());
118        gz3.write("DATA3".getBytes());
119
120        w0.close();
121        gz1.close();
122        os2.close();
123        gz3.close();
124
125        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
126                Context.DROPBOX_SERVICE);
127
128        dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
129        dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
130        dropbox.addFile("DropBoxTest", f2, 0);
131        dropbox.addFile("DropBoxTest", f3, DropBoxManager.IS_GZIPPED);
132
133        DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
134        DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
135        DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
136        DropBoxManager.Entry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis());
137        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
138
139        assertTrue(e0.getTimeMillis() > before);
140        assertTrue(e1.getTimeMillis() > e0.getTimeMillis());
141        assertTrue(e2.getTimeMillis() > e1.getTimeMillis());
142        assertTrue(e3.getTimeMillis() > e2.getTimeMillis());
143
144        assertEquals(DropBoxManager.IS_TEXT, e0.getFlags());
145        assertEquals(DropBoxManager.IS_TEXT, e1.getFlags());
146        assertEquals(0, e2.getFlags());
147        assertEquals(0, e3.getFlags());
148
149        assertEquals("FILE0", e0.getText(80));
150
151        byte[] buf1 = new byte[80];
152        assertEquals("FILE1", new String(buf1, 0, e1.getInputStream().read(buf1)));
153
154        assertTrue(null == e2.getText(80));
155        byte[] buf2 = new byte[80];
156        assertEquals("DATA2", new String(buf2, 0, e2.getInputStream().read(buf2)));
157
158        assertTrue(null == e3.getText(80));
159        byte[] buf3 = new byte[80];
160        assertEquals("DATA3", new String(buf3, 0, e3.getInputStream().read(buf3)));
161
162        e0.close();
163        e1.close();
164        e2.close();
165        e3.close();
166    }
167
168    public void testAddEntriesInTheFuture() throws Exception {
169        File dir = getEmptyDir("testAddEntriesInTheFuture");
170        long before = System.currentTimeMillis();
171
172        // Near future: should be allowed to persist
173        FileWriter w0 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 5000) + ".txt"));
174        w0.write("FUTURE0");
175        w0.close();
176
177        // Far future: should be collapsed
178        FileWriter w1 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 100000) + ".txt"));
179        w1.write("FUTURE1");
180        w1.close();
181
182        // Another far future item, this one gzipped
183        File f2 = new File(dir, "DropBoxTest@" + (before + 100001) + ".txt.gz");
184        GZIPOutputStream gz2 = new GZIPOutputStream(new FileOutputStream(f2));
185        gz2.write("FUTURE2".getBytes());
186        gz2.close();
187
188        // Tombstone in the far future
189        new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
190
191        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
192        DropBoxManager dropbox = new DropBoxManager(service);
193
194        // Until a write, the timestamps are taken at face value
195        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
196        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
197        DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
198        DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
199        assertTrue(null == dropbox.getNextEntry(null, e3.getTimeMillis()));
200
201        assertEquals("FUTURE0", e0.getText(80));
202        assertEquals("FUTURE1", e1.getText(80));
203        assertEquals("FUTURE2", e2.getText(80));
204        assertEquals(null, e3.getText(80));
205
206        assertEquals(before + 5000, e0.getTimeMillis());
207        assertEquals(before + 100000, e1.getTimeMillis());
208        assertEquals(before + 100001, e2.getTimeMillis());
209        assertEquals(before + 100002, e3.getTimeMillis());
210
211        e0.close();
212        e1.close();
213        e2.close();
214        e3.close();
215
216        // Write something to force a collapse
217        dropbox.addText("NotDropBoxTest", "FUTURE");
218        e0 = dropbox.getNextEntry(null, before);
219        e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
220        e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
221        e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
222        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
223
224        assertEquals("FUTURE0", e0.getText(80));
225        assertEquals("FUTURE1", e1.getText(80));
226        assertEquals("FUTURE2", e2.getText(80));
227        assertEquals(null, e3.getText(80));
228
229        assertEquals(before + 5000, e0.getTimeMillis());
230        assertEquals(before + 5001, e1.getTimeMillis());
231        assertEquals(before + 5002, e2.getTimeMillis());
232        assertEquals(before + 5003, e3.getTimeMillis());
233
234        e0.close();
235        e1.close();
236        e2.close();
237        e3.close();
238        service.stop();
239    }
240
241    public void testIsTagEnabled() throws Exception {
242        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
243                Context.DROPBOX_SERVICE);
244        long before = System.currentTimeMillis();
245        dropbox.addText("DropBoxTest", "TEST-ENABLED");
246        assertTrue(dropbox.isTagEnabled("DropBoxTest"));
247
248        ContentResolver cr = getContext().getContentResolver();
249        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest",
250                                  "disabled");
251
252        dropbox.addText("DropBoxTest", "TEST-DISABLED");
253        assertFalse(dropbox.isTagEnabled("DropBoxTest"));
254
255        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest",
256                                  "");
257
258        dropbox.addText("DropBoxTest", "TEST-ENABLED-AGAIN");
259        assertTrue(dropbox.isTagEnabled("DropBoxTest"));
260
261        DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
262        DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
263        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()));
264
265        assertEquals("TEST-ENABLED", e0.getText(80));
266        assertEquals("TEST-ENABLED-AGAIN", e1.getText(80));
267
268        e0.close();
269        e1.close();
270    }
271
272    public void testGetNextEntry() throws Exception {
273        File dir = getEmptyDir("testGetNextEntry");
274        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
275        DropBoxManager dropbox = new DropBoxManager(service);
276
277        long before = System.currentTimeMillis();
278        dropbox.addText("DropBoxTest.A", "A0");
279        dropbox.addText("DropBoxTest.B", "B0");
280        dropbox.addText("DropBoxTest.A", "A1");
281
282        DropBoxManager.Entry a0 = dropbox.getNextEntry("DropBoxTest.A", before);
283        DropBoxManager.Entry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis());
284        assertTrue(null == dropbox.getNextEntry("DropBoxTest.A", a1.getTimeMillis()));
285
286        DropBoxManager.Entry b0 = dropbox.getNextEntry("DropBoxTest.B", before);
287        assertTrue(null == dropbox.getNextEntry("DropBoxTest.B", b0.getTimeMillis()));
288
289        DropBoxManager.Entry x0 = dropbox.getNextEntry(null, before);
290        DropBoxManager.Entry x1 = dropbox.getNextEntry(null, x0.getTimeMillis());
291        DropBoxManager.Entry x2 = dropbox.getNextEntry(null, x1.getTimeMillis());
292        assertTrue(null == dropbox.getNextEntry(null, x2.getTimeMillis()));
293
294        assertEquals("DropBoxTest.A", a0.getTag());
295        assertEquals("DropBoxTest.A", a1.getTag());
296        assertEquals("A0", a0.getText(80));
297        assertEquals("A1", a1.getText(80));
298
299        assertEquals("DropBoxTest.B", b0.getTag());
300        assertEquals("B0", b0.getText(80));
301
302        assertEquals("DropBoxTest.A", x0.getTag());
303        assertEquals("DropBoxTest.B", x1.getTag());
304        assertEquals("DropBoxTest.A", x2.getTag());
305        assertEquals("A0", x0.getText(80));
306        assertEquals("B0", x1.getText(80));
307        assertEquals("A1", x2.getText(80));
308
309        a0.close();
310        a1.close();
311        b0.close();
312        x0.close();
313        x1.close();
314        x2.close();
315        service.stop();
316    }
317
318    public void testSizeLimits() throws Exception {
319        File dir = getEmptyDir("testSizeLimits");
320        int blockSize =  new StatFs(dir.getPath()).getBlockSize();
321
322        // Limit storage to 10 blocks
323        int kb = blockSize * 10 / 1024;
324        ContentResolver cr = getContext().getContentResolver();
325        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, Integer.toString(kb));
326
327        // Three tags using a total of 12 blocks:
328        // DropBoxTest0 [ ][ ]
329        // DropBoxTest1 [x][ ][    ][ ][xxx(20 blocks)xxx]
330        // DropBoxTest2 [xxxxxxxxxx][ ][ ]
331        //
332        // The blocks marked "x" will be removed due to storage restrictions.
333        // Use random fill (so it doesn't compress), subtract a little for gzip overhead
334
335        final int overhead = 64;
336        long before = System.currentTimeMillis();
337        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
338        DropBoxManager dropbox = new DropBoxManager(service);
339
340        addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
341        addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
342
343        addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
344        addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
345        addRandomEntry(dropbox, "DropBoxTest1", blockSize * 2 - overhead);
346        addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
347        addRandomEntry(dropbox, "DropBoxTest1", blockSize * 20 - overhead);
348
349        addRandomEntry(dropbox, "DropBoxTest2", blockSize * 4 - overhead);
350        addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
351        addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
352
353        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
354        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
355        DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
356        DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
357        DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
358        DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
359        DropBoxManager.Entry e6 = dropbox.getNextEntry(null, e5.getTimeMillis());
360        DropBoxManager.Entry e7 = dropbox.getNextEntry(null, e6.getTimeMillis());
361        DropBoxManager.Entry e8 = dropbox.getNextEntry(null, e7.getTimeMillis());
362        DropBoxManager.Entry e9 = dropbox.getNextEntry(null, e8.getTimeMillis());
363        assertTrue(null == dropbox.getNextEntry(null, e9.getTimeMillis()));
364
365        assertEquals("DropBoxTest0", e0.getTag());
366        assertEquals("DropBoxTest0", e1.getTag());
367        assertEquals(blockSize - overhead, getEntrySize(e0));
368        assertEquals(blockSize - overhead, getEntrySize(e1));
369
370        assertEquals("DropBoxTest1", e2.getTag());
371        assertEquals("DropBoxTest1", e3.getTag());
372        assertEquals("DropBoxTest1", e4.getTag());
373        assertEquals("DropBoxTest1", e5.getTag());
374        assertEquals("DropBoxTest1", e6.getTag());
375        assertEquals(-1, getEntrySize(e2));  // Tombstone
376        assertEquals(blockSize - overhead, getEntrySize(e3));
377        assertEquals(blockSize * 2 - overhead, getEntrySize(e4));
378        assertEquals(blockSize - overhead, getEntrySize(e5));
379        assertEquals(-1, getEntrySize(e6));
380
381        assertEquals("DropBoxTest2", e7.getTag());
382        assertEquals("DropBoxTest2", e8.getTag());
383        assertEquals("DropBoxTest2", e9.getTag());
384        assertEquals(-1, getEntrySize(e7));  // Tombstone
385        assertEquals(blockSize - overhead, getEntrySize(e8));
386        assertEquals(blockSize - overhead, getEntrySize(e9));
387
388        e0.close();
389        e1.close();
390        e2.close();
391        e3.close();
392        e4.close();
393        e5.close();
394        e6.close();
395        e7.close();
396        e8.close();
397        e9.close();
398
399        // Specifying a tag name skips tombstone records.
400
401        DropBoxManager.Entry t0 = dropbox.getNextEntry("DropBoxTest1", before);
402        DropBoxManager.Entry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis());
403        DropBoxManager.Entry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis());
404        assertTrue(null == dropbox.getNextEntry("DropBoxTest1", t2.getTimeMillis()));
405
406        assertEquals("DropBoxTest1", t0.getTag());
407        assertEquals("DropBoxTest1", t1.getTag());
408        assertEquals("DropBoxTest1", t2.getTag());
409
410        assertEquals(blockSize - overhead, getEntrySize(t0));
411        assertEquals(blockSize * 2 - overhead, getEntrySize(t1));
412        assertEquals(blockSize - overhead, getEntrySize(t2));
413
414        t0.close();
415        t1.close();
416        t2.close();
417        service.stop();
418    }
419
420    public void testAgeLimits() throws Exception {
421        File dir = getEmptyDir("testAgeLimits");
422        int blockSize = new StatFs(dir.getPath()).getBlockSize();
423
424        // Limit storage to 10 blocks with an expiration of 1 second
425        int kb = blockSize * 10 / 1024;
426        ContentResolver cr = getContext().getContentResolver();
427        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_AGE_SECONDS, "1");
428        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, Integer.toString(kb));
429
430        // Write one normal entry and another so big that it is instantly tombstoned
431        long before = System.currentTimeMillis();
432        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
433        DropBoxManager dropbox = new DropBoxManager(service);
434
435        dropbox.addText("DropBoxTest", "TEST");
436        addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
437
438        // Verify that things are as expected
439        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
440        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
441        assertTrue(null == dropbox.getNextEntry(null, e1.getTimeMillis()));
442
443        assertEquals("TEST", e0.getText(80));
444        assertEquals(null, e1.getText(80));
445        assertEquals(-1, getEntrySize(e1));
446
447        e0.close();
448        e1.close();
449
450        // Wait a second and write another entry -- old ones should be expunged
451        Thread.sleep(2000);
452        dropbox.addText("DropBoxTest", "TEST1");
453
454        e0 = dropbox.getNextEntry(null, before);
455        assertTrue(null == dropbox.getNextEntry(null, e0.getTimeMillis()));
456        assertEquals("TEST1", e0.getText(80));
457        e0.close();
458    }
459
460    public void testCreateDropBoxManagerWithInvalidDirectory() throws Exception {
461        // If created with an invalid directory, the DropBoxManager should suffer quietly
462        // and fail all operations (this is how it survives a full disk).
463        // Once the directory becomes possible to create, it will start working.
464
465        File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
466        new FileOutputStream(dir).close();  // Create an empty file
467        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
468        DropBoxManager dropbox = new DropBoxManager(service);
469
470        dropbox.addText("DropBoxTest", "should be ignored");
471        dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
472        assertTrue(null == dropbox.getNextEntry("DropBoxTest", 0));
473
474        dir.delete();  // Remove the file so a directory can be created
475        dropbox.addText("DropBoxTest", "TEST");
476        DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", 0);
477        assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
478        assertEquals("DropBoxTest", e.getTag());
479        assertEquals("TEST", e.getText(80));
480        e.close();
481        service.stop();
482    }
483
484    private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
485        byte[] bytes = new byte[size];
486        new Random(System.currentTimeMillis()).nextBytes(bytes);
487
488        File f = new File(getEmptyDir("addRandomEntry"), "random.dat");
489        FileOutputStream os = new FileOutputStream(f);
490        os.write(bytes);
491        os.close();
492
493        dropbox.addFile(tag, f, 0);
494    }
495
496    private int getEntrySize(DropBoxManager.Entry e) throws Exception {
497        InputStream is = e.getInputStream();
498        if (is == null) return -1;
499        int length = 0;
500        while (is.read() != -1) length++;
501        return length;
502    }
503
504    private void recursiveDelete(File file) {
505        if (!file.delete() && file.isDirectory()) {
506            for (File f : file.listFiles()) recursiveDelete(f);
507            file.delete();
508        }
509    }
510
511    private File getEmptyDir(String name) {
512        File dir = getContext().getDir("DropBoxTest." + name, 0);
513        for (File f : dir.listFiles()) recursiveDelete(f);
514        assertTrue(dir.listFiles().length == 0);
515        return dir;
516    }
517}
518