@Test
  public void testReadFetchResponse() throws IOException {
    final String base64EncodedData =
        "AAAALgAAAAEAIDAwMDAwMDAwMDEwMDAwMDAwMDAwMDA4MDAwMDAwMDAwAAAAANcwdr5kYXRh";
    final RuleKey ruleKey = new RuleKey("00000000010000000000008000000000");
    final String data = "data";

    byte[] expectedData;
    try (ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dataOut = new DataOutputStream(out)) {
      byte[] metadata =
          HttpArtifactCacheBinaryProtocol.createMetadataHeader(
              ImmutableSet.of(ruleKey),
              ImmutableMap.<String, String>of(),
              ByteSource.wrap(data.getBytes(Charsets.UTF_8)));
      dataOut.writeInt(metadata.length);
      dataOut.write(metadata);
      dataOut.write(data.getBytes(Charsets.UTF_8));
      expectedData = out.toByteArray();
    }
    assertThat(expectedData, Matchers.equalTo(BaseEncoding.base64().decode(base64EncodedData)));

    try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(expectedData))) {
      FetchResponseReadResult result =
          HttpArtifactCacheBinaryProtocol.readFetchResponse(inputStream, outputStream);
      assertThat(result.getRuleKeys(), Matchers.contains(ruleKey));
      assertThat(outputStream.toByteArray(), Matchers.equalTo(data.getBytes(Charsets.UTF_8)));
      assertThat(result.getActualHashCode(), Matchers.equalTo(HashCode.fromString("d73076be")));
      assertThat(result.getExpectedHashCode(), Matchers.equalTo(HashCode.fromString("d73076be")));
      assertThat(result.getMetadata(), Matchers.anEmptyMap());
      assertThat(result.getResponseSizeBytes(), Matchers.equalTo(4L));
    }
  }
  @Test
  public void testFetchResponse() throws IOException {
    RuleKey ruleKey = new RuleKey("00000000000000000000000000000000");
    RuleKey ruleKey2 = new RuleKey("90000000000000000000008000000005");
    final String data = "data";
    ImmutableMap<String, String> metadata = ImmutableMap.of("metaKey", "metaValue");

    HttpArtifactCacheBinaryProtocol.FetchResponse fetchResponse =
        new HttpArtifactCacheBinaryProtocol.FetchResponse(
            ImmutableSet.of(ruleKey, ruleKey2),
            metadata,
            new ByteSource() {
              @Override
              public InputStream openStream() throws IOException {
                return new ByteArrayInputStream(data.getBytes(Charsets.UTF_8));
              }
            });
    assertThat(fetchResponse.getContentLength(), Matchers.is(110L));

    ByteArrayOutputStream fetchResponseOutputStream = new ByteArrayOutputStream();
    fetchResponse.write(fetchResponseOutputStream);

    ByteArrayInputStream fetchResponseInputStream =
        new ByteArrayInputStream(fetchResponseOutputStream.toByteArray());
    ByteArrayOutputStream fetchResponsePayload = new ByteArrayOutputStream();
    FetchResponseReadResult responseReadResult =
        HttpArtifactCacheBinaryProtocol.readFetchResponse(
            new DataInputStream(fetchResponseInputStream), fetchResponsePayload);

    assertThat(responseReadResult.getRuleKeys(), Matchers.containsInAnyOrder(ruleKey, ruleKey2));
    assertThat(responseReadResult.getMetadata(), Matchers.equalTo(metadata));
    assertThat(fetchResponsePayload.toByteArray(), Matchers.equalTo(data.getBytes(Charsets.UTF_8)));
  }
  @Test
  public void testStoreRequest() throws IOException {
    final RuleKey ruleKey = new RuleKey("00000000010000000000008000000000");
    final RuleKey ruleKey2 = new RuleKey("90000000000000000000008000000005");
    final String data = "data";
    ImmutableMap<String, String> metadata = ImmutableMap.of("metaKey", "metaValue");

    HttpArtifactCacheBinaryProtocol.StoreRequest storeRequest =
        new HttpArtifactCacheBinaryProtocol.StoreRequest(
            ArtifactInfo.builder().addRuleKeys(ruleKey, ruleKey2).setMetadata(metadata).build(),
            new ByteSource() {
              @Override
              public InputStream openStream() throws IOException {
                return new ByteArrayInputStream(data.getBytes(Charsets.UTF_8));
              }
            });

    ByteArrayOutputStream storeRequestOutputStream = new ByteArrayOutputStream();
    storeRequest.write(storeRequestOutputStream);

    ByteArrayOutputStream storeRequestPayloadStream = new ByteArrayOutputStream();
    StoreResponseReadResult readStoreRequest =
        HttpArtifactCacheBinaryProtocol.readStoreRequest(
            new DataInputStream(new ByteArrayInputStream(storeRequestOutputStream.toByteArray())),
            storeRequestPayloadStream);

    assertThat(readStoreRequest.getRuleKeys(), Matchers.containsInAnyOrder(ruleKey, ruleKey2));
    assertThat(readStoreRequest.getMetadata(), Matchers.equalTo(metadata));
    assertThat(
        storeRequestPayloadStream.toByteArray(), Matchers.equalTo(data.getBytes(Charsets.UTF_8)));
  }
 @Test
 public void testCreateKeysHeader() throws IOException {
   final String base64EncodedData =
       "AAAAAgAgMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAIDkwMDAwMDAwMDAwMDAwMDAw"
           + "MDAwMDA4MDAwMDAwMDA1";
   final RuleKey ruleKey = new RuleKey("00000000000000000000000000000000");
   final RuleKey ruleKey2 = new RuleKey("90000000000000000000008000000005");
   byte[] keysHeader =
       HttpArtifactCacheBinaryProtocol.createKeysHeader(ImmutableSet.of(ruleKey, ruleKey2));
   assertThat(keysHeader, Matchers.equalTo(BaseEncoding.base64().decode(base64EncodedData)));
 }
 @Test
 public void testCreateMetadataHeader() throws IOException {
   final String base64EncodedData =
       "AAAAAQAgMDAwMDAwMDAwMTAwMDAwMDAwMDAwMDgwMDAwMDAwMDAAAAABAANrZXkAAAAFdmFsdWVc/GBY";
   final RuleKey ruleKey = new RuleKey("00000000010000000000008000000000");
   final String data = "data";
   byte[] metadata =
       HttpArtifactCacheBinaryProtocol.createMetadataHeader(
           ImmutableSet.of(ruleKey),
           ImmutableMap.of("key", "value"),
           ByteSource.wrap(data.getBytes(Charsets.UTF_8)));
   assertThat(metadata, Matchers.equalTo(BaseEncoding.base64().decode(base64EncodedData)));
 }
  @Test
  public void testMassiveMetadataHeaderRead() throws IOException {
    byte[] bytes;
    try (ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dataOut = new DataOutputStream(out)) {
      dataOut.writeInt(Integer.MAX_VALUE);
      bytes = out.toByteArray();
    }

    try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
      thrown.expect(IOException.class);
      thrown.expectMessage(Matchers.containsString("too big"));
      HttpArtifactCacheBinaryProtocol.readFetchResponse(
          new DataInputStream(inputStream), ByteStreams.nullOutputStream());
    }
  }
  @Test
  public void testMassiveMetadataHeaderWrite() throws IOException {
    ImmutableMap.Builder<String, String> metadataBuilder = ImmutableMap.builder();
    long metadataSize = 65 * 1024 * 1024;
    StringBuilder valueBuilder = new StringBuilder();
    for (int i = 0; i < 16384; ++i) {
      valueBuilder.append('x');
    }
    final String value = valueBuilder.toString();
    final long valueLength = value.getBytes(Charsets.UTF_8).length;

    while (metadataSize > 0) {
      String key = "key" + Long.toString(metadataSize);
      metadataSize -= key.getBytes(Charsets.UTF_8).length + valueLength;
      metadataBuilder.put(key, value);
    }

    thrown.expect(IOException.class);
    thrown.expectMessage(Matchers.containsString("too big"));
    HttpArtifactCacheBinaryProtocol.createMetadataHeader(
        ImmutableSet.of(new RuleKey("0000")),
        metadataBuilder.build(),
        ByteSource.wrap("wsad".getBytes(Charsets.UTF_8)));
  }