/* * Copyright 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package io.atomix.variables; import io.atomix.testing.AbstractCopycatTest; import org.testng.annotations.Test; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Function; /** * Distributed atomic long test. * * @author <a href="http://github.com/kuujo">Jordan Halterman</a> */ @Test public class DistributedLongTest extends AbstractCopycatTest<DistributedLong> { @Override protected Class<? super DistributedLong> type() { return DistributedLong.class; } /** * Tests a value change event. */ public void testChangeEvent() throws Throwable { createServers(3); DistributedLong value = createResource(); value.onChange(event -> { threadAssertEquals(event.oldValue(), 0L); threadAssertEquals(event.newValue(), 1L); resume(); }).thenRun(this::resume); await(5000); value.compareAndSet(0L, 1L).thenRun(this::resume); await(5000, 2); } /** * Tests setting and getting a value. */ public void testAtomicIncrementAndGet() throws Throwable { testAtomic(3, atomic(DistributedLong::incrementAndGet, l -> l + 1)); } /** * Tests setting and getting a value. */ public void testAtomicDecrementAndGet() throws Throwable { testAtomic(3, atomic(DistributedLong::decrementAndGet, l -> l - 1)); } /** * Tests setting and getting a value. */ public void testAtomicGetAndIncrement() throws Throwable { testAtomic(3, atomic(DistributedLong::getAndIncrement, l -> l)); } /** * Tests setting and getting a value. */ public void testAtomicGetAndDecrement() throws Throwable { testAtomic(3, atomic(DistributedLong::getAndDecrement, l -> l)); } /** * Tests setting and getting a value. */ public void testAtomicAddAndGet() throws Throwable { testAtomic(3, atomic(l -> l.addAndGet(10), l -> l + 10)); } /** * Tests setting and getting a value. */ public void testAtomicGetAndAdd() throws Throwable { testAtomic(3, atomic(l -> l.getAndAdd(10), l -> l)); } /** * Tests incrementing a value followed by setting it and then incrementing it again. */ public void testSequenceOfUpdates() throws Throwable { Function<DistributedLong, CompletableFuture<Long>> sequence = l -> l.incrementAndGet() .thenCompose(v -> l.set(10L)) .thenCompose(v -> l.incrementAndGet()); testAtomic(3, atomic(sequence, l -> 11L)); } /** * Returns an atomic set/get test callback. */ private Consumer<DistributedLong> atomic(Function<DistributedLong, CompletableFuture<Long>> commandFunction, Function<Long, Long> resultFunction) { return (a) -> { a.get().thenAccept(value -> { commandFunction.apply(a).thenAccept(result -> { threadAssertEquals(result, resultFunction.apply(value)); resume(); }); }); }; } /** * Tests a set of atomic operations. */ private void testAtomic(int servers, Consumer<DistributedLong> consumer) throws Throwable { createServers(servers); DistributedLong atomic = createResource(); consumer.accept(atomic); await(10000); } }