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 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Copyright (C) 2009-2010, Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.util.io;
  11. import static org.junit.Assert.assertArrayEquals;
  12. import static org.junit.Assert.assertEquals;
  13. import static org.junit.Assert.assertFalse;
  14. import static org.junit.Assert.assertTrue;
  15. import static org.junit.Assert.fail;
  16. import java.io.IOException;
  17. import java.io.InterruptedIOException;
  18. import java.io.OutputStream;
  19. import java.io.PipedInputStream;
  20. import java.io.PipedOutputStream;
  21. import java.util.Arrays;
  22. import java.util.List;
  23. import org.eclipse.jgit.util.IO;
  24. import org.junit.After;
  25. import org.junit.Before;
  26. import org.junit.Test;
  27. public class TimeoutOutputStreamTest {
  28. private static final int timeout = 250;
  29. private PipedOutputStream out;
  30. private FullPipeInputStream in;
  31. private InterruptTimer timer;
  32. private TimeoutOutputStream os;
  33. private long start;
  34. @Before
  35. public void setUp() throws Exception {
  36. out = new PipedOutputStream();
  37. in = new FullPipeInputStream(out);
  38. timer = new InterruptTimer();
  39. os = new TimeoutOutputStream(out, timer);
  40. os.setTimeout(timeout);
  41. }
  42. @After
  43. public void tearDown() throws Exception {
  44. timer.terminate();
  45. for (Thread t : active())
  46. assertFalse(t instanceof InterruptTimer.AlarmThread);
  47. }
  48. @Test
  49. public void testTimeout_writeByte_Success1() throws IOException {
  50. in.free(1);
  51. os.write('a');
  52. in.want(1);
  53. assertEquals('a', in.read());
  54. }
  55. @Test
  56. public void testTimeout_writeByte_Success2() throws IOException {
  57. final byte[] exp = new byte[] { 'a', 'b', 'c' };
  58. final byte[] act = new byte[exp.length];
  59. in.free(exp.length);
  60. os.write(exp[0]);
  61. os.write(exp[1]);
  62. os.write(exp[2]);
  63. in.want(exp.length);
  64. in.read(act);
  65. assertArrayEquals(exp, act);
  66. }
  67. @Test
  68. public void testTimeout_writeByte_Timeout() throws IOException {
  69. beginWrite();
  70. try {
  71. os.write('\n');
  72. fail("incorrectly write a byte");
  73. } catch (InterruptedIOException e) {
  74. // expected
  75. }
  76. assertTimeout();
  77. }
  78. @Test
  79. public void testTimeout_writeBuffer_Success1() throws IOException {
  80. final byte[] exp = new byte[] { 'a', 'b', 'c' };
  81. final byte[] act = new byte[exp.length];
  82. in.free(exp.length);
  83. os.write(exp);
  84. in.want(exp.length);
  85. in.read(act);
  86. assertArrayEquals(exp, act);
  87. }
  88. @Test
  89. public void testTimeout_writeBuffer_Timeout() throws IOException {
  90. beginWrite();
  91. try {
  92. os.write(new byte[512]);
  93. fail("incorrectly wrote bytes");
  94. } catch (InterruptedIOException e) {
  95. // expected
  96. }
  97. assertTimeout();
  98. }
  99. @Test
  100. public void testTimeout_flush_Success() throws IOException {
  101. final boolean[] called = new boolean[1];
  102. os = new TimeoutOutputStream(new OutputStream() {
  103. @Override
  104. public void write(int b) throws IOException {
  105. fail("should not have written");
  106. }
  107. @Override
  108. public void flush() throws IOException {
  109. called[0] = true;
  110. }
  111. }, timer);
  112. os.setTimeout(timeout);
  113. os.flush();
  114. assertTrue(called[0]);
  115. }
  116. @Test
  117. public void testTimeout_flush_Timeout() throws IOException {
  118. final boolean[] called = new boolean[1];
  119. os = new TimeoutOutputStream(new OutputStream() {
  120. @Override
  121. public void write(int b) throws IOException {
  122. fail("should not have written");
  123. }
  124. @Override
  125. public void flush() throws IOException {
  126. called[0] = true;
  127. for (;;) {
  128. try {
  129. Thread.sleep(1000);
  130. } catch (InterruptedException e) {
  131. InterruptedIOException e1 = new InterruptedIOException();
  132. e1.initCause(e);
  133. throw e1;
  134. }
  135. }
  136. }
  137. }, timer);
  138. os.setTimeout(timeout);
  139. beginWrite();
  140. try {
  141. os.flush();
  142. fail("incorrectly flushed");
  143. } catch (InterruptedIOException e) {
  144. // expected
  145. }
  146. assertTimeout();
  147. assertTrue(called[0]);
  148. }
  149. @Test
  150. public void testTimeout_close_Success() 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 close() throws IOException {
  159. called[0] = true;
  160. }
  161. }, timer);
  162. os.setTimeout(timeout);
  163. os.close();
  164. assertTrue(called[0]);
  165. }
  166. @Test
  167. public void testTimeout_close_Timeout() throws IOException {
  168. final boolean[] called = new boolean[1];
  169. os = new TimeoutOutputStream(new OutputStream() {
  170. @Override
  171. public void write(int b) throws IOException {
  172. fail("should not have written");
  173. }
  174. @Override
  175. public void close() throws IOException {
  176. called[0] = true;
  177. for (;;) {
  178. try {
  179. Thread.sleep(1000);
  180. } catch (InterruptedException e) {
  181. InterruptedIOException e1 = new InterruptedIOException();
  182. e1.initCause(e);
  183. throw e1;
  184. }
  185. }
  186. }
  187. }, timer);
  188. os.setTimeout(timeout);
  189. beginWrite();
  190. try {
  191. os.close();
  192. fail("incorrectly closed");
  193. } catch (InterruptedIOException e) {
  194. // expected
  195. }
  196. assertTimeout();
  197. assertTrue(called[0]);
  198. }
  199. private void beginWrite() {
  200. start = now();
  201. }
  202. private void assertTimeout() {
  203. // Our timeout was supposed to be ~250 ms. Since this is a timing
  204. // test we can't assume we spent *exactly* the timeout period, as
  205. // there may be other activity going on in the system. Instead we
  206. // look for the delta between the start and end times to be within
  207. // 50 ms of the expected timeout.
  208. //
  209. final long wait = now() - start;
  210. assertTrue("waited only " + wait + " ms", timeout - wait < 50);
  211. }
  212. private static List<Thread> active() {
  213. Thread[] all = new Thread[16];
  214. int n = Thread.currentThread().getThreadGroup().enumerate(all);
  215. while (n == all.length) {
  216. all = new Thread[all.length * 2];
  217. n = Thread.currentThread().getThreadGroup().enumerate(all);
  218. }
  219. return Arrays.asList(all).subList(0, n);
  220. }
  221. private static long now() {
  222. return System.currentTimeMillis();
  223. }
  224. private static final class FullPipeInputStream extends PipedInputStream {
  225. FullPipeInputStream(PipedOutputStream src) throws IOException {
  226. super(src);
  227. src.write(new byte[PIPE_SIZE]);
  228. }
  229. void want(int cnt) throws IOException {
  230. IO.skipFully(this, PIPE_SIZE - cnt);
  231. }
  232. void free(int cnt) throws IOException {
  233. IO.skipFully(this, cnt);
  234. }
  235. }
  236. }