/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.gossip; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.apache.gossip.crdt.GrowOnlyCounter; import org.apache.gossip.crdt.GrowOnlySet; import org.apache.gossip.crdt.OrSet; import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManagerBuilder; import org.apache.gossip.model.PerNodeDataMessage; import org.apache.gossip.model.SharedDataMessage; import org.junit.Test; import io.teknek.tunit.TUnit; public class DataTest extends AbstractIntegrationBase { private String orSetKey = "cror"; private String gCounterKey = "crdtgc"; @Test public void dataTest() throws InterruptedException, UnknownHostException, URISyntaxException{ GossipSettings settings = new GossipSettings(); settings.setPersistRingState(false); settings.setPersistDataState(false); String cluster = UUID.randomUUID().toString(); int seedNodes = 1; List startupMembers = new ArrayList<>(); for (int i = 1; i < seedNodes+1; ++i) { URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i)); startupMembers.add(new RemoteMember(cluster, uri, i + "")); } final List clients = new ArrayList<>(); final int clusterMembers = 2; for (int i = 1; i < clusterMembers + 1; ++i) { URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + i)); GossipManager gossipService = GossipManagerBuilder.newBuilder().cluster(cluster).uri(uri) .id(i + "").gossipMembers(startupMembers).gossipSettings(settings).build(); clients.add(gossipService); gossipService.init(); register(gossipService); } TUnit.assertThat(() -> { int total = 0; for (int i = 0; i < clusterMembers; ++i) { total += clients.get(i).getLiveMembers().size(); } return total; }).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(2); clients.get(0).gossipPerNodeData(msg()); clients.get(0).gossipSharedData(sharedMsg()); TUnit.assertThat(()-> { PerNodeDataMessage x = clients.get(1).findPerNodeGossipData(1 + "", "a"); if (x == null) return ""; else return x.getPayload(); }).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo("b"); TUnit.assertThat(() -> { SharedDataMessage x = clients.get(1).findSharedGossipData("a"); if (x == null) return ""; else return x.getPayload(); }).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo("c"); givenDifferentDatumsInSet(clients); assertThatListIsMerged(clients); givenOrs(clients); assertThatOrSetIsMerged(clients); dropIt(clients); assertThatOrSetDelIsMerged(clients); // test g counter givenDifferentIncrement(clients); assertThatCountIsUpdated(clients, 3); givenIncreaseOther(clients); assertThatCountIsUpdated(clients, 7); for (int i = 0; i < clusterMembers; ++i) { clients.get(i).shutdown(); } } private void givenDifferentIncrement(final List clients) { { SharedDataMessage d = new SharedDataMessage(); d.setKey(gCounterKey); d.setPayload(new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(0)).increment(1L))); d.setExpireAt(Long.MAX_VALUE); d.setTimestamp(System.currentTimeMillis()); clients.get(0).merge(d); } { SharedDataMessage d = new SharedDataMessage(); d.setKey(gCounterKey); d.setPayload(new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(1)).increment(2L))); d.setExpireAt(Long.MAX_VALUE); d.setTimestamp(System.currentTimeMillis()); clients.get(1).merge(d); } } private void givenIncreaseOther(final List clients) { GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(1).findCrdt(gCounterKey); GrowOnlyCounter gc2 = new GrowOnlyCounter(gc, new GrowOnlyCounter.Builder(clients.get(1)).increment(4L)); SharedDataMessage d = new SharedDataMessage(); d.setKey(gCounterKey); d.setPayload(gc2); d.setExpireAt(Long.MAX_VALUE); d.setTimestamp(System.currentTimeMillis()); clients.get(1).merge(d); } private void givenOrs(List clients) { { SharedDataMessage d = new SharedDataMessage(); d.setKey(orSetKey); d.setPayload(new OrSet("1", "2")); d.setExpireAt(Long.MAX_VALUE); d.setTimestamp(System.currentTimeMillis()); clients.get(0).merge(d); } { SharedDataMessage d = new SharedDataMessage(); d.setKey(orSetKey); d.setPayload(new OrSet("3", "4")); d.setExpireAt(Long.MAX_VALUE); d.setTimestamp(System.currentTimeMillis()); clients.get(1).merge(d); } } private void dropIt(List clients) { @SuppressWarnings("unchecked") OrSet o = (OrSet) clients.get(0).findCrdt(orSetKey); OrSet o2 = new OrSet(o, new OrSet.Builder().remove("3")); SharedDataMessage d = new SharedDataMessage(); d.setKey(orSetKey); d.setPayload(o2); d.setExpireAt(Long.MAX_VALUE); d.setTimestamp(System.currentTimeMillis()); clients.get(0).merge(d); } private void assertThatOrSetIsMerged(final List clients){ TUnit.assertThat(() -> { return clients.get(0).findCrdt(orSetKey).value(); }).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new OrSet("1", "2", "3", "4").value()); TUnit.assertThat(() -> { return clients.get(1).findCrdt(orSetKey).value(); }).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new OrSet("1", "2", "3", "4").value()); } private void assertThatOrSetDelIsMerged(final List clients){ TUnit.assertThat(() -> { return clients.get(0).findCrdt(orSetKey); }).afterWaitingAtMost(10, TimeUnit.SECONDS).equals(new OrSet("1", "2", "4")); } private void givenDifferentDatumsInSet(final List clients){ clients.get(0).merge(CrdtMessage("1")); clients.get(1).merge(CrdtMessage("2")); } private void assertThatCountIsUpdated(final List clients, long finalCount) { TUnit.assertThat(() -> { return clients.get(0).findCrdt(gCounterKey); }).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new GrowOnlyCounter( new GrowOnlyCounter.Builder(clients.get(0)).increment(finalCount))); } private void assertThatListIsMerged(final List clients){ TUnit.assertThat(() -> { return clients.get(0).findCrdt("cr"); }).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(new GrowOnlySet(Arrays.asList("1","2"))); } private SharedDataMessage CrdtMessage(String item){ SharedDataMessage d = new SharedDataMessage(); d.setKey("cr"); d.setPayload(new GrowOnlySet( Arrays.asList(item))); d.setExpireAt(Long.MAX_VALUE); d.setTimestamp(System.currentTimeMillis()); return d; } private PerNodeDataMessage msg(){ PerNodeDataMessage g = new PerNodeDataMessage(); g.setExpireAt(Long.MAX_VALUE); g.setKey("a"); g.setPayload("b"); g.setTimestamp(System.currentTimeMillis()); return g; } private SharedDataMessage sharedMsg(){ SharedDataMessage g = new SharedDataMessage(); g.setExpireAt(Long.MAX_VALUE); g.setKey("a"); g.setPayload("c"); g.setTimestamp(System.currentTimeMillis()); return g; } }