1/* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 8155808 27 * @run main SkipTest 28 * @summary verify skip method of Process Input Stream 29 */ 30 31import java.io.BufferedOutputStream; 32import java.io.File; 33import java.io.IOException; 34import java.io.InputStream; 35import java.io.OutputStream; 36 37public class SkipTest { 38 private static final String javaExe = 39 System.getProperty("java.home") + 40 File.separator + "bin" + File.separator + "java"; 41 42 private static final String classpath = 43 System.getProperty("java.class.path"); 44 45 static final int BLOCK_SIZE = 10000; 46 47 48 public static void main(String[] args) throws Throwable { 49 50 // Start a Process to generate the test data to stdout and stderr 51 ProcessBuilder pb = new ProcessBuilder(javaExe, "-classpath", classpath, "SkipTest$GenerateData"); 52 System.out.printf("cmd: %s%n", pb.command()); 53 Process process = pb.start(); 54 55 /* 56 * Verify the data expected is received mixing reads and skip. 57 */ 58 try (InputStream in = process.getInputStream()) { 59 60 // Note: Process.getInputStream() actually returns a BufferedInputStream whose 61 // skip() method works perfectly, partially obscuring the bug. Only when the 62 // BufferedInputStream's buffer is drained, and it passes the skip() call to 63 // the underlying native stream, does the problem occur. 64 65 long n = in.skip(-1); 66 if (n != 0) { 67 throw new AssertionError("skip(-1) should return 0"); 68 } 69 n = in.skip(0); 70 if (n != 0) { 71 throw new AssertionError("skip(0) should return 0"); 72 } 73 74 // Now iterate all the data blocks 75 int header; 76 for (int expectedHeader = 'A'; (header = in.read()) != -1; expectedHeader++) { 77 // The header byte should be simple 'A' to 'Z'. 78 // When the bug hits, we will get lowercase letters instead. 79 if (header != expectedHeader) { 80 throw new AssertionError("header char wrong, expected: " + 81 expectedHeader + ", actual: " + header); 82 } 83 84 // Handle the data bytes. 85 // If the correct number of bytes are not skipped, 86 // then subsequent reads become out-of-sync; 87 int remaining = BLOCK_SIZE; 88 do { 89 remaining -= in.skip(remaining); 90 } while (remaining != 0); 91 } 92 n = in.skip(1); 93 if (n != 0) { 94 throw new AssertionError("skip(1) at eof should return 0"); 95 } 96 } 97 98 /** 99 * Do the same for the standard error stream. 100 */ 101 try (InputStream in = process.getErrorStream()) { 102 long n = in.skip(-1); 103 if (n != 0) { 104 throw new AssertionError("skip(-1) should return 0"); 105 } 106 n = in.skip(0); 107 if (n != 0) { 108 throw new AssertionError("skip(0) should return 0"); 109 } 110 111 // Now iterate all the data blocks 112 int header; 113 for (int expectedHeader = 'A'; (header = in.read()) != -1; expectedHeader++) { 114 // The header byte should be simple 'A' to 'Z'. 115 // When the bug hits, we will get lowercase letters instead. 116 if (header != expectedHeader) { 117 throw new AssertionError("header char wrong, expected: " + 118 expectedHeader + ", actual: " + header); 119 } 120 121 // Handle the data bytes. 122 // If the correct number of bytes are not skipped, 123 // then subsequent reads become out-of-sync; 124 int remaining = BLOCK_SIZE; 125 do { 126 remaining -= in.skip(remaining); 127 } while (remaining != 0); 128 } 129 n = in.skip(1); 130 if (n != 0) { 131 throw new AssertionError("skip(1) at eof should return 0"); 132 } 133 } 134 } 135 136 /** 137 * Alternate main to generate the test data to standard output 138 * and standard error. 139 */ 140 static class GenerateData { 141 142 public static void main(String[] args) { 143 // Generate test data containing a series of data blocks of length BLOCK_SIZE, 144 // each with a one-byte header. For example's sake, the "header" is a capital letter, 145 // and the "data" is the lowercase version of that letter repeated BLOCK_SIZE times: 146 try (OutputStream out = new BufferedOutputStream(System.out)) { 147 for (int header = 'A'; header <= 'Z'; header++) { 148 out.write(header); 149 150 int data = Character.toLowerCase(header); 151 for (int i = 0; i < BLOCK_SIZE; i++) { 152 out.write(data); 153 } 154 } 155 } catch (IOException ioe) { 156 ioe.printStackTrace(); 157 System.exit(1); 158 } 159 // Generate the same data to the error output 160 try (OutputStream err = new BufferedOutputStream(System.err)) { 161 for (int header = 'A'; header <= 'Z'; header++) { 162 err.write(header); 163 164 int data = Character.toLowerCase(header); 165 for (int i = 0; i < BLOCK_SIZE; i++) { 166 err.write(data); 167 } 168 } 169 } catch (IOException ioe) { 170 ioe.printStackTrace(); 171 System.exit(1); 172 } 173 } 174 } 175} 176