How to mock a responder flow in corda - corda

I am trying to mock a responder flow inside my unit tests, my responder flow does several validations that deals with configurations and off ledger services. I would like to mock the value to always return a true so that the unit test does not have any dependencies on the other components in the network.
The purpose is only for unit tests, is there any way I could mock the response using API as I am aware that we have to register the responder classes during the mock network setup?

Simply define a dummy responder flow, and register that instead of the real responder flow when setting up the mock network:
public class FlowTests {
private MockNetwork network;
private StartedMockNode a;
private StartedMockNode b;
#InitiatedBy(ExampleFlow.Initiator.class)
public static class DummyResponder extends FlowLogic<Void> {
private final FlowSession otherPartySession;
public DummyResponder(FlowSession otherPartySession) {
this.otherPartySession = otherPartySession;
}
#Suspendable
#Override
public Void call() throws FlowException {
otherPartySession.send(true);
return null;
}
}
#Before
public void setup() {
network = new MockNetwork(ImmutableList.of("com.example.contract"));
a = network.createPartyNode(null);
b = network.createPartyNode(null);
// For real nodes this happens automatically, but we have to manually register the flow for tests.
for (StartedMockNode node : ImmutableList.of(a, b)) {
node.registerInitiatedFlow(DummyResponder.class);
}
network.runNetwork();
}
#After
public void tearDown() {
network.stopNodes();
}
#Rule
public final ExpectedException exception = ExpectedException.none();
#Test
public void flowUsesDummyResponder() throws ExecutionException, InterruptedException {
ExampleFlow.Initiator flow = new ExampleFlow.Initiator(-1, b.getInfo().getLegalIdentities().get(0));
CordaFuture<Boolean> future = a.startFlow(flow);
network.runNetwork();
Boolean bool = future.get();
assertEquals(true, bool);
}
}

Related

How to test a kafka consumer against a real kafka broker running on a server?

