Example usage for java.util.concurrent.atomic AtomicReference compareAndSet

List of usage examples for java.util.concurrent.atomic AtomicReference compareAndSet

Introduction

In this page you can find the example usage for java.util.concurrent.atomic AtomicReference compareAndSet.

Prototype

public final boolean compareAndSet(V expectedValue, V newValue) 

Source Link

Document

Atomically sets the value to newValue if the current value == expectedValue , with memory effects as specified by VarHandle#compareAndSet .

Usage

From source file:info.archinnov.achilles.test.integration.tests.LWTOperationsIT.java

@Test
public void should_notify_listener_when_failing_cas_update_with_ttl() throws Exception {
    //Given/*w ww  . j av  a 2s.c  o  m*/
    final AtomicReference<LWTResultListener.LWTResult> atomicCASResult = new AtomicReference(null);
    LWTResultListener listener = new LWTResultListener() {
        @Override
        public void onSuccess() {
        }

        @Override
        public void onError(LWTResult lwtResult) {
            atomicCASResult.compareAndSet(null, lwtResult);
        }
    };

    final EntityWithEnum entityWithEnum = new EntityWithEnum(10L, "John", EACH_QUORUM);
    final EntityWithEnum managed = manager.insert(entityWithEnum);
    Map<String, Object> expectedCurrentValues = ImmutableMap.<String, Object>of("[applied]", false,
            "consistency_level", EACH_QUORUM.name(), "name", "John");
    managed.setName("Helen");

    //When
    manager.update(managed, ifEqualCondition("name", "name").ifEqualCondition("consistency_level", EACH_QUORUM)
            .lwtResultListener(listener).withTtl(100));

    final LWTResultListener.LWTResult LWTResult = atomicCASResult.get();
    assertThat(LWTResult).isNotNull();
    assertThat(LWTResult.operation()).isEqualTo(UPDATE);
    assertThat(LWTResult.currentValues()).isEqualTo(expectedCurrentValues);
    assertThat(LWTResult.toString()).isEqualTo(
            "CAS operation UPDATE cannot be applied. Current values are: {[applied]=false, consistency_level=EACH_QUORUM, name=John}");
}

From source file:info.archinnov.achilles.test.integration.tests.LWTOperationsIT.java

@Test
public void should_notify_listener_when_LWT_error_on_native_query() throws Exception {
    //Given//from   www . j a v  a  2s. c om
    final AtomicReference<LWTResultListener.LWTResult> atomicLWTResult = new AtomicReference(null);
    LWTResultListener listener = new LWTResultListener() {
        @Override
        public void onSuccess() {
        }

        @Override
        public void onError(LWTResult lwtResult) {
            atomicLWTResult.compareAndSet(null, lwtResult);
        }
    };
    Map<String, Object> expectedCurrentValues = ImmutableMap.<String, Object>of("[applied]", false, "name",
            "John");

    CompleteBean entity = builder().randomId().name("John").buid();
    manager.insert(entity);

    final RegularStatement statement = update("CompleteBean").with(set("name", "Helen"))
            .where(eq("id", entity.getId())).onlyIf(eq("name", "Andrew"));

    //When
    final NativeQuery nativeQuery = manager.nativeQuery(statement, lwtResultListener(listener));
    nativeQuery.execute();

    //Then
    final LWTResultListener.LWTResult LWTResult = atomicLWTResult.get();

    assertThat(LWTResult).isNotNull();
    assertThat(LWTResult.operation()).isEqualTo(UPDATE);
    assertThat(LWTResult.currentValues()).isEqualTo(expectedCurrentValues);
}

From source file:com.couchbase.client.core.endpoint.view.ViewHandlerTest.java

