InvalidChainIdHashHandler extends ComparableFailoverHandler { @Override public <T> Response<T> handle(final Invocation<T> invocation, final Response<T> response) { try { logger.debug("Handle {} with {}", response.getError(), this); if (null == response.getError() || !(response.getError() instanceof CommitException)) { return response; } final CommitException commitException = (CommitException) response.getError(); if (!commitException.getMessage().contains("invalid chain id hash")) { return response; } final Context current = ContextHolder.current(); logger.trace("Context: {}", current); final ChainIdHashHolder chainIdHashHolder = current.get(GRPC_VALUE_CHAIN_ID_HASH_HOLDER); if (null == chainIdHashHolder) { throw new HerajException("No chain id hash holder in context"); } final RequestMethod<BlockchainStatus> requestMethod = blockchainMethods.getBlockchainStatus(); final ChainIdHash chainIdHash = requestMethod.invoke().getChainIdHash(); logger.debug("Fetched ChainIdHash: {}", chainIdHash); chainIdHashHolder.put(chainIdHash); } catch (HerajException e) { throw e; } catch (Exception e) { throw new HerajException("Unexpected error", e); } Response<T> next; try { final T ret = invocation.invoke(); next = Response.success(ret); } catch (Exception e) { next = Response.fail(e); } return next; } InvalidChainIdHashHandler(); @Override Response<T> handle(final Invocation<T> invocation, final Response<T> response);  }
@Test public void testHandleWithNextRequestSuccess() throws Throwable { runOnOtherThread(new Runnable() { @Override public void run() { try { final Context context = EmptyContext.getInstance() .withValue(GRPC_VALUE_CHAIN_ID_HASH_HOLDER, new ChainIdHashHolder()); ContextHolder.attach(context); final InvalidChainIdHashHandler failoverHandler = new InvalidChainIdHashHandler(); final ChainIdHash chainIdHash = ChainIdHash.of(BytesValue.EMPTY); final BlockchainMethods mockBlockchainMethods = mock(BlockchainMethods.class); final RequestMethod<BlockchainStatus> blockchainStatusRequestMethod = TestRequestMethod .success(BlockchainStatus.newBuilder().chainIdHash(chainIdHash).build()); when(mockBlockchainMethods.getBlockchainStatus()) .thenReturn(blockchainStatusRequestMethod); failoverHandler.blockchainMethods = mockBlockchainMethods; final Object expected = randomUUID().toString(); final Invocation<Object> invocation = new TestInvocation<>( TestRequestMethod.success(expected)); final Exception error = new CommitException(types.Rpc.CommitStatus.TX_INTERNAL_ERROR, "invalid chain id hash"); final Response<Object> response = Response.fail(error); final Response<Object> handled = failoverHandler.handle(invocation, response); assertEquals(expected, handled.getValue()); } finally { ContextHolder.remove(); } } }); }
@Test public void testHandleWithNextRequestFailure() throws Throwable { runOnOtherThread(new Runnable() { @Override public void run() { try { final Context context = EmptyContext.getInstance() .withValue(GRPC_VALUE_CHAIN_ID_HASH_HOLDER, new ChainIdHashHolder()); ContextHolder.attach(context); final InvalidChainIdHashHandler failoverHandler = new InvalidChainIdHashHandler(); final ChainIdHash chainIdHash = ChainIdHash.of(BytesValue.EMPTY); final BlockchainMethods mockBlockchainMethods = mock(BlockchainMethods.class); final RequestMethod<BlockchainStatus> blockchainStatusRequestMethod = TestRequestMethod .success(BlockchainStatus.newBuilder().chainIdHash(chainIdHash).build()); when(mockBlockchainMethods.getBlockchainStatus()) .thenReturn(blockchainStatusRequestMethod); failoverHandler.blockchainMethods = mockBlockchainMethods; final Exception expected = new UnsupportedOperationException(); final Invocation<Object> invocation = new TestInvocation<>( TestRequestMethod.fail(expected)); final Exception error = new CommitException(types.Rpc.CommitStatus.TX_INTERNAL_ERROR, "invalid chain id hash"); final Response<Object> response = Response.fail(error); final Response<Object> handled = failoverHandler.handle(invocation, response); assertEquals(expected, handled.getError()); } finally { ContextHolder.remove(); } } }); }
@Test public void shouldNotHandleOnNoError() { final FailoverHandler failoverHandler = new InvalidChainIdHashHandler(); final String expected = randomUUID().toString(); final Response<String> response = Response.success(expected); final Response<String> handled = failoverHandler.handle(null, response); assertEquals(expected, handled.getValue()); }
@Test public void shouldNotHandleOnNoCommitException() { final FailoverHandler failoverHandler = new InvalidChainIdHashHandler(); final Exception expected = new UnsupportedOperationException(); final Response<Object> response = Response.fail(expected); final Response<Object> handled = failoverHandler.handle(null, response); assertEquals(expected, handled.getError()); }