1 /*
   2  * Copyright (c) 2001, 2017, 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 /* @test
  25  * @bug 4434723 4482726 4559072 4795550 5081340 5103988 6984545
  26  * @summary Test FileChannel.transferFrom and transferTo (use -Dseed=X to set PRNG seed)
  27  * @library ..
  28  * @library /test/lib
  29  * @run testng/timeout=300 Transfer
  30  * @key randomness
  31  */
  32 
  33 import java.io.BufferedReader;
  34 import java.io.File;
  35 import java.io.FileInputStream;
  36 import java.io.FileOutputStream;
  37 import java.io.InputStreamReader;
  38 import java.io.IOException;
  39 import java.io.RandomAccessFile;
  40 import java.io.Reader;
  41 import java.net.InetAddress;
  42 import java.net.InetSocketAddress;
  43 import java.nio.ByteBuffer;
  44 import java.nio.channels.FileChannel;
  45 import java.nio.channels.NonReadableChannelException;
  46 import java.nio.channels.Pipe;
  47 import java.nio.channels.ServerSocketChannel;
  48 import java.nio.channels.SocketChannel;
  49 import java.nio.channels.spi.SelectorProvider;
  50 import java.util.Random;
  51 import java.util.concurrent.TimeUnit;
  52 
  53 import jdk.test.lib.RandomFactory;
  54 
  55 import org.testng.annotations.Test;
  56 
  57 public class Transfer {
  58 
  59     private static Random generator = RandomFactory.getRandom();
  60 
  61     @Test
  62     public void testFileChannel() throws Exception {
  63         File source = File.createTempFile("source", null);
  64         source.deleteOnExit();
  65         File sink = File.createTempFile("sink", null);
  66         sink.deleteOnExit();
  67 
  68         FileOutputStream fos = new FileOutputStream(source);
  69         FileChannel sourceChannel = fos.getChannel();
  70         sourceChannel.write(ByteBuffer.wrap(
  71             "Use the source, Luke!".getBytes()));
  72         sourceChannel.close();
  73 
  74         FileInputStream fis = new FileInputStream(source);
  75         sourceChannel = fis.getChannel();
  76 
  77         RandomAccessFile raf = new RandomAccessFile(sink, "rw");
  78         FileChannel sinkChannel = raf.getChannel();
  79         long oldSinkPosition = sinkChannel.position();
  80         long oldSourcePosition = sourceChannel.position();
  81 
  82         long bytesWritten = sinkChannel.transferFrom(sourceChannel, 0, 10);
  83         if (bytesWritten != 10)
  84             throw new RuntimeException("Transfer failed");
  85 
  86         if (sourceChannel.position() == oldSourcePosition)
  87             throw new RuntimeException("Source position didn't change");
  88 
  89         if (sinkChannel.position() != oldSinkPosition)
  90             throw new RuntimeException("Sink position changed");
  91 
  92         if (sinkChannel.size() != 10)
  93             throw new RuntimeException("Unexpected sink size");
  94 
  95         bytesWritten = sinkChannel.transferFrom(sourceChannel, 1000, 10);
  96 
  97         if (bytesWritten > 0)
  98             throw new RuntimeException("Wrote past file size");
  99 
 100         sourceChannel.close();
 101         sinkChannel.close();
 102 
 103         source.delete();
 104         sink.delete();
 105     }
 106 
 107     @Test
 108     public void testReadableByteChannel() throws Exception {
 109         int[] testSizes = { 0, 10, 1023, 1024, 1025, 2047, 2048, 2049 };
 110 
 111         for (int size : testSizes) {
 112             SelectorProvider sp = SelectorProvider.provider();
 113             Pipe p = sp.openPipe();
 114             Pipe.SinkChannel sink = p.sink();
 115             Pipe.SourceChannel source = p.source();
 116             sink.configureBlocking(false);
 117 
 118             ByteBuffer outgoingdata = ByteBuffer.allocateDirect(size + 10);
 119             byte[] someBytes = new byte[size + 10];
 120             generator.nextBytes(someBytes);
 121             outgoingdata.put(someBytes);
 122             outgoingdata.flip();
 123 
 124             int totalWritten = 0;
 125             while (totalWritten < size + 10) {
 126                 int written = sink.write(outgoingdata);
 127                 if (written < 0)
 128                     throw new Exception("Write failed");
 129                 totalWritten += written;
 130             }
 131 
 132             File f = File.createTempFile("blah"+size, null);
 133             f.deleteOnExit();
 134             RandomAccessFile raf = new RandomAccessFile(f, "rw");
 135             FileChannel fc = raf.getChannel();
 136             long oldPosition = fc.position();
 137 
 138             long bytesWritten = fc.transferFrom(source, 0, size);
 139             fc.force(true);
 140             if (bytesWritten != size)
 141                 throw new RuntimeException("Transfer failed");
 142 
 143             if (fc.position() != oldPosition)
 144                 throw new RuntimeException("Position changed");
 145 
 146             if (fc.size() != size)
 147                 throw new RuntimeException("Unexpected sink size "+ fc.size());
 148 
 149             fc.close();
 150             sink.close();
 151             source.close();
 152 
 153             f.delete();
 154         }
 155     }
 156 
 157     @Test
 158     public void xferTest02() throws Exception { // for bug 4482726
 159         byte[] srcData = new byte[5000];
 160         for (int i=0; i<5000; i++)
 161             srcData[i] = (byte)generator.nextInt();
 162 
 163         // get filechannel for the source file.
 164         File source = File.createTempFile("source", null);
 165         source.deleteOnExit();
 166         RandomAccessFile raf1 = new RandomAccessFile(source, "rw");
 167         FileChannel fc1 = raf1.getChannel();
 168 
 169         // write out data to the file channel
 170         long bytesWritten = 0;
 171         while (bytesWritten < 5000) {
 172             bytesWritten = fc1.write(ByteBuffer.wrap(srcData));
 173         }
 174 
 175         // get filechannel for the dst file.
 176         File dest = File.createTempFile("dest", null);
 177         dest.deleteOnExit();
 178         RandomAccessFile raf2 = new RandomAccessFile(dest, "rw");
 179         FileChannel fc2 = raf2.getChannel();
 180 
 181         int bytesToWrite = 3000;
 182         int startPosition = 1000;
 183 
 184         bytesWritten = fc1.transferTo(startPosition, bytesToWrite, fc2);
 185 
 186         fc1.close();
 187         fc2.close();
 188         raf1.close();
 189         raf2.close();
 190 
 191         source.delete();
 192         dest.delete();
 193     }
 194 
 195     @Test
 196     public void xferTest03() throws Exception { // for bug 4559072
 197         byte[] srcData = new byte[] {1,2,3,4} ;
 198 
 199         // get filechannel for the source file.
 200         File source = File.createTempFile("source", null);
 201         source.deleteOnExit();
 202         RandomAccessFile raf1 = new RandomAccessFile(source, "rw");
 203         FileChannel fc1 = raf1.getChannel();
 204         fc1.truncate(0);
 205 
 206         // write out data to the file channel
 207         int bytesWritten = 0;
 208         while (bytesWritten < 4) {
 209             bytesWritten = fc1.write(ByteBuffer.wrap(srcData));
 210         }
 211 
 212         // get filechannel for the dst file.
 213         File dest = File.createTempFile("dest", null);
 214         dest.deleteOnExit();
 215         RandomAccessFile raf2 = new RandomAccessFile(dest, "rw");
 216         FileChannel fc2 = raf2.getChannel();
 217         fc2.truncate(0);
 218 
 219         fc1.transferTo(0, srcData.length + 1, fc2);
 220 
 221         if (fc2.size() > 4)
 222             throw new Exception("xferTest03 failed");
 223 
 224         fc1.close();
 225         fc2.close();
 226         raf1.close();
 227         raf2.close();
 228 
 229         source.delete();
 230         dest.delete();
 231     }
 232 
 233     // xferTest04() and xferTest05() moved to Transfer4GBFile.java
 234 
 235     static void checkFileData(File file, String expected) throws Exception {
 236         FileInputStream fis = new FileInputStream(file);
 237         Reader r = new BufferedReader(new InputStreamReader(fis, "ASCII"));
 238         StringBuilder sb = new StringBuilder();
 239         int c;
 240         while ((c = r.read()) != -1)
 241             sb.append((char)c);
 242         String contents = sb.toString();
 243         if (! contents.equals(expected))
 244             throw new Exception("expected: " + expected
 245                                 + ", got: " + contents);
 246         r.close();
 247     }
 248 
 249     // Test transferFrom asking for more bytes than remain in source
 250     @Test
 251     public void xferTest06() throws Exception { // for bug 5081340
 252         String data = "Use the source, Luke!";
 253 
 254         File source = File.createTempFile("source", null);
 255         source.deleteOnExit();
 256         File sink = File.createTempFile("sink", null);
 257         sink.deleteOnExit();
 258 
 259         FileOutputStream fos = new FileOutputStream(source);
 260         fos.write(data.getBytes("ASCII"));
 261         fos.close();
 262 
 263         FileChannel sourceChannel =
 264             new RandomAccessFile(source, "rw").getChannel();
 265         sourceChannel.position(7);
 266         long remaining = sourceChannel.size() - sourceChannel.position();
 267         FileChannel sinkChannel =
 268             new RandomAccessFile(sink, "rw").getChannel();
 269         long n = sinkChannel.transferFrom(sourceChannel, 0L,
 270                                           sourceChannel.size()); // overflow
 271         if (n != remaining)
 272             throw new Exception("n == " + n + ", remaining == " + remaining);
 273 
 274         sinkChannel.close();
 275         sourceChannel.close();
 276 
 277         checkFileData(source, data);
 278         checkFileData(sink, data.substring(7,data.length()));
 279 
 280         source.delete();
 281     }
 282 
 283     // Test transferTo to non-blocking socket channel
 284     @Test
 285     public void xferTest07() throws Exception { // for bug 5103988
 286         File source = File.createTempFile("source", null);
 287         source.deleteOnExit();
 288 
 289         FileChannel sourceChannel = new RandomAccessFile(source, "rw")
 290             .getChannel();
 291         sourceChannel.position(32000L)
 292             .write(ByteBuffer.wrap("The End".getBytes()));
 293 
 294         // The sink is a non-blocking socket channel
 295         ServerSocketChannel ssc = ServerSocketChannel.open();
 296         ssc.socket().bind(new InetSocketAddress(0));
 297         InetSocketAddress sa = new InetSocketAddress(
 298             InetAddress.getLocalHost(), ssc.socket().getLocalPort());
 299         SocketChannel sink = SocketChannel.open(sa);
 300         sink.configureBlocking(false);
 301         SocketChannel other = ssc.accept();
 302 
 303         long size = sourceChannel.size();
 304 
 305         // keep sending until congested
 306         long n;
 307         do {
 308             n = sourceChannel.transferTo(0, size, sink);
 309         } while (n > 0);
 310 
 311         sourceChannel.close();
 312         sink.close();
 313         other.close();
 314         ssc.close();
 315         source.delete();
 316     }
 317 
 318     // xferTest08() moved to TransferTo6GBFile.java
 319 
 320     // Test that transferFrom with FileChannel source that is not readable
 321     // throws NonReadableChannelException
 322     @Test
 323     public void xferTest09() throws Exception { // for bug 6984545
 324         File source = File.createTempFile("source", null);
 325         source.deleteOnExit();
 326 
 327         File target = File.createTempFile("target", null);
 328         target.deleteOnExit();
 329 
 330         FileChannel fc1 = new FileOutputStream(source).getChannel();
 331         FileChannel fc2 = new RandomAccessFile(target, "rw").getChannel();
 332         try {
 333             fc2.transferFrom(fc1, 0L, 0);
 334             throw new RuntimeException("NonReadableChannelException expected");
 335         } catch (NonReadableChannelException expected) {
 336         } finally {
 337             fc1.close();
 338             fc2.close();
 339         }
 340     }
 341 }