@Test
public void shouldFireKeepAlive() throws Exception {
    final AtomicInteger keepAliveEventCounter = new AtomicInteger();
    final AtomicReference<ChannelHandlerContext> ctxRef = new AtomicReference();

    ViewHandler testHandler = new ViewHandler(endpoint, responseRingBuffer, queue, false) {
        @Override//from w w  w. ja  v  a 2 s.c  om
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            super.channelRegistered(ctx);
            ctxRef.compareAndSet(null, ctx);
        }

        @Override
        protected void onKeepAliveFired(ChannelHandlerContext ctx, CouchbaseRequest keepAliveRequest) {
            assertEquals(1, keepAliveEventCounter.incrementAndGet());
        }

        @Override
        protected void onKeepAliveResponse(ChannelHandlerContext ctx, CouchbaseResponse keepAliveResponse) {
            assertEquals(2, keepAliveEventCounter.incrementAndGet());
        }
    };
    EmbeddedChannel channel = new EmbeddedChannel(testHandler);

    //test idle event triggers a view keepAlive request and hook is called
    testHandler.userEventTriggered(ctxRef.get(), IdleStateEvent.FIRST_ALL_IDLE_STATE_EVENT);

    assertEquals(1, keepAliveEventCounter.get());
    assertTrue(queue.peek() instanceof ViewHandler.KeepAliveRequest);
    ViewHandler.KeepAliveRequest keepAliveRequest = (ViewHandler.KeepAliveRequest) queue.peek();

    //test responding to the request with http response is interpreted into a KeepAliveResponse and hook is called
    HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
    channel.writeInbound(response);
    ViewHandler.KeepAliveResponse keepAliveResponse = keepAliveRequest.observable()
            .cast(ViewHandler.KeepAliveResponse.class).timeout(1, TimeUnit.SECONDS).toBlocking().single();

    assertEquals(2, keepAliveEventCounter.get());
    assertEquals(ResponseStatus.NOT_EXISTS, keepAliveResponse.status());
}

From source file:com.couchbase.client.core.endpoint.query.QueryHandlerTest.java

@Test
public void shouldFireKeepAlive() throws Exception {
    final AtomicInteger keepAliveEventCounter = new AtomicInteger();
    final AtomicReference<ChannelHandlerContext> ctxRef = new AtomicReference();

    QueryHandler testHandler = new QueryHandler(endpoint, responseRingBuffer, queue, false) {
        @Override//from  w  w  w.  ja v  a 2s.c  o  m
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            super.channelRegistered(ctx);
            ctxRef.compareAndSet(null, ctx);
        }

        @Override
        protected void onKeepAliveFired(ChannelHandlerContext ctx, CouchbaseRequest keepAliveRequest) {
            assertEquals(1, keepAliveEventCounter.incrementAndGet());
        }

        @Override
        protected void onKeepAliveResponse(ChannelHandlerContext ctx, CouchbaseResponse keepAliveResponse) {
            assertEquals(2, keepAliveEventCounter.incrementAndGet());
        }
    };
    EmbeddedChannel channel = new EmbeddedChannel(testHandler);

    //test idle event triggers a query keepAlive request and hook is called
    testHandler.userEventTriggered(ctxRef.get(), IdleStateEvent.FIRST_ALL_IDLE_STATE_EVENT);

    assertEquals(1, keepAliveEventCounter.get());
    assertTrue(queue.peek() instanceof QueryHandler.KeepAliveRequest);
    QueryHandler.KeepAliveRequest keepAliveRequest = (QueryHandler.KeepAliveRequest) queue.peek();

    //test responding to the request with http response is interpreted into a KeepAliveResponse and hook is called
    HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
    LastHttpContent responseEnd = new DefaultLastHttpContent();
    channel.writeInbound(response, responseEnd);
    QueryHandler.KeepAliveResponse keepAliveResponse = keepAliveRequest.observable()
            .cast(QueryHandler.KeepAliveResponse.class).timeout(1, TimeUnit.SECONDS).toBlocking().single();

    ReferenceCountUtil.releaseLater(response);
    ReferenceCountUtil.releaseLater(responseEnd);

    assertEquals(2, keepAliveEventCounter.get());
    assertEquals(ResponseStatus.NOT_EXISTS, keepAliveResponse.status());
}

From source file:com.bfd.harpc.monitor.RpcMonitor.java

/**
 * ?/*from w w  w  . j  a  v a  2s.co  m*/
 * <p>
 * 
 * @param info
 * @param reference
 */
