|
4 | 4 | import gherkin.util.FixJava;
|
5 | 5 | import org.junit.After;
|
6 | 6 | import org.junit.Before;
|
| 7 | +import org.junit.Rule; |
7 | 8 | import org.junit.Test;
|
| 9 | +import org.junit.rules.TemporaryFolder; |
8 | 10 | import org.webbitserver.HttpControl;
|
9 | 11 | import org.webbitserver.HttpHandler;
|
10 | 12 | import org.webbitserver.HttpRequest;
|
|
27 | 29 | import java.nio.charset.Charset;
|
28 | 30 | import java.nio.file.Files;
|
29 | 31 | import java.nio.file.Path;
|
| 32 | +import java.util.ArrayList; |
| 33 | +import java.util.List; |
30 | 34 | import java.util.concurrent.BlockingQueue;
|
| 35 | +import java.util.concurrent.CountDownLatch; |
31 | 36 | import java.util.concurrent.ExecutionException;
|
32 | 37 | import java.util.concurrent.Executors;
|
33 | 38 | import java.util.concurrent.LinkedBlockingDeque;
|
34 | 39 | import java.util.concurrent.TimeUnit;
|
35 | 40 |
|
36 | 41 | import static org.junit.Assert.assertEquals;
|
| 42 | +import static org.junit.Assert.assertTrue; |
37 | 43 | import static org.junit.Assert.fail;
|
38 | 44 |
|
39 | 45 | public class URLOutputStreamTest {
|
40 | 46 | private WebServer webbit;
|
| 47 | + private final int threadsCount = 100; |
| 48 | + private final long waitTimeoutMillis = 30000L; |
| 49 | + private final List<File> tmpFiles = new ArrayList<File>(); |
| 50 | + private final List<String> threadErrors = new ArrayList<String>(); |
| 51 | + |
| 52 | + @Rule |
| 53 | + public TemporaryFolder tempFolder = new TemporaryFolder(); |
41 | 54 |
|
42 | 55 | @Before
|
43 | 56 | public void startWebbit() throws ExecutionException, InterruptedException {
|
@@ -127,7 +140,80 @@ public void handleHttpRequest(HttpRequest req, HttpResponse res, HttpControl ctl
|
127 | 140 | }
|
128 | 141 | }
|
129 | 142 |
|
| 143 | + @Test |
| 144 | + public void do_not_throw_ioe_if_parent_dir_created_by_another_thread() { |
| 145 | + final CountDownLatch countDownLatch = new CountDownLatch(1); |
| 146 | + List<Thread> testThreads = getThreadsWithLatchForFile(countDownLatch, threadsCount); |
| 147 | + startThreadsFromList(testThreads); |
| 148 | + countDownLatch.countDown(); |
| 149 | + waitAllThreadsFromList(testThreads); |
| 150 | + assertTrue("Not all parent folders were created for tmp file or tmp file was not created", isAllFilesCreated()); |
| 151 | + assertTrue("Some thread get error during work. Error list:" + threadErrors.toString(), threadErrors.isEmpty()); |
| 152 | + } |
| 153 | + |
130 | 154 | private Reader openUTF8FileReader(final File file) throws IOException {
|
131 | 155 | return new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
|
132 | 156 | }
|
| 157 | + |
| 158 | + private List<Thread> getThreadsWithLatchForFile(final CountDownLatch countDownLatch, int threadsCount) { |
| 159 | + List<Thread> result = new ArrayList<Thread>(); |
| 160 | + String ballast = "" + System.currentTimeMillis(); |
| 161 | + for (int i = 0; i < threadsCount; i++) { |
| 162 | + final int curThreadNo = i; |
| 163 | + // It useful when 2-3 threads (not more) tries to create the same directory for the report |
| 164 | + final File tmp = (i % 3 == 0 || i % 3 == 2) ? |
| 165 | + new File(tempFolder.getRoot().getAbsolutePath() + "/cuce" + ballast + i + "/tmpFile.tmp") : |
| 166 | + new File(tempFolder.getRoot().getAbsolutePath() + "/cuce" + ballast + (i - 1) + "/tmpFile.tmp"); |
| 167 | + tmpFiles.add(tmp); |
| 168 | + result.add(new Thread() { |
| 169 | + @Override |
| 170 | + public void run() { |
| 171 | + try { |
| 172 | + // Every thread should wait command to run |
| 173 | + countDownLatch.await(); |
| 174 | + new URLOutputStream(tmp.toURI().toURL()); |
| 175 | + } catch (IOException e) { |
| 176 | + threadErrors.add("Thread" + curThreadNo + ": parent dir not created. " + e.getMessage()); |
| 177 | + } catch (InterruptedException e) { |
| 178 | + threadErrors.add("Thread" + curThreadNo + ": not started on time. " + e.getMessage()); |
| 179 | + } |
| 180 | + } |
| 181 | + }); |
| 182 | + } |
| 183 | + return result; |
| 184 | + } |
| 185 | + |
| 186 | + private void startThreadsFromList(List<Thread> threads) { |
| 187 | + for (Thread thread : threads) { |
| 188 | + thread.start(); |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + private void waitAllThreadsFromList(List<Thread> threads) { |
| 193 | + long timeStart = System.currentTimeMillis(); |
| 194 | + do { |
| 195 | + // Protection from forever loop |
| 196 | + if (System.currentTimeMillis() - timeStart > waitTimeoutMillis) { |
| 197 | + assertTrue("Some threads are still alive", false); |
| 198 | + } |
| 199 | + } while (hasListAliveThreads(threads)); |
| 200 | + } |
| 201 | + |
| 202 | + private boolean hasListAliveThreads(List<Thread> threads) { |
| 203 | + for (Thread thread : threads) { |
| 204 | + if (thread.isAlive()) { |
| 205 | + return true; |
| 206 | + } |
| 207 | + } |
| 208 | + return false; |
| 209 | + } |
| 210 | + |
| 211 | + private boolean isAllFilesCreated() { |
| 212 | + for (File tmpFile : tmpFiles) { |
| 213 | + if (tmpFile.getParentFile() == null || !tmpFile.getParentFile().isDirectory() || !tmpFile.exists()) { |
| 214 | + return false; |
| 215 | + } |
| 216 | + } |
| 217 | + return true; |
| 218 | + } |
133 | 219 | }
|
0 commit comments