Skip to content

Commit c83d637

Browse files
authored
Merge pull request #17 from Laffini/added-and-matched-events
Order added & matched events
2 parents b31308d + a29d894 commit c83d637

File tree

12 files changed

+192
-19
lines changed

12 files changed

+192
-19
lines changed

.classpath

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,11 @@
2828
<attribute name="maven.pomderived" value="true"/>
2929
</attributes>
3030
</classpathentry>
31+
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
32+
<attributes>
33+
<attribute name="maven.pomderived" value="true"/>
34+
<attribute name="test" value="true"/>
35+
</attributes>
36+
</classpathentry>
3137
<classpathentry kind="output" path="target/classes"/>
3238
</classpath>

src/main/java/net/laffyco/javamatchingengine/OrderController.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.Optional;
77

88
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.context.ApplicationEventPublisher;
910
import org.springframework.web.bind.annotation.DeleteMapping;
1011
import org.springframework.web.bind.annotation.GetMapping;
1112
import org.springframework.web.bind.annotation.PathVariable;
@@ -18,6 +19,9 @@
1819
import net.laffyco.javamatchingengine.engine.Order;
1920
import net.laffyco.javamatchingengine.engine.OrderBook;
2021
import net.laffyco.javamatchingengine.engine.Side;
22+
import net.laffyco.javamatchingengine.engine.Trade;
23+
import net.laffyco.javamatchingengine.events.OrderAddedEvent;
24+
import net.laffyco.javamatchingengine.events.OrderMatchedEvent;
2125

