View Javadoc
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  
11  package org.eclipse.jgit.transport;
12  
13  import static java.lang.Integer.valueOf;
14  import static java.nio.charset.StandardCharsets.UTF_8;
15  import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA;
16  import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR;
17  import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
18  import static org.eclipse.jgit.transport.SideBandOutputStream.HDR_SIZE;
19  import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
20  import static org.eclipse.jgit.transport.SideBandOutputStream.SMALL_BUF;
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.fail;
23  
24  import java.io.ByteArrayOutputStream;
25  import java.io.IOException;
26  import java.io.OutputStream;
27  import java.text.MessageFormat;
28  
29  import org.eclipse.jgit.internal.JGitText;
30  import org.junit.Before;
31  import org.junit.Test;
32  
33  // Note, test vectors created with:
34  //
35  // perl -e 'printf "%4.4x%s\n", 4+length($ARGV[0]),$ARGV[0]'
36  
37  public class SideBandOutputStreamTest {
38  	private ByteArrayOutputStream rawOut;
39  
40  	@Before
41  	public void setUp() throws Exception {
42  		rawOut = new ByteArrayOutputStream();
43  	}
44  
45  	@Test
46  	public void testWrite_CH_DATA() throws IOException {
47  		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
48  				SMALL_BUF, rawOut)) {
49  			out.write(new byte[] { 'a', 'b', 'c' });
50  			out.flush();
51  		}
52  		assertBuffer("0008\001abc");
53  	}
54  
55  	@Test
56  	public void testWrite_CH_PROGRESS() throws IOException {
57  		try (SideBandOutputStream out = new SideBandOutputStream(CH_PROGRESS,
58  				SMALL_BUF, rawOut)) {
59  			out.write(new byte[] { 'a', 'b', 'c' });
60  			out.flush();
61  		}
62  		assertBuffer("0008\002abc");
63  	}
64  
65  	@Test
66  	public void testWrite_CH_ERROR() throws IOException {
67  		try (SideBandOutputStream out = new SideBandOutputStream(CH_ERROR,
68  				SMALL_BUF, rawOut)) {
69  			out.write(new byte[] { 'a', 'b', 'c' });
70  			out.flush();
71  		}
72  		assertBuffer("0008\003abc");
73  	}
74  
75  	@Test
76  	public void testWrite_Small() throws IOException {
77  		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
78  				SMALL_BUF, rawOut)) {
79  			out.write('a');
80  			out.write('b');
81  			out.write('c');
82  			out.flush();
83  		}
84  		assertBuffer("0008\001abc");
85  	}
86  
87  	@Test
88  	public void testWrite_SmallBlocks1() throws IOException {
89  		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 6,
90  				rawOut)) {
91  			out.write('a');
92  			out.write('b');
93  			out.write('c');
94  			out.flush();
95  		}
96  		assertBuffer("0006\001a0006\001b0006\001c");
97  	}
98  
99  	@Test
100 	public void testWrite_SmallBlocks2() throws IOException {
101 		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 6,
102 				rawOut)) {
103 			out.write(new byte[] { 'a', 'b', 'c' });
104 			out.flush();
105 		}
106 		assertBuffer("0006\001a0006\001b0006\001c");
107 	}
108 
109 	@Test
110 	public void testWrite_SmallBlocks3() throws IOException {
111 		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA, 7,
112 				rawOut)) {
113 			out.write('a');
114 			out.write(new byte[] { 'b', 'c' });
115 			out.flush();
116 		}
117 		assertBuffer("0007\001ab0006\001c");
118 	}
119 
120 	@Test
121 	public void testWrite_Large() throws IOException {
122 		final int buflen = MAX_BUF - HDR_SIZE;
123 		final byte[] buf = new byte[buflen];
124 		for (int i = 0; i < buf.length; i++) {
125 			buf[i] = (byte) i;
126 		}
127 
128 		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
129 				MAX_BUF, rawOut)) {
130 			out.write(buf);
131 			out.flush();
132 		}
133 
134 		final byte[] act = rawOut.toByteArray();
135 		final String explen = Integer.toString(buf.length + HDR_SIZE, 16);
136 		assertEquals(HDR_SIZE + buf.length, act.length);
137 		assertEquals(new String(act, 0, 4, "UTF-8"), explen);
138 		assertEquals(1, act[4]);
139 		for (int i = 0, j = HDR_SIZE; i < buf.length; i++, j++) {
140 			assertEquals(buf[i], act[j]);
141 		}
142 	}
143 
144 	@Test
145 	public void testFlush() throws IOException {
146 		final int[] flushCnt = new int[1];
147 		final OutputStream mockout = new OutputStream() {
148 			@Override
149 			public void write(int arg0) throws IOException {
150 				fail("should not write");
151 			}
152 
153 			@Override
154 			public void flush() throws IOException {
155 				flushCnt[0]++;
156 			}
157 		};
158 
159 		try (SideBandOutputStream out = new SideBandOutputStream(CH_DATA,
160 				SMALL_BUF, mockout)) {
161 			out.flush();
162 		}
163 		assertEquals(1, flushCnt[0]);
164 	}
165 
166 	private void createSideBandOutputStream(int chan, int sz, OutputStream os)
167 			throws Exception {
168 		try (SideBandOutputStream s = new SideBandOutputStream(chan, sz, os)) {
169 			// Unused
170 		}
171 	}
172 
173 	@Test
174 	public void testConstructor_RejectsBadChannel() throws Exception {
175 		try {
176 			createSideBandOutputStream(-1, MAX_BUF, rawOut);
177 			fail("Accepted -1 channel number");
178 		} catch (IllegalArgumentException e) {
179 			assertEquals("channel -1 must be in range [1, 255]", e.getMessage());
180 		}
181 
182 		try {
183 			createSideBandOutputStream(0, MAX_BUF, rawOut);
184 			fail("Accepted 0 channel number");
185 		} catch (IllegalArgumentException e) {
186 			assertEquals("channel 0 must be in range [1, 255]", e.getMessage());
187 		}
188 
189 		try {
190 			createSideBandOutputStream(256, MAX_BUF, rawOut);
191 			fail("Accepted 256 channel number");
192 		} catch (IllegalArgumentException e) {
193 			assertEquals("channel 256 must be in range [1, 255]", e
194 					.getMessage());
195 		}
196 	}
197 
198 	@Test
199 	public void testConstructor_RejectsBadBufferSize() throws Exception {
200 		try {
201 			createSideBandOutputStream(CH_DATA, -1, rawOut);
202 			fail("Accepted -1 for buffer size");
203 		} catch (IllegalArgumentException e) {
204 			assertEquals("packet size -1 must be >= 5", e.getMessage());
205 		}
206 
207 		try {
208 			createSideBandOutputStream(CH_DATA, 0, rawOut);
209 			fail("Accepted 0 for buffer size");
210 		} catch (IllegalArgumentException e) {
211 			assertEquals("packet size 0 must be >= 5", e.getMessage());
212 		}
213 
214 		try {
215 			createSideBandOutputStream(CH_DATA, 1, rawOut);
216 			fail("Accepted 1 for buffer size");
217 		} catch (IllegalArgumentException e) {
218 			assertEquals("packet size 1 must be >= 5", e.getMessage());
219 		}
220 
221 		try {
222 			createSideBandOutputStream(CH_DATA, Integer.MAX_VALUE, rawOut);
223 			fail("Accepted " + Integer.MAX_VALUE + " for buffer size");
224 		} catch (IllegalArgumentException e) {
225 			assertEquals(MessageFormat.format(
226 					JGitText.get().packetSizeMustBeAtMost,
227 					valueOf(Integer.MAX_VALUE), valueOf(65520)), e.getMessage());
228 		}
229 	}
230 
231 	private void assertBuffer(String exp) {
232 		assertEquals(exp, new String(rawOut.toByteArray(), UTF_8));
233 	}
234 }