I have difficulty understanding some Kafka concepts in Java Spring Boot. I’d like to test a consumer against a real Kafka broker running on a server, which has some producers that write / have already written data to various topics. I would like to establish a connection with the server, consume the data, and verify or process its content in a test.
An enormous majority of examples (actually all I have seen so far) in the internet refer to embedded kafka, EmbeddedKafkaBroker, and show both a producer and a consumer implemented on one machine, locally. I haven’t found any example that would explain how to make a connection with a remote kafka server and read data from a particular topic.
I've written some code and I've printed the broker address with:
System.out.println(embeddedKafkaBroker.getBrokerAddress(0));
What I got is 127.0.0.1:9092, which means that it is local, so the connection with the remote server has not been established.
On the other hand, when I run the SpringBootApplication I get the payload from the remote broker.
Receiver:
#Component
public class Receiver {
private static final String TOPIC_NAME = "X";
private static final Logger LOGGER = LoggerFactory.getLogger(Receiver.class);
private CountDownLatch latch = new CountDownLatch(1);
public CountDownLatch getLatch() {
return latch;
}
#KafkaListener(topics = TOPIC_NAME)
public void receive(final byte[] payload) {
LOGGER.info("received the following payload: '{}'", payload);
latch.countDown();
}
}
Config:
#EnableKafka
#Configuration
public class ByteReceiverConfig {
#Autowired
EmbeddedKafkaBroker kafkaEmbeded;
#Value("${spring.kafka.bootstrap-servers}")
private String bootstrapServers;
#Value("${spring.kafka.consumer.group-id}")
private String groupIdConfig;
#Bean
public KafkaListenerContainerFactory<?> kafkaListenerContainerFactory() {
final ConcurrentKafkaListenerContainerFactory<Object, Object> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
return factory;
}
#Bean
ConsumerFactory<Object, Object> consumerFactory() {
return new DefaultKafkaConsumerFactory<>(consumerProperties());
}
#Bean
Map<String, Object> consumerProperties() {
final Map<String, Object> properties =
KafkaTestUtils.consumerProps("junit-test", "true", this.kafkaEmbeded);
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);
properties.put(ConsumerConfig.GROUP_ID_CONFIG, groupIdConfig);
return properties;
}
Test:
#EnableAutoConfiguration
#EnableKafka
#SpringBootTest(classes = {ByteReceiverConfig.class, Receiver.class})
#EmbeddedKafka
#ContextConfiguration(classes = ByteReceiverConfig.class)
#TestPropertySource(properties = { "spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}",
"spring.kafka.consumer.group-id=EmbeddedKafkaTest"})
public class KafkaTest {
#Autowired
private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry;
#Autowired
EmbeddedKafkaBroker embeddedKafkaBroker;
#Autowired
Receiver receiver;
#BeforeEach
void waitForAssignment() {
for (MessageListenerContainer messageListenerContainer : kafkaListenerEndpointRegistry.getListenerContainers()) {
System.out.println(messageListenerContainer.getAssignedPartitions().isEmpty());
System.out.println(messageListenerContainer.toString());
System.out.println(embeddedKafkaBroker.getTopics().size());
System.out.println(embeddedKafkaBroker.getPartitionsPerTopic());
System.out.println(embeddedKafkaBroker.getBrokerAddress(0));
System.out.println(embeddedKafkaBroker.getBrokersAsString());
ContainerTestUtils.waitForAssignment(messageListenerContainer,
embeddedKafkaBroker.getPartitionsPerTopic());
}
#Test
public void testReceive() {
}
}
I would like somebody to shed some light on the following issues:
1.Can an instance of the class EmbeddedKafkaBroker be used to test data that comes from a remote broker, or is it only used for local tests, in which I would procude i.e send data to a topic that I created and consume data myself?
2.Is it possible to write a test class for a real kafka server? For instance to verify if a connection has been establish, or if a data has been read from a specific topic. What annotations, configurations, and classes would be needed in such case?
3.If I only want to consume data, do I have to provide the producer configuration in a config file (it would be strange, but all examples I have encountered so far did it)?
4.Do you know any resources (books, websites etc.) that show real examples of using kafka i.e. with a remote kafka server, with a procuder or a consumer only?
You don't need an embedded broker at all if you want to talk to an external broker only.
Yes, just set the bootstrap servers property appropriately.
No, you don't need producer configuration.
EDIT
#SpringBootApplication
public class So56044105Application {
public static void main(String[] args) {
SpringApplication.run(So56044105Application.class, args);
}
#Bean
public NewTopic topic() {
return new NewTopic("so56044105", 1, (short) 1);
}
}
spring.kafka.bootstrap-servers=10.0.0.8:9092
spring.kafka.consumer.enable-auto-commit=false
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { So56044105Application.class, So56044105ApplicationTests.Config.class })
public class So56044105ApplicationTests {
#Autowired
public Config config;
#Test
public void test() throws InterruptedException {
assertThat(config.latch.await(10, TimeUnit.SECONDS)).isTrue();
assertThat(config.received.get(0)).isEqualTo("foo");
}
#Configuration
public static class Config implements ConsumerSeekAware {
List<String> received = new ArrayList<>();
CountDownLatch latch = new CountDownLatch(3);
#KafkaListener(id = "so56044105", topics = "so56044105")
public void listen(String in) {
System.out.println(in);
this.received.add(in);
this.latch.countDown();
}
#Override
public void registerSeekCallback(ConsumerSeekCallback callback) {
}
#Override
public void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
System.out.println("Seeking to beginning");
assignments.keySet().forEach(tp -> callback.seekToBeginning(tp.topic(), tp.partition()));
}
#Override
public void onIdleContainer(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
}
}
}
There are some examples in this repository for bootstrapping real Kafka producers and consumers across a variety of configurations — plaintext, SSL, with and without authentication, etc.
Note: the repo above contains examples for the Effective Kafka book, which I am the author of. However, they can be used freely without the book and hopefully they make just as much sense on their own.
More to the point, here are a pair of examples for a basic producer and a consumer.
/** A sample Kafka producer. */
import static java.lang.System.*;
import java.util.*;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.*;
public final class BasicProducerSample {
public static void main(String[] args) throws InterruptedException {
final var topic = "getting-started";
final Map<String, Object> config =
Map.of(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092",
ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName(),
ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName(),
ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);
try (var producer = new KafkaProducer<String, String>(config)) {
while (true) {
final var key = "myKey";
final var value = new Date().toString();
out.format("Publishing record with value %s%n",
value);
final Callback callback = (metadata, exception) -> {
out.format("Published with metadata: %s, error: %s%n",
metadata, exception);
};
// publish the record, handling the metadata in the callback
producer.send(new ProducerRecord<>(topic, key, value), callback);
// wait a second before publishing another
Thread.sleep(1000);
}
}
}
}
/** A sample Kafka consumer. */
import static java.lang.System.*;
import java.time.*;
import java.util.*;
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.serialization.*;
public final class BasicConsumerSample {
public static void main(String[] args) {
final var topic = "getting-started";
final Map<String, Object> config =
Map.of(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092",
ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName(),
ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName(),
ConsumerConfig.GROUP_ID_CONFIG, "basic-consumer-sample",
ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest",
ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
try (var consumer = new KafkaConsumer<String, String>(config)) {
consumer.subscribe(Set.of(topic));
while (true) {
final var records = consumer.poll(Duration.ofMillis(100));
for (var record : records) {
out.format("Got record with value %s%n", record.value());
}
consumer.commitAsync();
}
}
}
}
Now, these are obviously not unit tests. But with very little rework they could be turned into one. The next step would be to remove Thread.sleep() and add assertions. Note, since Kafka is inherently asynchronous, naively asserting a published message in a consumer immediately after publishing will fail. For a robust, repeatable test, you may want to use something like Timesert.

In Corda, how to start a flow from a service?

I have created a CordaService running on my node. I want this service to start flows based on various conditions. However, the ServiceHub provided to the service does not provide the ability to start flows.
Is there any flow for a service to start a flow? How would I do thi?
Yes. Simply pass your CordaService an AppServiceHub instead of a ServiceHub in its constructor.
The AppServiceHub interface extends the ServiceHub interface to give a node the ability to start flows:
interface AppServiceHub : ServiceHub {
fun <T> startFlow(flow: FlowLogic<T>): FlowHandle<T>
fun <T> startTrackedFlow(flow: FlowLogic<T>): FlowProgressHandle<T>
}
Yes, pass AppServiceHub to the constructor
In Kotlin:
class MyCordaService(private val serviceHub: AppServiceHub) : SingletonSerializeAsToken() {
init {
// code ran at service creation / node startup
}
// public api of service
}
or Java:
public class MyCordaService extends SingletonSerializeAsToken {
private AppServiceHub serviceHub;
public MyCordaService(AppServiceHub serviceHub) {
this.serviceHub = serviceHub;
// code ran at service creation / node startup
}
// public api of service
}
Important: to avoid possible any potential deadlocks between running nodes, start inner flows from their own Thread
For example:
public class MyCordaService extends SingletonSerializeAsToken {
private AppServiceHub serviceHub;
public MyCordaService(AppServiceHub serviceHub) {
this.serviceHub = serviceHub;
// code ran at service creation / node startup
}
// public api of service
public void doSomething(){
// do something and start a new flow
Thread flowThread = new Thread(new StartFlow());
flowThread.start();
}
private class StartFlow implements Runnable {
#Override
public void run() {
// start new flow
CordaFuture<SignedTransaction> cordaFuture= appServiceHub.startFlow(new
Flow(params).getReturnValue();
SignedTransaction signedTransaction = cordaFuture.get();
}
}
}

CordaApp with Spring Boot Api different response

I have integrated the cordapp with spring boot .One strange observation we found that the response differs coming from the cordawebserver and spring boot server for example
Blockquote
API :GET: market/me
gives
{
“me”: {
“commonName”: null,
“organisationUnit”: null,
“organisation”: “PartyG-CT”,
“locality”: “Tokyo”,
“state”: null,
“country”: “JP”,
“x500Principal”: {
“name”: “O=PartyG-CT,L=Tokyo,C=JP”,
“encoded”: “MDExCzAJBgNVBAYTAkpQMQ4wDAYDVQQHDAVUb2t5bzESMBAGA1UECgwJUGFydHlHLUNU”
}
}
}
with Spring boot
while with cordawebserver we are getting :
{
“me”: “C=JP,L=Tokyo,O=PartyG-CT”
}
Same behaviour we are finding the same for different APIs Any help will be appreciated
#GET
#Path("peers")
#Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON)
// CordaX500Name
public Map<String, List<CordaX500Name>> getPeers() {
List<NodeInfo> nodeInfoSnapshot = proxy.networkMapSnapshot();
return ImmutableMap.of(
"peers",
nodeInfoSnapshot
.stream()
.map(node -> node.getLegalIdentities().get(0).getName())
.filter(name -> !name.equals(myLegalName) && !name.getOrganisation().equals(controllerName)
&& !name.getOrganisation().equals(NETWORK_MAP_NAME))
.collect(toList()));
}
//boot entry point
#SpringBootApplication
public class FacilityServer {
#Autowired
public static NodeRPCConnection nodeRPCConnection;
/**
* Starts our Spring Boot application.
*/
public static void main(String[] args) throws Exception {
SpringApplication springApplication = new SpringApplication();
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(FacilityServer.class, args);
}
#EventListener(ApplicationReadyEvent.class)
public void initiateFacilityObserverPostStartup() throws Exception{
FacilityObserver.startFacilityWatch();
}
// this class for using the jersey instead of spring rest impltn
#Configuration
#ApplicationPath("rest")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
}
#PostConstruct
public void setUp() {
register(MarketApi.class);
//register(GenericExceptionMapper.class);
}
}
I found the solution ;According to the corda documentation we need to register cordajackson mapper .Then, we will be able to get the same response as in corda webserer.
for example:
List<StateAndRef<YourState>> vaultStatesList = vaultStates.getStates();
ObjectMapper mapper = JacksonSupport.createNonRpcMapper();
String json = mapper.writeValueAsString(vaultStatesList);

How to write a mockito test case for ResourceAssembler with in Spring Hateos?

I am trying to write a unit test for the below Assembler but i keep getting Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler?. I wanted to know how i can mock out the resource creation?
#Component
public class LoginResourceAssembler extends ResourceAssemblerSupport<User, ResourceSupport> {
public LoginResourceAssembler() {
super(User.class, ResourceSupport.class);
}
#Override
public ResourceSupport toResource(User user) {
ResourceSupport resource = new ResourceSupport();
final String id = user.getId();
resource.add(linkTo(MyAccountsController.class).slash(id).slash("accounts").withRel("accounts"));
return resource;
}
}
Instead of changing from a plain unit test to a IMO integration test (given dependency of the spring framework) you could do something like:
#RunWith(MockitoJUnitRunner.class)
public class LoginResourceAssemblerTest {
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setup() {
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
}
#Test
public void testToResource() {
//...
}
}
I was seeing the error Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler because my test class was annotated with #RunWith(MockitoJUnitRunner.class) and this was not injecting the controller.
To fix this error, i annotated my test case with
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
A working test case in my case
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class LoginResourceAssemblerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setUp() {
initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void testToResource() {
User user = new User();
user.setId("1234");
ResourceSupport resource = loginResourceAssembler.toResource(user);
assertEquals(1,resource.getLinks().size());
assertEquals("accounts",resource.getLinks().get(0).getRel());
assertTrue(resource.getLinks().get(0).getHref().contains("accounts"));
}
}

Apache Camel Integration test results in OutOfMemory

I have a simple Camel route that sends data to an external REST interface, integrated with Spring MVC.
#RestController
public class MyController {
#Autowired
private camelService camelService;
#RequestMapping(method = RequestMethod.POST, value = "/test")
#ResponseStatus(HttpStatus.CREATED)
public TestModel createEV(#Valid #RequestBody TestModel testModel) {
camelService.publishTestCase(testModel);
return testModel;
}
}
#Service
public class CamelService {
#Produce(uri = "direct:test")
private ProducerTemplate producerTemplate;
#Override
public void publishTestCase(TestModel testModel) {
producerTemplate.sendBody(testModel);
}
}
#Component
public class TestRouter extends SpringRouteBuilder
#Override
public void configure() throws Exception {
errorHandler(loggingErrorHandler(log).level(LoggingLevel.ERROR));
from("direct:test")
.routeId("testRoute")
.beanRef("mapper", "map")
.to("velocity:test.vm")
.setHeader(Exchange.HTTP_METHOD, simple("POST"))
.to("log:test?level=DEBUG&showAll=true&multiline=true&maxChars=100000")
.to("cxfrs:http://url.here");
}
}
Then there's an integration test for the rest endpoint with mockMvc that mocks the external camel endpoint.
#ContextConfiguration(loader = SpringApplicationContextLoader, classes = Application)
#WebIntegrationTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MyControllerIntegrationTest extends Specification {
#Autowired
private CamelContext camelContext
MockMvc mockMvc
#Autowired
WebApplicationContext wac
#Shared
def setupOnceRun = false
#Shared
def validInput = new File(JSON_DIR + '/valid.json').text
def setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
// no way to use setupSpec as Autowired fields can't be Shared
if (!setupOnceRun) {
ModelCamelContext mcc = camelContext.adapt(ModelCamelContext);
camelContext.getRouteDefinition("testRoute).adviceWith(mcc, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
mockEndpointsAndSkip("cxfrs:http://url.here")
}
});
setupOnceRun = true
}
}
def 'valid scenario'() {
setup:
MockEndpoint mockEndpoint = (MockEndpoint) camelContext.hasEndpoint("mock:cxfrs:http://url.here")
mockEndpoint.expectedMessageCount(1)
when:
def response = mockMvc.perform(post('/test').content(validInput)).andReturn()
then:
response.getResponse().getStatus() == 201
mockEndpoint.assertIsSatisfied()
}
}
The test is passing if you run it by itself but once it's included in the build together with other integration tests it's constantly producing OutOfMemory. MaxPermSize is 4G, it doesn't look like that's an issue. I am new to Camel so my guess is that I am wiring the test in a wrong way. Would appreciate any suggestions.

Resources