2226
/**
2327
* Controller for orders.
@@ -35,6 +39,12 @@ public class OrderController {
3539
@Autowired
3640
private OrderBook orderBook;
3741

42+
/**
43+
* Event publisher.
44+
*/
45+
@Autowired
46+
private ApplicationEventPublisher applicationEventPublisher;
47+
3848
/**
3949
* Retrieve orders.
4050
*
@@ -81,8 +91,17 @@ public Map<String, Object> addOrder(@RequestParam("side") final Side side,
8191

8292
final Order order = new Order(amount, price, side);
8393

94+
final List<Trade> trades = this.orderBook.process(order);
95+
8496
response.put("id", order.getId());
85-
response.put("trades", this.orderBook.process(order));
97+
response.put("trades", trades);
98+
this.applicationEventPublisher
99+
.publishEvent(new OrderAddedEvent(this, order));
100+
101+
if (!trades.isEmpty()) {
102+
this.applicationEventPublisher
103+
.publishEvent(new OrderMatchedEvent(this, trades));
104+
}
86105

87106
return response;
88107
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package net.laffyco.javamatchingengine.events;
2+
3+
import org.springframework.context.ApplicationEvent;
4+
5+
import net.laffyco.javamatchingengine.engine.Order;
6+
7+
/**
8+
* Event for when an order is added to the engine.
9+
*
10+
* @author Laffini
11+
*
12+
*/
13+
public class OrderAddedEvent extends ApplicationEvent {
14+
15+
/**
16+
* The order added.
17+
*/
18+
private final Order order;
19+
20+
/**
21+
* Constructor.
22+
*
23+
* @param source
24+
* @param pOrder
25+
*/
26+
public OrderAddedEvent(final Object source, final Order pOrder) {
27+
super(source);
28+
this.order = pOrder;
29+
}
30+
31+
/**
32+
* Get order.
33+
*
34+
* @return the order
35+
*/
36+
public Order getOrder() {
37+
return this.order;
38+
}
39+
40+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package net.laffyco.javamatchingengine.events;
2+
3+
import java.util.List;
4+
5+
import org.springframework.context.ApplicationEvent;
6+
7+
import net.laffyco.javamatchingengine.engine.Trade;
8+
9+
/**
10+
* Order matched event.
11+
*
12+
* @author Laffini
13+
*
14+
*/
15+
public class OrderMatchedEvent extends ApplicationEvent {
16+
17+
/**
18+
* Completed trades.
19+
*/
20+
private final List<Trade> trades;
21+
22+
/**
23+
* Constructor.
24+
*
25+
* @param source
26+
* @param pTrades
27+
*/
28+
public OrderMatchedEvent(final Object source, final List<Trade> pTrades) {
29+
super(source);
30+
this.trades = pTrades;
31+
}
32+
33+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* @author Laffini
3+
*
4+
*/
5+
package net.laffyco.javamatchingengine.events;

src/test/java/net/laffyco/javamatchingengine/OrderControllerTests.java

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@
1212

1313
import org.junit.jupiter.api.DisplayName;
1414
import org.junit.jupiter.api.Test;
15+
import org.mockito.ArgumentCaptor;
16+
import org.mockito.Captor;
1517
import org.mockito.InjectMocks;
1618
import org.mockito.Mock;
1719
import org.mockito.Mockito;
20+
import org.springframework.context.ApplicationEvent;
21+
import org.springframework.context.ApplicationEventPublisher;
1822

1923
import net.laffyco.javamatchingengine.engine.Order;
2024
import net.laffyco.javamatchingengine.engine.OrderBook;
2125
import net.laffyco.javamatchingengine.engine.Side;
2226
import net.laffyco.javamatchingengine.engine.Trade;
27+
import net.laffyco.javamatchingengine.events.OrderAddedEvent;
28+
import net.laffyco.javamatchingengine.events.OrderMatchedEvent;
2329
import test.utils.AbstractTest;
2430

2531
/**
@@ -36,13 +42,25 @@ public class OrderControllerTests extends AbstractTest {
3642
@Mock
3743
private OrderBook orderBook;
3844

45+
/**
46+
* Event publisher.
47+
*/
48+
@Mock
49+
private ApplicationEventPublisher applicationEventPublisher;
50+
3951
/**
4052
* Controller under test.
4153
*/
4254
@InjectMocks
4355
@Resource
4456
private OrderController controller;
4557

58+
/**
59+
* Key captor.
60+
*/
61+
@Captor
62+
private ArgumentCaptor<ApplicationEvent> captor;
63+
4664
/**
4765
* Test data id.
4866
*/
@@ -61,6 +79,11 @@ public class OrderControllerTests extends AbstractTest {
6179
*/
6280
private final double amt = 25.0;
6381

82+
/**
83+
* Test data price.
84+
*/
85+
private final double price = 25;
86+
6487
@Override
6588
public final void init() {
6689
Mockito.when(this.orderBook.findOrder(this.id, this.side))
@@ -100,19 +123,41 @@ public void getOrderById() {
100123
@Test
101124
@DisplayName("Add an order")
102125
public void addOrder() {
103-
final double price = 25;
104-
105126
final List<Trade> trades = new ArrayList<Trade>();
106127
Mockito.when(this.orderBook.process(Mockito.any())).thenReturn(trades);
107128

108129
final Map<String, Object> result = this.controller.addOrder(this.side,
109-
this.amt, price);
130+
this.amt, this.price);
110131

111132
assertTrue(result.containsKey(this.id));
112133
assertTrue(result.containsKey("trades"));
113134
assertEquals(result.get("trades"), trades);
114135
}
115136

137+
/**
138+
* Checking that the correct events are published.
139+
*/
140+
@Test
141+
@DisplayName("Check that appropriate events are published")
142+
public void events() {
143+
final List<Trade> trades = new ArrayList<Trade>() {
144+
{
145+
this.add(null);
146+
}
147+
};
148+
Mockito.when(this.orderBook.process(Mockito.any())).thenReturn(trades);
149+
150+
this.controller.addOrder(this.side, this.amt, this.price);
151+
152+
Mockito.verify(this.applicationEventPublisher, Mockito.times(2))
153+
.publishEvent(this.captor.capture());
154+
155+
assertTrue(
156+
this.captor.getAllValues().get(0) instanceof OrderAddedEvent);
157+
assertTrue(
158+
this.captor.getAllValues().get(1) instanceof OrderMatchedEvent);
159+
}
160+
116161
/**
117162
* Delete an order.
118163
*/
@@ -137,16 +182,15 @@ public void deleteOrder() {
137182
@Test
138183
@DisplayName("Update an order")
139184
public void updateOrder() {
140-
final double price = 35.0;
141185
final Side newSide = Side.SELL;
142186

143187
final Map<String, Object> result = this.controller.updateOrder(this.id,
144-
this.side, Optional.of(this.amt), Optional.of(price),
188+
this.side, Optional.of(this.amt), Optional.of(this.price),
145189
Optional.of(newSide));
146190

147191
assertTrue((boolean) result.get("updated"));
148192
Mockito.verify(this.mockOrder).setAmount(this.amt);
149-
Mockito.verify(this.mockOrder).setPrice(price);
193+
Mockito.verify(this.mockOrder).setPrice(this.price);
150194
Mockito.verify(this.mockOrder).setSide(newSide);
151195
}
152196

@@ -156,7 +200,6 @@ public void updateOrder() {
156200
@Test
157201
@DisplayName("Update an order with one parameter")
158202
public void updateOrder1Param() {
159-
160203
final Map<String, Object> result = this.controller.updateOrder(this.id,
161204
this.side, Optional.of(this.amt), Optional.empty(),
162205
Optional.empty());

src/test/java/net/laffyco/javamatchingengine/scenarios/CucumberRunner.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package net.laffyco.javamatchingengine.scenarios;
22

3-
import io.cucumber.junit.Cucumber;
4-
import io.cucumber.junit.CucumberOptions;
3+
import static io.cucumber.junit.CucumberOptions.SnippetType.CAMELCASE;
4+
55
import org.junit.runner.RunWith;
66

7-
import static io.cucumber.junit.CucumberOptions.SnippetType.CAMELCASE;
7+
import io.cucumber.junit.Cucumber;
8+
import io.cucumber.junit.CucumberOptions;
89

910
/**
1011
* Cucumber test runner.
1112
*
1213
* @author Laffini
1314
*/
1415
@RunWith(Cucumber.class)
15-
@CucumberOptions(plugin = {"pretty", "summary"}, snippets = CAMELCASE,
16+
@CucumberOptions(plugin = { "pretty",
17+
"summary" }, snippets = CAMELCASE,
1618
features = "src/test/java/net/laffyco/javamatchingengine/scenarios/")
1719
public class CucumberRunner {
1820
// Intentionally left blank.

src/test/java/net/laffyco/javamatchingengine/scenarios/orders/OrdersSteps.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
package net.laffyco.javamatchingengine.scenarios.orders;
22

3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import java.util.List;
7+
38
import io.cucumber.java.en.Given;
49
import io.cucumber.java.en.Then;
510
import io.cucumber.java.en.When;
611
import net.laffyco.javamatchingengine.engine.Order;
712
import net.laffyco.javamatchingengine.engine.OrderBook;
813
import net.laffyco.javamatchingengine.engine.Side;
914

10-
import java.util.List;
11-
12-
import static org.junit.jupiter.api.Assertions.assertEquals;
13-
import static org.junit.jupiter.api.Assertions.assertTrue;
14-
1515
/**
1616
* Orders feature steps.
17+
*
1718
* @author Laffini
1819
*/
1920
public class OrdersSteps {
@@ -28,21 +29,30 @@ public class OrdersSteps {
2829
*/
2930
private Order order;
3031

32+
/**
33+
* Create the order book.
34+
*/
3135
@Given("There is an instance of the order book")
3236
public void createOrderBook() {
3337
this.orderBook = new OrderBook();
3438
}
3539

40+
/**
41+
* Add the order.
42+
*/
3643
@When("I add an order")
3744
public void addOrder() {
3845
final double amount = 10;
3946
final double price = 25.59;
4047
final Side side = Side.BUY;
4148

4249
this.order = new Order(amount, price, side);
43-
this.orderBook.process(order);
50+
this.orderBook.process(this.order);
4451
}
4552

53+
/**
54+
* Confirm order is added.
55+
*/
4656
@Then("It is added to the order book")
4757
public void orderIsAdded() {
4858
final List<Order> buyOrders = this.orderBook.getBuyOrders();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* @author Laffini
3+
*
4+
*/
5+
package net.laffyco.javamatchingengine.scenarios.orders;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* @author Laffini
3+
*
4+
*/
5+
package net.laffyco.javamatchingengine.scenarios;

0 commit comments

Comments
 (0)