You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TimeoutOutputStreamTest.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * Copyright (C) 2009-2010, Google Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.util.io;
  44. import static org.junit.Assert.assertArrayEquals;
  45. import static org.junit.Assert.assertEquals;
  46. import static org.junit.Assert.assertFalse;
  47. import static org.junit.Assert.assertTrue;
  48. import static org.junit.Assert.fail;
  49. import java.io.IOException;
  50. import java.io.InterruptedIOException;
  51. import java.io.OutputStream;
  52. import java.io.PipedInputStream;
  53. import java.io.PipedOutputStream;
  54. import java.util.Arrays;
  55. import java.util.List;
  56. import org.eclipse.jgit.util.IO;
  57. import org.junit.After;
  58. import org.junit.Before;
  59. import org.junit.Test;
  60. public class TimeoutOutputStreamTest {
  61. private static final int timeout = 250;
  62. private PipedOutputStream out;
  63. private FullPipeInputStream in;
  64. private InterruptTimer timer;
  65. private TimeoutOutputStream os;
  66. private long start;
  67. @Before
  68. public void setUp() throws Exception {
  69. out = new PipedOutputStream();
  70. in = new FullPipeInputStream(out);
  71. timer = new InterruptTimer();
  72. os = new TimeoutOutputStream(out, timer);
  73. os.setTimeout(timeout);
  74. }
  75. @After
  76. public void tearDown() throws Exception {
  77. timer.terminate();
  78. for (Thread t : active())
  79. assertFalse(t instanceof InterruptTimer.AlarmThread);
  80. }
  81. @Test
  82. public void testTimeout_writeByte_Success1() throws IOException {
  83. in.free(1);
  84. os.write('a');
  85. in.want(1);
  86. assertEquals('a', in.read());
  87. }
  88. @Test
  89. public void testTimeout_writeByte_Success2() throws IOException {
  90. final byte[] exp = new byte[] { 'a', 'b', 'c' };
  91. final byte[] act = new byte[exp.length];
  92. in.free(exp.length);
  93. os.write(exp[0]);
  94. os.write(exp[1]);
  95. os.write(exp[2]);
  96. in.want(exp.length);
  97. in.read(act);
  98. assertArrayEquals(exp, act);
  99. }
  100. @Test
  101. public void testTimeout_writeByte_Timeout() throws IOException {
  102. beginWrite();
  103. try {
  104. os.write('\n');
  105. fail("incorrectly write a byte");
  106. } catch (InterruptedIOException e) {
  107. // expected
  108. }
  109. assertTimeout();
  110. }
  111. @Test
  112. public void testTimeout_writeBuffer_Success1() throws IOException {
  113. final byte[] exp = new byte[] { 'a', 'b', 'c' };
  114. final byte[] act = new byte[exp.length];
  115. in.free(exp.length);
  116. os.write(exp);
  117. in.want(exp.length);
  118. in.read(act);
  119. assertArrayEquals(exp, act);
  120. }
  121. @Test
  122. public void testTimeout_writeBuffer_Timeout() throws IOException {
  123. beginWrite();
  124. try {
  125. os.write(new byte[512]);
  126. fail("incorrectly wrote bytes");
  127. } catch (InterruptedIOException e) {
  128. // expected
  129. }
  130. assertTimeout();
  131. }
  132. @Test
  133. public void testTimeout_flush_Success() throws IOException {
  134. final boolean[] called = new boolean[1];
  135. os = new TimeoutOutputStream(new OutputStream() {
  136. @Override
  137. public void write(int b) throws IOException {
  138. fail("should not have written");
  139. }
  140. @Override
  141. public void flush() throws IOException {
  142. called[0] = true;
  143. }
  144. }, timer);
  145. os.setTimeout(timeout);
  146. os.flush();
  147. assertTrue(called[0]);
  148. }
  149. @Test
  150. public void testTimeout_flush_Timeout() throws IOException {
  151. final boolean[] called = new boolean[1];
  152. os = new TimeoutOutputStream(new OutputStream() {
  153. @Override
  154. public void write(int b) throws IOException {
  155. fail("should not have written");
  156. }
  157. @Override
  158. public void flush() throws IOException {
  159. called[0] = true;
  160. for (;;) {
  161. try {
  162. Thread.sleep(1000);
  163. } catch (InterruptedException e) {
  164. throw new InterruptedIOException();
  165. }
  166. }
  167. }
  168. }, timer);
  169. os.setTimeout(timeout);
  170. beginWrite();
  171. try {
  172. os.flush();
  173. fail("incorrectly flushed");
  174. } catch (InterruptedIOException e) {
  175. // expected
  176. }
  177. assertTimeout();
  178. assertTrue(called[0]);
  179. }
  180. @Test
  181. public void testTimeout_close_Success() throws IOException {
  182. final boolean[] called = new boolean[1];
  183. os = new TimeoutOutputStream(new OutputStream() {
  184. @Override
  185. public void write(int b) throws IOException {
  186. fail("should not have written");
  187. }
  188. @Override
  189. public void close() throws IOException {
  190. called[0] = true;
  191. }
  192. }, timer);
  193. os.setTimeout(timeout);
  194. os.close();
  195. assertTrue(called[0]);
  196. }
  197. @Test
  198. public void testTimeout_close_Timeout() throws IOException {
  199. final boolean[] called = new boolean[1];
  200. os = new TimeoutOutputStream(new OutputStream() {
  201. @Override
  202. public void write(int b) throws IOException {
  203. fail("should not have written");
  204. }
  205. @Override
  206. public void close() throws IOException {
  207. called[0] = true;
  208. for (;;) {
  209. try {
  210. Thread.sleep(1000);
  211. } catch (InterruptedException e) {
  212. throw new InterruptedIOException();
  213. }
  214. }
  215. }
  216. }, timer);
  217. os.setTimeout(timeout);
  218. beginWrite();
  219. try {
  220. os.close();
  221. fail("incorrectly closed");
  222. } catch (InterruptedIOException e) {
  223. // expected
  224. }
  225. assertTimeout();
  226. assertTrue(called[0]);
  227. }
  228. private void beginWrite() {
  229. start = now();
  230. }
  231. private void assertTimeout() {
  232. // Our timeout was supposed to be ~250 ms. Since this is a timing
  233. // test we can't assume we spent *exactly* the timeout period, as
  234. // there may be other activity going on in the system. Instead we
  235. // look for the delta between the start and end times to be within
  236. // 50 ms of the expected timeout.
  237. //
  238. final long wait = now() - start;
  239. assertTrue("waited only " + wait + " ms", timeout - wait < 50);
  240. }
  241. private static List<Thread> active() {
  242. Thread[] all = new Thread[16];
  243. int n = Thread.currentThread().getThreadGroup().enumerate(all);
  244. while (n == all.length) {
  245. all = new Thread[all.length * 2];
  246. n = Thread.currentThread().getThreadGroup().enumerate(all);
  247. }
  248. return Arrays.asList(all).subList(0, n);
  249. }
  250. private static long now() {
  251. return System.currentTimeMillis();
  252. }
  253. private final class FullPipeInputStream extends PipedInputStream {
  254. FullPipeInputStream(PipedOutputStream src) throws IOException {
  255. super(src);
  256. src.write(new byte[PIPE_SIZE]);
  257. }
  258. void want(int cnt) throws IOException {
  259. IO.skipFully(this, PIPE_SIZE - cnt);
  260. }
  261. void free(int cnt) throws IOException {
  262. IO.skipFully(this, cnt);
  263. }
  264. }
  265. }