package org.web3j.protocol.rx; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; import org.junit.Test; import org.mockito.stubbing.OngoingStubbing; import rx.Observable; import rx.Subscription; import org.web3j.protocol.ObjectMapperFactory; import org.web3j.protocol.Web3j; import org.web3j.protocol.Web3jService; import org.web3j.protocol.core.DefaultBlockParameterNumber; import org.web3j.protocol.core.Request; import org.web3j.protocol.core.methods.response.EthBlock; import org.web3j.protocol.core.methods.response.EthFilter; import org.web3j.protocol.core.methods.response.EthLog; import org.web3j.protocol.core.methods.response.EthUninstallFilter; import org.web3j.utils.Numeric; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class JsonRpc2_0RxTest { private final ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); private Web3j web3j; private Web3jService web3jService; @Before public void setUp() { web3jService = mock(Web3jService.class); web3j = Web3j.build(web3jService, 1000, Executors.newSingleThreadScheduledExecutor()); } @Test public void testReplayBlocksObservable() throws Exception { List<EthBlock> ethBlocks = Arrays.asList(createBlock(0), createBlock(1), createBlock(2)); OngoingStubbing<EthBlock> stubbing = when(web3jService.send(any(Request.class), eq(EthBlock.class))); for (EthBlock ethBlock : ethBlocks) { stubbing = stubbing.thenReturn(ethBlock); } Observable<EthBlock> observable = web3j.replayBlocksObservable( new DefaultBlockParameterNumber(BigInteger.ZERO), new DefaultBlockParameterNumber(BigInteger.valueOf(2)), false); CountDownLatch transactionLatch = new CountDownLatch(ethBlocks.size()); CountDownLatch completedLatch = new CountDownLatch(1); List<EthBlock> results = new ArrayList<>(ethBlocks.size()); Subscription subscription = observable.subscribe( result -> { results.add(result); transactionLatch.countDown(); }, throwable -> fail(throwable.getMessage()), () -> completedLatch.countDown()); transactionLatch.await(1, TimeUnit.SECONDS); assertThat(results, equalTo(ethBlocks)); subscription.unsubscribe(); completedLatch.await(1, TimeUnit.SECONDS); assertTrue(subscription.isUnsubscribed()); } @Test public void testReplayBlocksDescendingObservable() throws Exception { List<EthBlock> ethBlocks = Arrays.asList(createBlock(2), createBlock(1), createBlock(0)); OngoingStubbing<EthBlock> stubbing = when(web3jService.send(any(Request.class), eq(EthBlock.class))); for (EthBlock ethBlock : ethBlocks) { stubbing = stubbing.thenReturn(ethBlock); } Observable<EthBlock> observable = web3j.replayBlocksObservable( new DefaultBlockParameterNumber(BigInteger.ZERO), new DefaultBlockParameterNumber(BigInteger.valueOf(2)), false, false); CountDownLatch transactionLatch = new CountDownLatch(ethBlocks.size()); CountDownLatch completedLatch = new CountDownLatch(1); List<EthBlock> results = new ArrayList<>(ethBlocks.size()); Subscription subscription = observable.subscribe( result -> { results.add(result); transactionLatch.countDown(); }, throwable -> fail(throwable.getMessage()), () -> completedLatch.countDown()); transactionLatch.await(1, TimeUnit.SECONDS); assertThat(results, equalTo(ethBlocks)); subscription.unsubscribe(); completedLatch.await(1, TimeUnit.SECONDS); assertTrue(subscription.isUnsubscribed()); } @Test public void testCatchUpToLatestAndSubscribeToNewBlockObservable() throws Exception { List<EthBlock> expected = Arrays.asList( createBlock(0), createBlock(1), createBlock(2), createBlock(3), createBlock(4), createBlock(5), createBlock(6)); List<EthBlock> ethBlocks = Arrays.asList( expected.get(2), // greatest block expected.get(0), expected.get(1), expected.get(2), expected.get(4), // greatest block expected.get(3), expected.get(4), expected.get(4), // greatest block expected.get(5), // initial response from ethGetFilterLogs call expected.get(6)); // subsequent block from new block observable OngoingStubbing<EthBlock> stubbing = when(web3jService.send(any(Request.class), eq(EthBlock.class))); for (EthBlock ethBlock : ethBlocks) { stubbing = stubbing.thenReturn(ethBlock); } EthFilter ethFilter = objectMapper.readValue( "{\n" + " \"id\":1,\n" + " \"jsonrpc\": \"2.0\",\n" + " \"result\": \"0x1\"\n" + "}", EthFilter.class); EthLog ethLog = objectMapper.readValue( "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":[" + "\"0x31c2342b1e0b8ffda1507fbffddf213c4b3c1e819ff6a84b943faabb0ebf2403\"" + "]}", EthLog.class); EthUninstallFilter ethUninstallFilter = objectMapper.readValue( "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":true}", EthUninstallFilter.class); when(web3jService.send(any(Request.class), eq(EthFilter.class))) .thenReturn(ethFilter); when(web3jService.send(any(Request.class), eq(EthLog.class))) .thenReturn(ethLog); when(web3jService.send(any(Request.class), eq(EthUninstallFilter.class))) .thenReturn(ethUninstallFilter); Observable<EthBlock> observable = web3j.catchUpToLatestAndSubscribeToNewBlocksObservable( new DefaultBlockParameterNumber(BigInteger.ZERO), false); CountDownLatch transactionLatch = new CountDownLatch(expected.size()); CountDownLatch completedLatch = new CountDownLatch(1); List<EthBlock> results = new ArrayList<>(expected.size()); Subscription subscription = observable.subscribe( result -> { results.add(result); transactionLatch.countDown(); }, throwable -> fail(throwable.getMessage()), () -> completedLatch.countDown()); transactionLatch.await(1250, TimeUnit.MILLISECONDS); assertThat(results, equalTo(expected)); subscription.unsubscribe(); completedLatch.await(1, TimeUnit.SECONDS); assertTrue(subscription.isUnsubscribed()); } private EthBlock createBlock(int number) { EthBlock ethBlock = new EthBlock(); EthBlock.Block block = new EthBlock.Block(); block.setNumber(Numeric.encodeQuantity(BigInteger.valueOf(number))); ethBlock.setResult(block); return ethBlock; } }