blob: 6fd7e2ee3ed3b03a6f2be3aee9c894010f1083d6 [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.util.io;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.io.ByteStreams;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Test for {@link StreamMultiplexer}.
*/
@RunWith(JUnit4.class)
public class StreamMultiplexerTest {
private ByteArrayOutputStream multiplexed;
private OutputStream out;
private OutputStream err;
private OutputStream ctl;
@Before
public final void createOutputStreams() throws Exception {
multiplexed = new ByteArrayOutputStream();
StreamMultiplexer multiplexer = new StreamMultiplexer(multiplexed);
out = multiplexer.createStdout();
err = multiplexer.createStderr();
ctl = multiplexer.createControl();
}
@Test
public void testEmptyWire() throws IOException {
out.flush();
err.flush();
ctl.flush();
assertThat(multiplexed.toByteArray()).isEmpty();
}
private static byte[] getLatin(String string)
throws UnsupportedEncodingException {
return string.getBytes("ISO-8859-1");
}
@Test
public void testHelloWorldOnStdOut() throws Exception {
out.write(getLatin("Hello, world."));
out.flush();
assertMessage(multiplexed.toByteArray(), 0, "Hello, world.");
}
@Test
public void testInterleavedStdoutStderrControl() throws Exception {
int start = 0;
out.write(getLatin("Hello, stdout."));
out.flush();
assertMessage(multiplexed.toByteArray(), start, "Hello, stdout.");
start = multiplexed.toByteArray().length;
err.write(getLatin("Hello, stderr."));
err.flush();
assertMessage(multiplexed.toByteArray(), start, "Hello, stderr.");
start = multiplexed.toByteArray().length;
ctl.write(getLatin("Hello, control."));
ctl.flush();
assertMessage(multiplexed.toByteArray(), start, "Hello, control.");
start = multiplexed.toByteArray().length;
out.write(getLatin("... and back!"));
out.flush();
assertMessage(multiplexed.toByteArray(), start, "... and back!");
}
@Test
public void testWillNotCommitToUnderlyingStreamUnlessFlushOrNewline()
throws Exception {
out.write(getLatin("There are no newline characters in here, so it won't" +
" get written just yet."));
assertThat(new byte[0]).isEqualTo(multiplexed.toByteArray());
}
@Test
public void testNewlineTriggersFlush() throws Exception {
out.write(getLatin("No newline just yet, so no flushing. "));
assertThat(new byte[0]).isEqualTo(multiplexed.toByteArray());
out.write(getLatin("OK, here we go:\nAnd more to come."));
assertMessage(
multiplexed.toByteArray(), 0, "No newline just yet, so no flushing. OK, here we go:\n");
int firstMessageLength = multiplexed.toByteArray().length;
out.write((byte) '\n');
assertMessage(multiplexed.toByteArray(), firstMessageLength, "And more to come.\n");
}
@Test
public void testFlush() throws Exception {
out.write(getLatin("Don't forget to flush!"));
assertThat(multiplexed.toByteArray()).isEqualTo(new byte[0]);
out.flush(); // now the output will appear in multiplexed.
assertStartsWith(multiplexed.toByteArray(), 1, 0, 0, 0);
assertMessage(multiplexed.toByteArray(), 0, "Don't forget to flush!");
}
@Test
public void testByteEncoding() throws IOException {
OutputStream devNull = ByteStreams.nullOutputStream();
StreamDemultiplexer demux = new StreamDemultiplexer((byte) 1, devNull);
StreamMultiplexer mux = new StreamMultiplexer(demux);
OutputStream out = mux.createStdout();
// When we cast 266 to a byte, we get 10. So basically, we ended up
// comparing 266 with 10 as an integer (because out.write takes an int),
// and then later cast it to 10. This way we'd end up with a control
// character \n in the middle of the payload which would then screw things
// up when the real control character arrived. The fixed version of the
// StreamMultiplexer avoids this problem by always casting to a byte before
// carrying out any comparisons.
out.write(266);
out.write(10);
}
private static void assertStartsWith(byte[] actual, int... expectedPrefix){
for (int i = 0; i < expectedPrefix.length; i++) {
assertThat(actual[i]).isEqualTo(expectedPrefix[i]);
}
}
private static void assertMessage(byte[] actual, int start, String expected) throws Exception {
assertThat(Arrays.copyOfRange(actual, start + 5, actual.length)).isEqualTo(getLatin(expected));
}
}