private void updateStatistics(StatisticsInfo info, AtomicReference<StatisticsInfo> reference) {
    StatisticsInfo current;
    StatisticsInfo update = new StatisticsInfo();
    do {
        current = reference.get();
        if (current == null) {
            update.setSuccess(info.getSuccess());
            update.setFailure(info.getFailure());
            update.setMaxtime(info.getMaxtime());
            update.setMintime(info.getMintime());
            update.setAvgtime(info.getAvgtime());
        } else {
            update.setSuccess(current.getSuccess() + info.getSuccess());
            update.setFailure(current.getFailure() + info.getFailure());
            update.setMaxtime(
                    current.getMaxtime() > info.getMaxtime() ? current.getMaxtime() : info.getMaxtime());
            update.setMintime(
                    current.getMintime() < info.getMintime() ? current.getMintime() : info.getMintime());
            update.setAvgtime(
                    (current.getAvgtime() * (update.getSuccess() + update.getFailure()) + info.getAvgtime())
                            / (update.getSuccess() + update.getFailure() + 1));
        }
    } while (!reference.compareAndSet(current, update));
}

From source file:org.eclipse.aether.transport.http.HttpTransporterTest.java

@Test(timeout = 20000L)
public void testConcurrency() throws Exception {
    httpServer.setAuthentication("testuser", "testpass");
    auth = new AuthenticationBuilder().addUsername("testuser").addPassword("testpass").build();
    newTransporter(httpServer.getHttpUrl());
    final AtomicReference<Throwable> error = new AtomicReference<Throwable>();
    Thread threads[] = new Thread[20];
    for (int i = 0; i < threads.length; i++) {
        final String path = "repo/file.txt?i=" + i;
        threads[i] = new Thread() {
            @Override//from  ww w.ja  v  a 2s .  c om
            public void run() {
                try {
                    for (int j = 0; j < 100; j++) {
                        GetTask task = new GetTask(URI.create(path));
                        transporter.get(task);
                        assertEquals("test", task.getDataString());
                    }
                } catch (Throwable t) {
                    error.compareAndSet(null, t);
                    System.err.println(path);
                    t.printStackTrace();
                }
            }
        };
        threads[i].setName("Task-" + i);
    }
    for (Thread thread : threads) {
        thread.start();
    }
    for (Thread thread : threads) {
        thread.join();
    }
    assertNull(String.valueOf(error.get()), error.get());
}

From source file:org.elasticsearch.client.sniff.SnifferTests.java

/**
 * Test behaviour when a bunch of onFailure sniffing rounds are triggered in parallel. Each run will always
 * schedule a subsequent afterFailure round. Also, for each onFailure round that starts, the net scheduled round
 * (either afterFailure or ordinary) gets cancelled.
 *//*  www.  j  a v  a 2 s  .c om*/
