bcb1850d8c30cef9b204a9a3666f7fb51c5ba1bf
[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         File dir = new File(TEMP_DIR);
44         if (!dir.exists() && !dir.mkdirs()) {
45             throw new RuntimeException("Failed to create temp dir " + TEMP_DIR);
46         }
47     }
48
49     @AfterClass
50     public static void staticCleanup() {
51         deleteTempFiles();
52         deleteFile(TEMP_DIR);
53     }
54
55     @Before
56     public void setup() {
57         deleteTempFiles();
58         FileBackedOutputStream.REFERENCE_CACHE.clear();
59     }
60
61     @After
62     public void cleanup() {
63         deleteTempFiles();
64     }
65
66     @Test
67     public void testFileThresholdNotReached() throws IOException {
68         LOG.info("testFileThresholdNotReached starting");
69         try (FileBackedOutputStream fbos = new FileBackedOutputStream(10, TEMP_DIR)) {
70             byte[] bytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
71             fbos.write(bytes[0]);
72             fbos.write(bytes, 1, bytes.length - 1);
73
74             assertEquals("getCount", bytes.length, fbos.getCount());
75             assertNull("Found unexpected temp file", findTempFileName());
76             assertEquals("Size", bytes.length, fbos.asByteSource().size());
77
78             // Read bytes twice.
79             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
80             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
81
82             assertEquals("Reference cache size", 0, FileBackedOutputStream.REFERENCE_CACHE.size());
83
84             fbos.cleanup();
85         }
86
87         LOG.info("testFileThresholdNotReached ending");
88     }
89
90     @Test
91     public void testFileThresholdReachedWithWriteBytes() throws IOException {
92         LOG.info("testFileThresholdReachedWithWriteBytes starting");
93         try (FileBackedOutputStream fbos = new FileBackedOutputStream(10, TEMP_DIR)) {
94             byte[] bytes = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
95             fbos.write(bytes[0]);
96             fbos.write(bytes, 1, 11);
97
98             String tempFileName = findTempFileName();
99             assertNotNull("Expected temp file created", tempFileName);
100
101             fbos.write(bytes[12]);
102             fbos.write(bytes, 13, bytes.length - 13);
103
104             assertEquals("Temp file", tempFileName, findTempFileName());
105             assertEquals("Size", bytes.length, fbos.asByteSource().size());
106
107             InputStream inputStream = fbos.asByteSource().openStream();
108
109             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
110
111             byte[] inBytes = new byte[bytes.length];
112             assertEquals("# bytes read", bytes.length, inputStream.read(inBytes));
113             assertArrayEquals("Read InputStream", bytes, inBytes);
114             assertEquals("End of stream", -1, inputStream.read());
115
116             inputStream.close();
117
118             assertEquals("Reference cache size", 1, FileBackedOutputStream.REFERENCE_CACHE.size());
119
120             fbos.cleanup();
121
122             assertEquals("Reference cache size", 0, FileBackedOutputStream.REFERENCE_CACHE.size());
123
124             assertNull("Found unexpected temp file", findTempFileName());
125         }
126
127         LOG.info("testFileThresholdReachedWithWriteBytes ending");
128     }
129
130     @Test
131     public void testFileThresholdReachedWithWriteByte() throws IOException {
132         LOG.info("testFileThresholdReachedWithWriteByte starting");
133         try (FileBackedOutputStream fbos = new FileBackedOutputStream(2, TEMP_DIR)) {
134             byte[] bytes = new byte[]{0, 1, 2};
135             fbos.write(bytes[0]);
136             fbos.write(bytes[1]);
137
138             assertNull("Found unexpected temp file", findTempFileName());
139
140             fbos.write(bytes[2]);
141             fbos.flush();
142
143             assertNotNull("Expected temp file created", findTempFileName());
144
145             assertEquals("Size", bytes.length, fbos.asByteSource().size());
146             assertArrayEquals("Read bytes", bytes, fbos.asByteSource().read());
147         }
148
149         LOG.info("testFileThresholdReachedWithWriteByte ending");
150     }
151
152     @Test(expected = IOException.class)
153     public void testWriteAfterAsByteSource() throws IOException {
154         LOG.info("testWriteAfterAsByteSource starting");
155         try (FileBackedOutputStream fbos = new FileBackedOutputStream(3, TEMP_DIR)) {
156             byte[] bytes = new byte[]{0, 1, 2};
157             fbos.write(bytes);
158
159             assertNull("Found unexpected temp file", findTempFileName());
160             assertEquals("Size", bytes.length, fbos.asByteSource().size());
161
162             // Should throw IOException after call to asByteSource.
163             fbos.write(1);
164         }
165     }
166
167     @Test
168     public void testTempFileDeletedOnGC() throws IOException {
169         LOG.info("testTempFileDeletedOnGC starting");
170
171         FileBackedOutputStream fbos = null;
172         try {
173             fbos = new FileBackedOutputStream(1, TEMP_DIR);
174             fbos.write(new byte[] {0, 1});
175             assertNotNull("Expected temp file created", findTempFileName());
176         } finally {
177             if (fbos != null) {
178                 fbos.close();
179             }
180             fbos = null;
181         }
182
183         Stopwatch sw = Stopwatch.createStarted();
184         while (sw.elapsed(TimeUnit.SECONDS) <= 20) {
185             System.gc();
186             if (findTempFileName() == null) {
187                 return;
188             }
189             Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
190         }
191
192         fail("Temp file was not deleted");
193     }
194
195     private static String findTempFileName() {
196         String[] files = new File(TEMP_DIR).list();
197         assertNotNull(files);
198         assertTrue("Found more than one temp file: " + Arrays.toString(files), files.length < 2);
199         return files.length == 1 ? files[0] : null;
200     }
201
202     private static boolean deleteFile(String file) {
203         return new File(file).delete();
204     }
205
206     private static void deleteTempFiles() {
207         String[] files = new File(TEMP_DIR).list();
208         if (files != null) {
209             for (String file: files) {
210                 deleteFile(TEMP_DIR + File.separator + file);
211             }
212         }
213     }
214 }