1 /* 2 * Copyright 2009 Google, Inc. 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 4206909 4813885 27 * @summary Test basic functionality of DeflaterOutputStream/InflaterInputStream and GZIPOutputStream/GZIPInputStream, including flush 28 * @key randomness 29 */ 30 31 import java.io.*; 32 import java.util.*; 33 import java.util.zip.*; 34 35 public class InflateIn_DeflateOut { 36 37 private static class PairedInputStream extends ByteArrayInputStream { 38 private PairedOutputStream out = null; 39 private Random random; 40 41 public PairedInputStream() { 42 // The ByteArrayInputStream needs to start with a buffer, but we 43 // need to set it to have no data 44 super(new byte[1]); 45 count = 0; 46 pos = 0; 47 random = new Random(new Date().getTime()); 48 } 49 50 public void setPairedOutputStream(PairedOutputStream out) { 51 this.out = out; 52 } 53 54 private void maybeFlushPair() { 55 if (random.nextInt(100) < 10) { 56 out.flush(); 57 } 58 } 59 60 public int read() { 61 maybeFlushPair(); 62 return super.read(); 63 } 64 65 public int read(byte b[], int off, int len) { 66 maybeFlushPair(); 67 return super.read(b, off, len); 68 } 69 70 public void addBytes(byte[] bytes, int len) { 71 int oldavail = count - pos; 72 int newcount = oldavail + len; 73 byte[] newbuf = new byte[newcount]; 74 System.arraycopy(buf, pos, newbuf, 0, oldavail); 75 System.arraycopy(bytes, 0, newbuf, oldavail, len); 76 pos = 0; 77 count = newcount; 78 buf = newbuf; 79 } 80 } 81 82 private static class PairedOutputStream extends ByteArrayOutputStream { 83 private PairedInputStream pairedStream = null; 84 85 public PairedOutputStream(PairedInputStream inputPair) { 86 super(); 87 this.pairedStream = inputPair; 88 } 89 90 public void flush() { 91 if (count > 0) { 92 pairedStream.addBytes(buf, count); 93 reset(); 94 } 95 } 96 97 public void close() { 98 flush(); 99 } 100 } 101 102 private static boolean readFully(InputStream in, byte[] buf, int length) 103 throws IOException { 104 int pos = 0; 105 int n; 106 while ((n = in.read(buf, pos, length - pos)) > 0) { 107 pos += n; 108 if (pos == length) return true; 109 } 110 return false; 111 } 112 113 private static boolean readLineIfAvailable(InputStream in, StringBuilder sb) 114 throws IOException { 115 try { 116 while (in.available() > 0) { 117 int i = in.read(); 118 if (i < 0) break; 119 char c = (char) (((byte) i) & 0xff); 120 sb.append(c); 121 if (c == '\n') return true; 122 } 123 } catch (EOFException e) { 124 // empty 125 } 126 return false; 127 } 128 129 /** Check that written, closed and read */ 130 private static void WriteCloseRead() throws Throwable { 131 Random random = new Random(new Date().getTime()); 132 133 PairedInputStream pis = new PairedInputStream(); 134 InflaterInputStream iis = new InflaterInputStream(pis); 135 136 PairedOutputStream pos = new PairedOutputStream(pis); 137 pis.setPairedOutputStream(pos); 138 139 byte[] data = new byte[random.nextInt(1024 * 1024)]; 140 byte[] buf = new byte[data.length]; 141 random.nextBytes(data); 142 143 try (DeflaterOutputStream dos = new DeflaterOutputStream(pos, true)) { 144 dos.write(data); 145 } 146 check(readFully(iis, buf, buf.length)); 147 check(Arrays.equals(data, buf)); 148 } 149 150 private static void check(InputStream is, OutputStream os) 151 throws Throwable 152 { 153 Random random = new Random(new Date().getTime()); 154 // Large writes 155 for (int x = 0; x < 200 ; x++) { 156 // byte[] data = new byte[random.nextInt(1024 * 1024)]; 157 byte[] data = new byte[1024]; 158 byte[] buf = new byte[data.length]; 159 random.nextBytes(data); 160 161 os.write(data); 162 os.flush(); 163 check(readFully(is, buf, buf.length)); 164 check(Arrays.equals(data, buf)); 165 } 166 167 // Small writes 168 for (int x = 0; x < 2000 ; x++) { 169 byte[] data = new byte[random.nextInt(20) + 10]; 170 byte[] buf = new byte[data.length]; 171 random.nextBytes(data); 172 173 os.write(data); 174 os.flush(); 175 if (!readFully(is, buf, buf.length)) { 176 fail("Didn't read full buffer of " + buf.length); 177 } 178 check(Arrays.equals(data, buf)); 179 } 180 181 String quit = "QUIT\r\n"; 182 183 // Close it out 184 os.write(quit.getBytes()); 185 os.close(); 186 187 StringBuilder sb = new StringBuilder(); 188 check(readLineIfAvailable(is, sb)); 189 equal(sb.toString(), quit); 190 } 191 192 /** Check that written, flushed and read */ 193 private static void WriteFlushRead() throws Throwable { 194 PairedInputStream pis = new PairedInputStream(); 195 InflaterInputStream iis = new InflaterInputStream(pis); 196 197 PairedOutputStream pos = new PairedOutputStream(pis); 198 pis.setPairedOutputStream(pos); 199 DeflaterOutputStream dos = new DeflaterOutputStream(pos, true); 200 201 check(iis, dos); 202 } 203 204 private static void GZWriteFlushRead() throws Throwable { 205 PairedInputStream pis = new PairedInputStream(); 206 PairedOutputStream pos = new PairedOutputStream(pis); 207 pis.setPairedOutputStream(pos); 208 209 GZIPOutputStream gos = new GZIPOutputStream(pos, true); 210 gos.flush(); // flush the head out, so gis can read 211 GZIPInputStream gis = new GZIPInputStream(pis); 212 213 check(gis, gos); 214 } 215 216 private static void checkLOP(InputStream is, OutputStream os) 217 throws Throwable 218 { 219 boolean flushed = false; 220 int count = 0; 221 222 // Do at least a certain number of lines, but too many without a 223 // flush means this test isn't testing anything 224 while ((count < 10 && flushed) || (count < 1000 && !flushed)) { 225 String command = "PING " + count + "\r\n"; 226 os.write(command.getBytes()); 227 228 StringBuilder buf = new StringBuilder(); 229 if (!readLineIfAvailable(is, buf)) { 230 flushed = true; 231 os.flush(); 232 check(readLineIfAvailable(is, buf)); 233 } 234 equal(buf.toString(), command); 235 count++; 236 } 237 check(flushed); 238 } 239 240 /** Validate that we need to use flush at least once on a line 241 * oriented protocol */ 242 private static void LineOrientedProtocol() throws Throwable { 243 PairedInputStream pis = new PairedInputStream(); 244 InflaterInputStream iis = new InflaterInputStream(pis); 245 246 PairedOutputStream pos = new PairedOutputStream(pis); 247 pis.setPairedOutputStream(pos); 248 DeflaterOutputStream dos = new DeflaterOutputStream(pos, true); 249 250 checkLOP(iis, dos); 251 } 252 253 private static void GZLineOrientedProtocol() throws Throwable { 254 PairedInputStream pis = new PairedInputStream(); 255 PairedOutputStream pos = new PairedOutputStream(pis); 256 pis.setPairedOutputStream(pos); 257 258 GZIPOutputStream gos = new GZIPOutputStream(pos, true); 259 gos.flush(); // flush the head out, so gis can read 260 GZIPInputStream gis = new GZIPInputStream(pis); 261 262 checkLOP(gis, gos); 263 } 264 265 public static void realMain(String[] args) throws Throwable { 266 WriteCloseRead(); 267 WriteFlushRead(); 268 LineOrientedProtocol(); 269 GZWriteFlushRead(); 270 GZLineOrientedProtocol(); 271 } 272 273 //--------------------- Infrastructure --------------------------- 274 static volatile int passed = 0, failed = 0; 275 static void pass() {passed++;} 276 static void fail() {failed++; Thread.dumpStack();} 277 static void fail(String msg) {System.out.println(msg); fail();} 278 static void unexpected(Throwable t) {failed++; t.printStackTrace();} 279 static void check(boolean cond) {if (cond) pass(); else fail();} 280 static void equal(Object x, Object y) { 281 if (x == null ? y == null : x.equals(y)) pass(); 282 else fail(x + " not equal to " + y);} 283 public static void main(String[] args) throws Throwable { 284 try {realMain(args);} catch (Throwable t) {unexpected(t);} 285 System.out.println("\nPassed = " + passed + " failed = " + failed); 286 if (failed > 0) throw new AssertionError("Some tests failed");} 287 }