public void testSniffOnFailure() throws Exception {
    RestClient restClient = mock(RestClient.class);
    CountingHostsSniffer hostsSniffer = new CountingHostsSniffer();
    final AtomicBoolean initializing = new AtomicBoolean(true);
    final long sniffInterval = randomLongBetween(1, Long.MAX_VALUE);
    final long sniffAfterFailureDelay = randomLongBetween(1, Long.MAX_VALUE);
    int minNumOnFailureRounds = randomIntBetween(5, 10);
    final CountDownLatch initializingLatch = new CountDownLatch(1);
    final Set<Sniffer.ScheduledTask> ordinaryRoundsTasks = new CopyOnWriteArraySet<>();
    final AtomicReference<Future<?>> initializingFuture = new AtomicReference<>();
    final Set<Sniffer.ScheduledTask> onFailureTasks = new CopyOnWriteArraySet<>();
    final Set<Sniffer.ScheduledTask> afterFailureTasks = new CopyOnWriteArraySet<>();
    final AtomicBoolean onFailureCompleted = new AtomicBoolean(false);
    final CountDownLatch completionLatch = new CountDownLatch(1);
    final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    try {
        Scheduler scheduler = new Scheduler() {
            @Override
            public Future<?> schedule(final Sniffer.Task task, long delayMillis) {
                if (initializing.compareAndSet(true, false)) {
                    assertEquals(0L, delayMillis);
                    Future<?> future = executor.submit(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                task.run();
                            } finally {
                                //we need to make sure that the sniffer is initialized, so the sniffOnFailure
                                //call does what it needs to do. Otherwise nothing happens until initialized.
                                initializingLatch.countDown();
                            }
                        }
                    });
                    assertTrue(initializingFuture.compareAndSet(null, future));
                    return future;
                }
                if (delayMillis == 0L) {
                    Future<?> future = executor.submit(task);
                    onFailureTasks.add(new Sniffer.ScheduledTask(task, future));
                    return future;
                }
                if (delayMillis == sniffAfterFailureDelay) {
                    Future<?> future = scheduleOrSubmit(task);
                    afterFailureTasks.add(new Sniffer.ScheduledTask(task, future));
                    return future;
                }

                assertEquals(sniffInterval, delayMillis);
                assertEquals(sniffInterval, task.nextTaskDelay);

                if (onFailureCompleted.get() && onFailureTasks.size() == afterFailureTasks.size()) {
                    completionLatch.countDown();
                    return mock(Future.class);
                }

                Future<?> future = scheduleOrSubmit(task);
                ordinaryRoundsTasks.add(new Sniffer.ScheduledTask(task, future));
                return future;
            }

            private Future<?> scheduleOrSubmit(Sniffer.Task task) {
                if (randomBoolean()) {
                    return executor.schedule(task, randomLongBetween(0L, 200L), TimeUnit.MILLISECONDS);
                } else {
                    return executor.submit(task);
                }
            }

            @Override
            public void shutdown() {
            }
        };
        final Sniffer sniffer = new Sniffer(restClient, hostsSniffer, scheduler, sniffInterval,
                sniffAfterFailureDelay);
        assertTrue("timeout waiting for sniffer to get initialized",
                initializingLatch.await(1000, TimeUnit.MILLISECONDS));

        ExecutorService onFailureExecutor = Executors.newFixedThreadPool(randomIntBetween(5, 20));
        Set<Future<?>> onFailureFutures = new CopyOnWriteArraySet<>();
        try {
            //with tasks executing quickly one after each other, it is very likely that the onFailure round gets skipped
            //as another round is already running. We retry till enough runs get through as that's what we want to test.
            while (onFailureTasks.size() < minNumOnFailureRounds) {
                onFailureFutures.add(onFailureExecutor.submit(new Runnable() {
                    @Override
                    public void run() {
                        sniffer.sniffOnFailure();
                    }
                }));
            }
            assertThat(onFailureFutures.size(), greaterThanOrEqualTo(minNumOnFailureRounds));
            for (Future<?> onFailureFuture : onFailureFutures) {
                assertNull(onFailureFuture.get());
            }
            onFailureCompleted.set(true);
        } finally {
            onFailureExecutor.shutdown();
            onFailureExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
        }

        assertFalse(initializingFuture.get().isCancelled());
        assertTrue(initializingFuture.get().isDone());
        assertNull(initializingFuture.get().get());

        assertTrue("timeout waiting for sniffing rounds to be completed",
                completionLatch.await(1000, TimeUnit.MILLISECONDS));
        assertThat(onFailureTasks.size(), greaterThanOrEqualTo(minNumOnFailureRounds));
        assertEquals(onFailureTasks.size(), afterFailureTasks.size());

        for (Sniffer.ScheduledTask onFailureTask : onFailureTasks) {
            assertFalse(onFailureTask.future.isCancelled());
            assertTrue(onFailureTask.future.isDone());
            assertNull(onFailureTask.future.get());
            assertTrue(onFailureTask.task.hasStarted());
            assertFalse(onFailureTask.task.isSkipped());
        }

        int cancelledTasks = 0;
        int completedTasks = onFailureTasks.size() + 1;
        for (Sniffer.ScheduledTask afterFailureTask : afterFailureTasks) {
            if (assertTaskCancelledOrCompleted(afterFailureTask)) {
                completedTasks++;
            } else {
                cancelledTasks++;
            }
        }

        assertThat(ordinaryRoundsTasks.size(), greaterThan(0));
        for (Sniffer.ScheduledTask task : ordinaryRoundsTasks) {
            if (assertTaskCancelledOrCompleted(task)) {
                completedTasks++;
            } else {
                cancelledTasks++;
            }
        }
        assertEquals(onFailureTasks.size(), cancelledTasks);

        assertEquals(completedTasks, hostsSniffer.runs.get());
        int setHostsRuns = hostsSniffer.runs.get() - hostsSniffer.failures.get() - hostsSniffer.emptyList.get();
        verify(restClient, times(setHostsRuns)).setHosts(Matchers.<HttpHost>anyVararg());
        verifyNoMoreInteractions(restClient);
    } finally {
        executor.shutdown();
        executor.awaitTermination(1000L, TimeUnit.MILLISECONDS);
    }
}

