@Test
  public void testPageBlobCopyWithMetadataOverride()
      throws URISyntaxException, StorageException, IOException, InterruptedException {
    Calendar calendar = Calendar.getInstance(Utility.UTC_ZONE);
    CloudPageBlob source = this.container.getPageBlobReference("source");

    byte[] buffer = BlobTestHelper.getRandomBuffer(512);
    ByteArrayInputStream stream = new ByteArrayInputStream(buffer);

    source.upload(stream, buffer.length);

    source.getMetadata().put("Test", "value");
    source.uploadMetadata();

    CloudPageBlob copy = this.container.getPageBlobReference("copy");
    copy.getMetadata().put("Test2", "value2");
    String copyId = copy.startCopy(BlobTestHelper.defiddler(source));
    BlobTestHelper.waitForCopy(copy);

    assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus());
    assertEquals(source.getQualifiedUri().getPath(), copy.getCopyState().getSource().getPath());
    assertEquals(buffer.length, copy.getCopyState().getTotalBytes().intValue());
    assertEquals(buffer.length, copy.getCopyState().getBytesCopied().intValue());
    assertEquals(copyId, copy.getCopyState().getCopyId());
    assertTrue(
        copy.getCopyState()
                .getCompletionTime()
                .compareTo(new Date(calendar.get(Calendar.MINUTE) - 1))
            > 0);

    ByteArrayOutputStream copyStream = new ByteArrayOutputStream();
    copy.download(copyStream);
    BlobTestHelper.assertStreamsAreEqual(
        stream, new ByteArrayInputStream(copyStream.toByteArray()));

    copy.downloadAttributes();
    source.downloadAttributes();
    BlobProperties prop1 = copy.getProperties();
    BlobProperties prop2 = source.getProperties();

    assertEquals(prop1.getCacheControl(), prop2.getCacheControl());
    assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding());
    assertEquals(prop1.getContentDisposition(), prop2.getContentDisposition());
    assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage());
    assertEquals(prop1.getContentMD5(), prop2.getContentMD5());
    assertEquals(prop1.getContentType(), prop2.getContentType());

    assertEquals("value2", copy.getMetadata().get("Test2"));
    assertFalse(copy.getMetadata().containsKey("Test"));

    copy.delete();
  }
  /**
   * Constructs a HttpURLConnection to set the blob's properties, Sign with zero length specified.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection putBlockList(
      final URI uri,
      final int timeout,
      final BlobProperties properties,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws IOException, URISyntaxException, StorageException {

    final UriQueryBuilder builder = new UriQueryBuilder();
    builder.add("comp", "blocklist");

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);

    request.setDoOutput(true);
    request.setRequestMethod("PUT");

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    BaseRequest.addOptionalHeader(
        request, Constants.HeaderConstants.CACHE_CONTROL_HEADER, properties.getCacheControl());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.CONTENT_ENCODING_HEADER, properties.getContentEncoding());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.CONTENT_LANGUAGE_HEADER, properties.getContentLanguage());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.BLOB_CONTENT_MD5_HEADER, properties.getContentMD5());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.CONTENT_TYPE_HEADER, properties.getContentType());

    return request;
  }
  /**
   * Constructs a HttpURLConnection to upload a blob. Sign with blob length, or -1 for pageblob
   * create.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param properties The properties to set for the blob.
   * @param blobType The type of the blob.
   * @param pageBlobSize For a page blob, the size of the blob. This parameter is ignored for block
   *     blobs.
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection put(
      final URI uri,
      final int timeout,
      final BlobProperties properties,
      final BlobType blobType,
      final long pageBlobSize,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws IOException, URISyntaxException, StorageException {
    if (blobType == BlobType.UNSPECIFIED) {
      throw new IllegalArgumentException("The blob type cannot be undefined.");
    }

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, null, blobOptions, opContext);

    request.setDoOutput(true);

    request.setRequestMethod("PUT");

    // use set optional header
    BaseRequest.addOptionalHeader(
        request, Constants.HeaderConstants.CACHE_CONTROL, properties.getCacheControl());
    BaseRequest.addOptionalHeader(
        request, Constants.HeaderConstants.CONTENT_TYPE, properties.getContentType());
    BaseRequest.addOptionalHeader(
        request, Constants.HeaderConstants.CONTENT_MD5, properties.getContentMD5());
    BaseRequest.addOptionalHeader(
        request, Constants.HeaderConstants.CONTENT_LANGUAGE, properties.getContentLanguage());
    BaseRequest.addOptionalHeader(
        request, Constants.HeaderConstants.CONTENT_ENCODING, properties.getContentEncoding());

    if (blobType == BlobType.PAGE_BLOB) {
      request.setFixedLengthStreamingMode(0);
      request.setRequestProperty(Constants.HeaderConstants.CONTENT_LENGTH, "0");

      request.setRequestProperty(BlobConstants.BLOB_TYPE_HEADER, BlobConstants.PAGE_BLOB);
      request.setRequestProperty(BlobConstants.SIZE, String.valueOf(pageBlobSize));

      properties.setLength(pageBlobSize);
    } else {
      request.setRequestProperty(BlobConstants.BLOB_TYPE_HEADER, BlobConstants.BLOCK_BLOB);
    }

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    return request;
  }
  @Test
  public void testPageBlobCopyFromSnapshot()
      throws StorageException, IOException, URISyntaxException, InterruptedException {
    CloudPageBlob source = this.container.getPageBlobReference("source");

    byte[] buffer = BlobTestHelper.getRandomBuffer(512);
    ByteArrayInputStream stream = new ByteArrayInputStream(buffer);

    source.upload(stream, buffer.length);

    source.getMetadata().put("Test", "value");
    source.uploadMetadata();

    CloudPageBlob snapshot = (CloudPageBlob) source.createSnapshot();

    // Modify source
    byte[] buffer2 = BlobTestHelper.getRandomBuffer(512);
    ByteArrayInputStream stream2 = new ByteArrayInputStream(buffer2);
    source.getMetadata().put("Test", "newvalue");
    source.uploadMetadata();
    source.getProperties().setContentMD5(null);
    source.upload(stream2, buffer.length);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    source.download(outputStream);

    ByteArrayOutputStream snapshotStream = new ByteArrayOutputStream();
    snapshot.download(snapshotStream);
    BlobTestHelper.assertStreamsAreEqual(
        stream2, new ByteArrayInputStream(outputStream.toByteArray()));
    BlobTestHelper.assertStreamsAreEqual(
        stream, new ByteArrayInputStream(snapshotStream.toByteArray()));

    source.downloadAttributes();
    snapshot.downloadAttributes();
    assertFalse(source.getMetadata().get("Test").equals(snapshot.getMetadata().get("Test")));

    CloudPageBlob copy = this.container.getPageBlobReference("copy");
    String copyId = copy.startCopy(BlobTestHelper.defiddler(snapshot));
    BlobTestHelper.waitForCopy(copy);

    ByteArrayOutputStream copyStream = new ByteArrayOutputStream();
    copy.download(copyStream);

    assertEquals(CopyStatus.SUCCESS, copy.getCopyState().getStatus());
    BlobTestHelper.assertStreamsAreEqual(
        stream, new ByteArrayInputStream(copyStream.toByteArray()));
    assertEquals(copyId, copy.getProperties().getCopyState().getCopyId());

    copy.downloadAttributes();
    BlobProperties prop1 = copy.getProperties();
    BlobProperties prop2 = snapshot.getProperties();

    assertEquals(prop1.getCacheControl(), prop2.getCacheControl());
    assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding());
    assertEquals(prop1.getContentDisposition(), prop2.getContentDisposition());
    assertEquals(prop1.getContentLanguage(), prop2.getContentLanguage());
    assertEquals(prop1.getContentMD5(), prop2.getContentMD5());
    assertEquals(prop1.getContentType(), prop2.getContentType());

    assertEquals("value", copy.getMetadata().get("Test"));

    copy.delete();
  }