/* * 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.ignite.internal.processors.continuous; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteEvents; import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.cluster.ClusterTopologyException; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.events.DiscoveryEvent; import org.apache.ignite.events.Event; import org.apache.ignite.events.JobEvent; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.util.GridConcurrentHashSet; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.P1; import org.apache.ignite.internal.util.typedef.P2; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.resources.IgniteInstanceResource; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.apache.ignite.events.EventType.EVTS_ALL; import static org.apache.ignite.events.EventType.EVTS_DISCOVERY; import static org.apache.ignite.events.EventType.EVT_JOB_FINISHED; import static org.apache.ignite.events.EventType.EVT_JOB_STARTED; import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; import static org.apache.ignite.events.EventType.EVT_NODE_LEFT; import static org.apache.ignite.internal.processors.continuous.GridContinuousProcessor.LocalRoutineInfo; /** * Event consume test. */ public class GridEventConsumeSelfTest extends GridCommonAbstractTest { /** */ private static final String PRJ_PRED_CLS_NAME = "org.apache.ignite.tests.p2p.GridEventConsumeProjectionPredicate"; /** */ private static final String FILTER_CLS_NAME = "org.apache.ignite.tests.p2p.GridEventConsumeFilter"; /** Grids count. */ private static final int GRID_CNT = 3; /** Number of created consumes per thread in multithreaded test. */ private static final int CONSUME_CNT = 500; /** */ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); /** Consume latch. */ private static volatile CountDownLatch consumeLatch; /** Consume counter. */ private static volatile AtomicInteger consumeCnt; /** Include node flag. */ private boolean include; /** No automatic unsubscribe flag. */ private boolean noAutoUnsubscribe; /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); TcpDiscoverySpi disc = new TcpDiscoverySpi(); disc.setIpFinder(IP_FINDER); cfg.setDiscoverySpi(disc); ((TcpCommunicationSpi)cfg.getCommunicationSpi()).setSharedMemoryPort(-1); if (include) cfg.setUserAttributes(F.asMap("include", true)); return cfg; } /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { assertTrue(GRID_CNT > 1); include = true; startGrids(GRID_CNT - 1); include = false; startGrid(GRID_CNT - 1); } /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { try { assertEquals(GRID_CNT, grid(0).cluster().nodes().size()); for (int i = 0; i < GRID_CNT; i++) { IgniteEx grid = grid(i); GridContinuousProcessor proc = grid.context().continuous(); try { if (!noAutoUnsubscribe) { Map rmtInfos = U.field(proc, "rmtInfos"); assertTrue("Unexpected remote infos: " + rmtInfos, rmtInfos.isEmpty()); } } finally { U.<Map>field(proc, "rmtInfos").clear(); } assertEquals(0, U.<Map>field(proc, "rmtInfos").size()); assertEquals(0, U.<Map>field(proc, "startFuts").size()); assertEquals(0, U.<Map>field(proc, "stopFuts").size()); assertEquals(0, U.<Map>field(proc, "bufCheckThreads").size()); } } finally { stopAllGrids(); } } /** * @param proc Continuous processor. * @return Local event routines. */ private Collection<LocalRoutineInfo> localRoutines(GridContinuousProcessor proc) { return F.view(U.<Map<UUID, LocalRoutineInfo>>field(proc, "locInfos").values(), new IgnitePredicate<LocalRoutineInfo>() { @Override public boolean apply(LocalRoutineInfo info) { return info.handler().isEvents(); } }); } /** * @throws Exception If failed. */ public void testApi() throws Exception { try { grid(0).events().stopRemoteListen(null); } catch (NullPointerException ignored) { // No-op. } grid(0).events().stopRemoteListen(UUID.randomUUID()); UUID consumeId = null; try { consumeId = grid(0).events().remoteListen( new P2<UUID, DiscoveryEvent>() { @Override public boolean apply(UUID uuid, DiscoveryEvent evt) { return false; } }, new P1<DiscoveryEvent>() { @Override public boolean apply(DiscoveryEvent e) { return false; } }, EVTS_DISCOVERY ); assertNotNull(consumeId); } finally { grid(0).events().stopRemoteListen(consumeId); } try { consumeId = grid(0).events().remoteListen( new P2<UUID, DiscoveryEvent>() { @Override public boolean apply(UUID uuid, DiscoveryEvent evt) { return false; } }, new P1<DiscoveryEvent>() { @Override public boolean apply(DiscoveryEvent e) { return false; } } ); assertNotNull(consumeId); } finally { grid(0).events().stopRemoteListen(consumeId); } try { consumeId = grid(0).events().remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID uuid, Event evt) { return false; } }, new P1<Event>() { @Override public boolean apply(Event e) { return false; } } ); assertNotNull(consumeId); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testApiAsyncOld() throws Exception { IgniteEvents evtAsync = grid(0).events().withAsync(); try { evtAsync.stopRemoteListen(null); evtAsync.future().get(); } catch (NullPointerException ignored) { // No-op. } evtAsync.stopRemoteListen(UUID.randomUUID()); evtAsync.future().get(); UUID consumeId = null; try { evtAsync.remoteListen( new P2<UUID, DiscoveryEvent>() { @Override public boolean apply(UUID uuid, DiscoveryEvent evt) { return false; } }, new P1<DiscoveryEvent>() { @Override public boolean apply(DiscoveryEvent e) { return false; } }, EVTS_DISCOVERY ); consumeId = (UUID)evtAsync.future().get(); assertNotNull(consumeId); } finally { evtAsync.stopRemoteListen(consumeId); evtAsync.future().get(); } try { evtAsync.remoteListen( new P2<UUID, DiscoveryEvent>() { @Override public boolean apply(UUID uuid, DiscoveryEvent evt) { return false; } }, new P1<DiscoveryEvent>() { @Override public boolean apply(DiscoveryEvent e) { return false; } } ); consumeId = (UUID)evtAsync.future().get(); assertNotNull(consumeId); } finally { evtAsync.stopRemoteListen(consumeId); evtAsync.future().get(); } try { evtAsync.remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID uuid, Event evt) { return false; } }, new P1<Event>() { @Override public boolean apply(Event e) { return false; } } ); consumeId = (UUID)evtAsync.future().get(); assertNotNull(consumeId); } finally { evtAsync.stopRemoteListen(consumeId); evtAsync.future().get(); } } /** * @throws Exception If failed. */ public void testApiAsync() throws Exception { IgniteEvents evt = grid(0).events(); try { evt.stopRemoteListenAsync(null).get(); } catch (NullPointerException ignored) { // No-op. } evt.stopRemoteListenAsync(UUID.randomUUID()).get(); UUID consumeId = null; try { consumeId = evt.remoteListenAsync( new P2<UUID, DiscoveryEvent>() { @Override public boolean apply(UUID uuid, DiscoveryEvent evt) { return false; } }, new P1<DiscoveryEvent>() { @Override public boolean apply(DiscoveryEvent e) { return false; } }, EVTS_DISCOVERY ).get(); assertNotNull(consumeId); } finally { evt.stopRemoteListenAsync(consumeId).get(); } try { consumeId = evt.remoteListenAsync( new P2<UUID, DiscoveryEvent>() { @Override public boolean apply(UUID uuid, DiscoveryEvent evt) { return false; } }, new P1<DiscoveryEvent>() { @Override public boolean apply(DiscoveryEvent e) { return false; } } ).get(); assertNotNull(consumeId); } finally { evt.stopRemoteListenAsync(consumeId).get(); } try { consumeId = evt.remoteListenAsync( new P2<UUID, Event>() { @Override public boolean apply(UUID uuid, Event evt) { return false; } }, new P1<Event>() { @Override public boolean apply(Event e) { return false; } } ).get(); assertNotNull(consumeId); } finally { evt.stopRemoteListenAsync(consumeId).get(); } } /** * @throws Exception If failed. */ public void testAllEvents() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT); UUID consumeId = grid(0).events().remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); if (evt.type() == EVT_JOB_STARTED) { nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); } return true; } }, null ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT, nodeIds.size()); assertEquals(GRID_CNT, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testEventsByType() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT); UUID consumeId = grid(0).events().remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, null, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT, nodeIds.size()); assertEquals(GRID_CNT, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testEventsByFilter() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT); UUID consumeId = grid(0).events().remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, new P1<Event>() { @Override public boolean apply(Event evt) { return evt.type() == EVT_JOB_STARTED; } } ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT, nodeIds.size()); assertEquals(GRID_CNT, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testEventsByTypeAndFilter() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT); UUID consumeId = grid(0).events().remoteListen( new P2<UUID, JobEvent>() { @Override public boolean apply(UUID nodeId, JobEvent evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, new P1<JobEvent>() { @Override public boolean apply(JobEvent evt) { return !"exclude".equals(evt.taskName()); } }, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); grid(0).compute().withName("exclude").run(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT, nodeIds.size()); assertEquals(GRID_CNT, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testRemoteProjection() throws Exception { final Collection<UUID> nodeIds = new ConcurrentSkipListSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT - 1); UUID consumeId = events(grid(0).cluster().forRemotes()).remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, null, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT - 1, nodeIds.size()); assertEquals(GRID_CNT - 1, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testProjectionWithLocalNode() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT - 1); UUID consumeId = events(grid(0).cluster().forAttribute("include", null)).remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, null, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT - 1, nodeIds.size()); assertEquals(GRID_CNT - 1, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testLocalNodeOnly() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(1); UUID consumeId = events(grid(0).cluster().forLocal()).remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, null, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(1, nodeIds.size()); assertEquals(1, cnt.get()); assertEquals(grid(0).localNode().id(), F.first(nodeIds)); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testStopByCallback() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(1); UUID consumeId = grid(0).events().remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return false; } }, null, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(1, nodeIds.size()); assertEquals(1, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testStopRemoteListen() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(1); UUID consumeId = grid(0).events().remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, null, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().run(F.noop()); assert latch.await(2, SECONDS); assertEquals(1, nodeIds.size()); assertEquals(1, cnt.get()); grid(0).events().stopRemoteListen(consumeId); grid(0).compute().run(F.noop()); U.sleep(500); assertEquals(1, nodeIds.size()); assertEquals(1, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testStopLocalListenByCallback() throws Exception { final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(1); grid(0).events().localListen( new P1<Event>() { @Override public boolean apply(Event evt) { info("Local event [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); cnt.incrementAndGet(); latch.countDown(); return false; } }, EVT_JOB_STARTED); compute(grid(0).cluster().forLocal()).run(F.noop()); assert latch.await(2, SECONDS); assertEquals(1, cnt.get()); compute(grid(0).cluster().forLocal()).run(F.noop()); U.sleep(500); assertEquals(1, cnt.get()); } /** * @throws Exception If failed. */ public void testNodeJoin() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT + 1); UUID consumeId = grid(0).events().remoteListen( notSerializableProxy(new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }), notSerializableProxy(new P1<Event>() { @Override public boolean apply(Event evt) { return evt.type() == EVT_JOB_STARTED; } }), EVT_JOB_STARTED, EVT_JOB_FINISHED ); try { assertNotNull(consumeId); include = true; startGrid("anotherGrid"); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT + 1, nodeIds.size()); assertEquals(GRID_CNT + 1, cnt.get()); } finally { stopGrid("anotherGrid"); grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testNodeJoinWithProjection() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT); UUID consumeId = events(grid(0).cluster().forAttribute("include", null)).remoteListen( new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, null, EVT_JOB_STARTED ); try { assertNotNull(consumeId); include = true; startGrid("anotherGrid1"); include = false; startGrid("anotherGrid2"); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT, nodeIds.size()); assertEquals(GRID_CNT, cnt.get()); } finally { stopGrid("anotherGrid1"); stopGrid("anotherGrid2"); grid(0).events().stopRemoteListen(consumeId); } } /** * TODO: IGNITE-585. * * @throws Exception If failed. */ public void testNodeJoinWithP2P() throws Exception { fail("https://issues.apache.org/jira/browse/IGNITE-585"); final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT + 1); ClassLoader ldr = getExternalClassLoader(); IgnitePredicate<ClusterNode> prjPred = (IgnitePredicate<ClusterNode>)ldr.loadClass(PRJ_PRED_CLS_NAME).newInstance(); IgnitePredicate<Event> filter = (IgnitePredicate<Event>)ldr.loadClass(FILTER_CLS_NAME).newInstance(); UUID consumeId = events(grid(0).cluster().forPredicate(prjPred)).remoteListen(new P2<UUID, Event>() { @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, filter, EVT_JOB_STARTED); try { assertNotNull(consumeId); startGrid("anotherGrid"); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT + 1, nodeIds.size()); assertEquals(GRID_CNT + 1, cnt.get()); } finally { stopGrid("anotherGrid"); grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testResources() throws Exception { final Collection<UUID> nodeIds = new HashSet<>(); final AtomicInteger cnt = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(GRID_CNT); UUID consumeId = grid(0).events().remoteListen( new P2<UUID, Event>() { @IgniteInstanceResource private Ignite grid; @Override public boolean apply(UUID nodeId, Event evt) { info("Event from " + nodeId + " [" + evt.shortDisplay() + ']'); assertEquals(EVT_JOB_STARTED, evt.type()); assertNotNull(grid); nodeIds.add(nodeId); cnt.incrementAndGet(); latch.countDown(); return true; } }, new P1<Event>() { @IgniteInstanceResource private Ignite grid; @Override public boolean apply(Event evt) { assertNotNull(grid); return true; } }, EVT_JOB_STARTED ); try { assertNotNull(consumeId); grid(0).compute().broadcast(F.noop()); assert latch.await(2, SECONDS); assertEquals(GRID_CNT, nodeIds.size()); assertEquals(GRID_CNT, cnt.get()); } finally { grid(0).events().stopRemoteListen(consumeId); } } /** * @throws Exception If failed. */ public void testMasterNodeLeave() throws Exception { final CountDownLatch latch = new CountDownLatch(GRID_CNT); Ignite g = startGrid("anotherGrid"); try { final UUID nodeId = g.cluster().localNode().id(); for (int i = 0; i < GRID_CNT; i++) { grid(i).events().localListen(new IgnitePredicate<Event>() { @Override public boolean apply(Event evt) { if (nodeId.equals(((DiscoveryEvent)evt).eventNode().id())) latch.countDown(); return true; } }, EVT_NODE_LEFT, EVT_NODE_FAILED); } g.events().remoteListen( null, new P1<Event>() { @Override public boolean apply(Event evt) { return true; } }, EVTS_ALL ); } finally { stopGrid("anotherGrid"); } assert latch.await(3000, MILLISECONDS); } /** * @throws Exception If failed. */ public void testMasterNodeLeaveNoAutoUnsubscribe() throws Exception { Ignite g = startGrid("anotherGrid"); final CountDownLatch discoLatch; try { final UUID nodeId = g.cluster().localNode().id(); discoLatch = new CountDownLatch(GRID_CNT); for (int i = 0; i < GRID_CNT; i++) { grid(0).events().localListen(new IgnitePredicate<Event>() { @Override public boolean apply(Event evt) { if (nodeId.equals(((DiscoveryEvent) evt).eventNode().id())) discoLatch.countDown(); return true; } }, EVT_NODE_LEFT); } consumeLatch = new CountDownLatch(GRID_CNT * 2 + 1); consumeCnt = new AtomicInteger(); noAutoUnsubscribe = true; g.events().remoteListen( 1, 0, false, null, new P1<Event>() { @Override public boolean apply(Event evt) { consumeLatch.countDown(); consumeCnt.incrementAndGet(); return true; } }, EVT_JOB_STARTED ); grid(0).compute().broadcast(F.noop()); } finally { stopGrid("anotherGrid"); } discoLatch.await(3000, MILLISECONDS); grid(0).compute().broadcast(F.noop()); assert consumeLatch.await(2, SECONDS); assertEquals(GRID_CNT * 2 + 1, consumeCnt.get()); } /** * @throws Exception If failed. */ public void testMultithreadedWithNodeRestart() throws Exception { final AtomicBoolean stop = new AtomicBoolean(); final BlockingQueue<IgniteBiTuple<Integer, UUID>> queue = new LinkedBlockingQueue<>(); final Collection<UUID> started = new GridConcurrentHashSet<>(); final Collection<UUID> stopped = new GridConcurrentHashSet<>(); final Random rnd = new Random(); IgniteInternalFuture<?> starterFut = multithreadedAsync(new Callable<Object>() { @Override public Object call() throws Exception { for (int i = 0; i < CONSUME_CNT; i++) { int idx = rnd.nextInt(GRID_CNT); try { IgniteEvents evts = grid(idx).events(); UUID consumeId = evts.remoteListenAsync(new P2<UUID, Event>() { @Override public boolean apply(UUID uuid, Event evt) { return true; } }, null, EVT_JOB_STARTED).get(3000); started.add(consumeId); queue.add(F.t(idx, consumeId)); } catch (ClusterTopologyException ignored) { // No-op. } U.sleep(10); } stop.set(true); return null; } }, 8, "consume-starter"); IgniteInternalFuture<?> stopperFut = multithreadedAsync(new Callable<Object>() { @Override public Object call() throws Exception { while (!stop.get()) { IgniteBiTuple<Integer, UUID> t = queue.poll(1, SECONDS); if (t == null) continue; int idx = t.get1(); UUID consumeId = t.get2(); try { IgniteEvents evts = grid(idx).events(); evts.stopRemoteListenAsync(consumeId).get(3000); stopped.add(consumeId); } catch (ClusterTopologyException ignored) { // No-op. } } return null; } }, 4, "consume-stopper"); IgniteInternalFuture<?> nodeRestarterFut = multithreadedAsync(new Callable<Object>() { @Override public Object call() throws Exception { while (!stop.get()) { startGrid("anotherGrid"); stopGrid("anotherGrid"); } return null; } }, 1, "node-restarter"); IgniteInternalFuture<?> jobRunnerFut = multithreadedAsync(new Callable<Object>() { @Override public Object call() throws Exception { while (!stop.get()) { int idx = rnd.nextInt(GRID_CNT); try { grid(idx).compute().runAsync(F.noop()).get(3000); } catch (IgniteException ignored) { // Ignore all job execution related errors. } } return null; } }, 1, "job-runner"); starterFut.get(); stopperFut.get(); nodeRestarterFut.get(); jobRunnerFut.get(); IgniteBiTuple<Integer, UUID> t; while ((t = queue.poll()) != null) { int idx = t.get1(); UUID consumeId = t.get2(); grid(idx).events().stopRemoteListenAsync(consumeId).get(3000); stopped.add(consumeId); } Collection<UUID> notStopped = F.lose(started, true, stopped); assertEquals("Not stopped IDs: " + notStopped, 0, notStopped.size()); } }