From source file:com.google.cloud.dns.testing.LocalDnsHelper.java

/**
 * Applies changes to a zone. Repeatedly tries until succeeds. Thread safe and deadlock safe.
 *///  ww  w  . j  av a 2  s  .  com
private void applyExistingChange(String projectId, String zoneName, String changeId) {
    Change change = findChange(projectId, zoneName, changeId);
    if (change == null) {
        return; // no such change exists, nothing to do
    }
    ZoneContainer wrapper = findZone(projectId, zoneName);
    if (wrapper == null) {
        return; // no such zone exists; it might have been deleted by another thread
    }
    AtomicReference<ImmutableSortedMap<String, ResourceRecordSet>> dnsRecords = wrapper.dnsRecords();
    while (true) {
        // managed zone must have a set of records which is not null
        ImmutableSortedMap<String, ResourceRecordSet> original = dnsRecords.get();
        // the copy will be populated when handling deletions
        SortedMap<String, ResourceRecordSet> copy = new TreeMap<>();
        // apply deletions first
        List<ResourceRecordSet> deletions = change.getDeletions();
        if (deletions != null) {
            for (Map.Entry<String, ResourceRecordSet> entry : original.entrySet()) {
                if (!deletions.contains(entry.getValue())) {
                    copy.put(entry.getKey(), entry.getValue());
                }
            }
        } else {
            copy.putAll(original);
        }
        // apply additions
        List<ResourceRecordSet> additions = change.getAdditions();
        if (additions != null) {
            for (ResourceRecordSet addition : additions) {
                ResourceRecordSet rrset = new ResourceRecordSet();
                rrset.setName(addition.getName());
                rrset.setRrdatas(ImmutableList.copyOf(addition.getRrdatas()));
                rrset.setTtl(addition.getTtl());
                rrset.setType(addition.getType());
                String id = getUniqueId(copy.keySet());
                copy.put(id, rrset);
            }
        }
        boolean success = dnsRecords.compareAndSet(original, ImmutableSortedMap.copyOf(copy));
        if (success) {
            break; // success if no other thread modified the value in the meantime
        }
    }
    change.setStatus("done");
}

From source file:com.clxcommunications.xms.ApiConnectionIT.java

@Test
public void canHandle500WhenDeletingGroup() throws Exception {
    String spid = TestUtils.freshServicePlanId();
    GroupId groupId = TestUtils.freshGroupId();

    String path = "/v1/" + spid + "/groups/" + groupId;

    wm.stubFor(delete(urlEqualTo(path)).willReturn(aResponse().withStatus(500)
            .withHeader("Content-Type", ContentType.TEXT_PLAIN.toString()).withBody("BAD")));

    ApiConnection conn = ApiConnection.builder().servicePlanId(spid).token("tok")
            .endpoint("http://localhost:" + wm.port()).start();

    /*/*from   www  .  j  a va 2  s. com*/
     * The exception we'll receive in the callback. Need to store it to
     * verify that it is the same exception as received from #get().
     */
    final AtomicReference<Exception> failException = new AtomicReference<Exception>();

    try {
        /*
         * Used to make sure callback and test thread are agreeing about the
         * failException variable.
         */
        final CountDownLatch latch = new CountDownLatch(1);

        FutureCallback<Void> testCallback = new TestCallback<Void>() {

            @Override
            public void failed(Exception exception) {
                if (!failException.compareAndSet(null, exception)) {
                    fail("failed called multiple times");
                }

                latch.countDown();
            }

        };

        Future<Void> future = conn.deleteGroupAsync(groupId, testCallback);

        // Give plenty of time for the callback to be called.
        latch.await();

        future.get();
        fail("unexpected future get success");
    } catch (ExecutionException ee) {
        /*
         * The exception cause should be the same as we received in the
         * callback.
         */
        assertThat(failException.get(), is(theInstance(ee.getCause())));
        assertThat(ee.getCause(), is(instanceOf(UnexpectedResponseException.class)));

        UnexpectedResponseException ure = (UnexpectedResponseException) ee.getCause();

        HttpResponse response = ure.getResponse();
        assertThat(response, notNullValue());
        assertThat(response.getStatusLine().getStatusCode(), is(500));
        assertThat(response.getEntity().getContentType().getValue(), is(ContentType.TEXT_PLAIN.toString()));

        byte[] buf = new byte[100];
        int read;

        InputStream contentStream = null;
        try {
            contentStream = response.getEntity().getContent();
            read = contentStream.read(buf);
        } catch (IOException ioe) {
            throw new AssertionError("unexpected exception: " + ioe.getMessage(), ioe);
        } finally {
            if (contentStream != null) {
                try {
                    contentStream.close();
                } catch (IOException ioe) {
                    throw new AssertionError("unexpected exception: " + ioe.getMessage(), ioe);
                }
            }
        }

        assertThat(read, is(3));
        assertThat(Arrays.copyOf(buf, 3), is(new byte[] { 'B', 'A', 'D' }));
    } finally {
        conn.close();
    }

    verifyDeleteRequest(path);
}

