a7abf7ca9740942285d8f14f13009ebc8ce3b58a
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / test / java / org / opendaylight / controller / cluster / io / FileBackedOutputStreamTest.java
1 /*
2  * Copyright (c) 2017 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.cluster.io;
9
10 import static org.junit.Assert.assertArrayEquals;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16
17 import com.google.common.base.Stopwatch;
18 import com.google.common.util.concurrent.Uninterruptibles;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.util.Arrays;
23 import java.util.concurrent.TimeUnit;
24 import org.junit.After;
25 import org.junit.AfterClass;
26 import org.junit.Before;
27 import org.junit.BeforeClass;
28 import org.junit.Test;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * Unit tests for FileBackedOutputStream.
34  *
35  * @author Thomas Pantelis
36  */
37 public class FileBackedOutputStreamTest {
38     private static final Logger LOG = LoggerFactory.getLogger(FileBackedOutputStreamTest.class);
39     private static final String TEMP_DIR = "target/FileBackedOutputStreamTest";
40
41     @BeforeClass
42     public static void staticSetup() {
43         createDir(TEMP_DIR);
44     }
45
46     @AfterClass
47     public static void staticCleanup() {
48         deleteTempFiles(TEMP_DIR);
49         deleteFile(TEMP_DIR);
50     }
51
52     @Before
53     public void setup() {
54         deleteTempFiles(TEMP_DIR);
55         FileBackedOutputStream.REFERENCE_CACHE.clear();
56     }
57
58     @After
59     public void cleanup() {
60         deleteTempFiles(TEMP_DIR);
61     }
62
63     @Test
64     public void testFileThresholdNotReached() throws IOException {
65         LOG.info("testFileThresholdNotReached starting");
66         try (FileBackedOutputStream fbos = new FileBackedOutputStream(10, TEMP_DIR)) {
67             byte[] bytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
68             fbos.write(bytes[0]);
69             fbos.write(bytes, 1, bytes.length - 1);
70
71             assertEquals("getCount", bytes.length, fbos.getCount());
72             assertNull("Found unexpected temp file", findTempFileName(TEMP_DIR));
73             assertEquals("Size", bytes.length, fbos.asByteSource().size());
74
75             // Read bytes twice.
76             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
77             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
78
79             assertEquals("Reference cache size", 0, FileBackedOutputStream.REFERENCE_CACHE.size());
80
81             fbos.cleanup();
82         }
83
84         LOG.info("testFileThresholdNotReached ending");
85     }
86
87     @Test
88     public void testFileThresholdReachedWithWriteBytes() throws IOException {
89         LOG.info("testFileThresholdReachedWithWriteBytes starting");
90         try (FileBackedOutputStream fbos = new FileBackedOutputStream(10, TEMP_DIR)) {
91             byte[] bytes = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
92             fbos.write(bytes[0]);
93             fbos.write(bytes, 1, 11);
94
95             String tempFileName = findTempFileName(TEMP_DIR);
96             assertNotNull("Expected temp file created", tempFileName);
97
98             fbos.write(bytes[12]);
99             fbos.write(bytes, 13, bytes.length - 13);
100
101             assertEquals("Temp file", tempFileName, findTempFileName(TEMP_DIR));
102             assertEquals("Size", bytes.length, fbos.asByteSource().size());
103
104             InputStream inputStream = fbos.asByteSource().openStream();
105
106             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
107
108             byte[] inBytes = new byte[bytes.length];
109             assertEquals("# bytes read", bytes.length, inputStream.read(inBytes));
110             assertArrayEquals("Read InputStream", bytes, inBytes);
111             assertEquals("End of stream", -1, inputStream.read());
112
113             inputStream.close();
114
115             assertEquals("Reference cache size", 1, FileBackedOutputStream.REFERENCE_CACHE.size());
116
117             fbos.cleanup();
118
119             assertEquals("Reference cache size", 0, FileBackedOutputStream.REFERENCE_CACHE.size());
120
121             assertNull("Found unexpected temp file", findTempFileName(TEMP_DIR));
122         }
123
124         LOG.info("testFileThresholdReachedWithWriteBytes ending");
125     }
126
127     @Test
128     public void testFileThresholdReachedWithWriteByte() throws IOException {
129         LOG.info("testFileThresholdReachedWithWriteByte starting");
130         try (FileBackedOutputStream fbos = new FileBackedOutputStream(2, TEMP_DIR)) {
131             byte[] bytes = new byte[]{0, 1, 2};
132             fbos.write(bytes[0]);
133             fbos.write(bytes[1]);
134
135             assertNull("Found unexpected temp file", findTempFileName(TEMP_DIR));
136
137             fbos.write(bytes[2]);
138             fbos.flush();
139
140             assertNotNull("Expected temp file created", findTempFileName(TEMP_DIR));
141
142             assertEquals("Size", bytes.length, fbos.asByteSource().size());
143             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
144         }
145
146         LOG.info("testFileThresholdReachedWithWriteByte ending");
147     }
148
149     @Test(expected = IOException.class)
150     public void testWriteAfterAsByteSource() throws IOException {
151         LOG.info("testWriteAfterAsByteSource starting");
152         try (FileBackedOutputStream fbos = new FileBackedOutputStream(3, TEMP_DIR)) {
153             byte[] bytes = new byte[]{0, 1, 2};
154             fbos.write(bytes);
155
156             assertNull("Found unexpected temp file", findTempFileName(TEMP_DIR));
157             assertEquals("Size", bytes.length, fbos.asByteSource().size());
158
159             // Should throw IOException after call to asByteSource.
160             fbos.write(1);
161         }
162     }
163
164     @Test
165     public void testTempFileDeletedOnGC() throws IOException {
166         LOG.info("testTempFileDeletedOnGC starting");
167
168         FileBackedOutputStream fbos = null;
169         try {
170             fbos = new FileBackedOutputStream(1, TEMP_DIR);
171             fbos.write(new byte[] {0, 1});
172             assertNotNull("Expected temp file created", findTempFileName(TEMP_DIR));
173         } finally {
174             if (fbos != null) {
175                 fbos.close();
176             }
177             fbos = null;
178         }
179
180         Stopwatch sw = Stopwatch.createStarted();
181         while (sw.elapsed(TimeUnit.SECONDS) <= 20) {
182             System.gc();
183             if (findTempFileName(TEMP_DIR) == null) {
184                 return;
185             }
186             Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
187         }
188
189         fail("Temp file was not deleted");
190     }
191
192     static String findTempFileName(String dirPath) {
193         String[] files = new File(dirPath).list();
194         assertNotNull(files);
195         assertTrue("Found more than one temp file: " + Arrays.toString(files), files.length < 2);
196         return files.length == 1 ? files[0] : null;
197     }
198
199     static boolean deleteFile(String file) {
200         return new File(file).delete();
201     }
202
203     static void deleteTempFiles(String path) {
204         String[] files = new File(path).list();
205         if (files != null) {
206             for (String file: files) {
207                 deleteFile(path + File.separator + file);
208             }
209         }
210     }
211
212     static void createDir(String path) {
213         File dir = new File(path);
214         if (!dir.exists() && !dir.mkdirs()) {
215             throw new RuntimeException("Failed to create temp dir " + path);
216         }
217     }
218 }