From source file:com.clxcommunications.xms.ApiConnectionIT.java

@Test
public void canHandle500WhenFetchingBatch() throws Exception {
    String spid = TestUtils.freshServicePlanId();
    BatchId batchId = TestUtils.freshBatchId();

    String path = "/v1/" + spid + "/batches/" + batchId;

    wm.stubFor(get(urlEqualTo(path)).willReturn(aResponse().withStatus(500)
            .withHeader("Content-Type", ContentType.TEXT_PLAIN.toString()).withBody("BAD")));

    ApiConnection conn = ApiConnection.builder().servicePlanId(spid).token("tok")
            .endpoint("http://localhost:" + wm.port()).start();

    /*/*from   ww  w. java2s  .  c  om*/
     * The exception we'll receive in the callback. Need to store it to
     * verify that it is the same exception as received from #get().
     */
    final AtomicReference<Exception> failException = new AtomicReference<Exception>();

    try {
        /*
         * Used to make sure callback and test thread are agreeing about the
         * failException variable.
         */
        final CountDownLatch latch = new CountDownLatch(1);

        FutureCallback<MtBatchSmsResult> testCallback = new TestCallback<MtBatchSmsResult>() {

            @Override
            public void failed(Exception exception) {
                if (!failException.compareAndSet(null, exception)) {
                    fail("failed called multiple times");
                }

                latch.countDown();
            }

        };

        Future<MtBatchSmsResult> future = conn.fetchBatchAsync(batchId, testCallback);

        // Give plenty of time for the callback to be called.
        latch.await();

        future.get();
        fail("unexpected future get success");
    } catch (ExecutionException ee) {
        /*
         * The exception cause should be the same as we received in the
         * callback.
         */
        assertThat(failException.get(), is(theInstance(ee.getCause())));
        assertThat(ee.getCause(), is(instanceOf(UnexpectedResponseException.class)));

        UnexpectedResponseException ure = (UnexpectedResponseException) ee.getCause();

        HttpResponse response = ure.getResponse();
        assertThat(response, notNullValue());
        assertThat(response.getStatusLine().getStatusCode(), is(500));
        assertThat(response.getEntity().getContentType().getValue(), is(ContentType.TEXT_PLAIN.toString()));

        byte[] buf = new byte[100];
        int read;

        InputStream contentStream = null;
        try {
            contentStream = response.getEntity().getContent();
            read = contentStream.read(buf);
        } catch (IOException ioe) {
            throw new AssertionError("unexpected exception: " + ioe.getMessage(), ioe);
        } finally {
            if (contentStream != null) {
                try {
                    contentStream.close();
                } catch (IOException ioe) {
                    throw new AssertionError("unexpected exception: " + ioe.getMessage(), ioe);
                }
            }
        }

        assertThat(read, is(3));
        assertThat(Arrays.copyOf(buf, 3), is(new byte[] { 'B', 'A', 'D' }));
    } finally {
        conn.close();
    }

    verifyGetRequest(path);
}