224 lines
6.0 KiB
Ruby
224 lines
6.0 KiB
Ruby
|
# require "eventmachine"
|
||
|
RSpec.describe Rex::Server::MatchingEngine do
|
||
|
let(:inbox) { MockQueue.new }
|
||
|
let(:outbox) { MockQueue.new }
|
||
|
|
||
|
subject(:instance) { described_class.new(inbox, outbox) }
|
||
|
|
||
|
around do |example|
|
||
|
instance.start
|
||
|
example.run
|
||
|
instance.stop
|
||
|
end
|
||
|
|
||
|
before do
|
||
|
messages.each do |message|
|
||
|
inbox.push(message)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe "order creation message" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 1,
|
||
|
price: 10,
|
||
|
quantity: 20,
|
||
|
side: :buy
|
||
|
)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "sends order created event followed by order book update event" do
|
||
|
expect(outbox.messages).to eq([
|
||
|
Rex::Server::Messages::OrderCreatedEvent.new(1, 1, :buy, 20, 20, 10),
|
||
|
Rex::Server::Messages::OrderBookUpdateEvent.new(:buy, 10, 20)
|
||
|
])
|
||
|
end
|
||
|
|
||
|
context "when my order matches an order" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 1,
|
||
|
price: 10,
|
||
|
quantity: 20,
|
||
|
side: :buy
|
||
|
),
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 2,
|
||
|
price: 9,
|
||
|
quantity: 22,
|
||
|
side: :sell
|
||
|
)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns order book updates, order fill updates and trades" do
|
||
|
expect(outbox.messages).to eq([
|
||
|
Rex::Server::Messages::OrderCreatedEvent.new(id: 1, user_id: 1, side: :buy, quantity: 20, remaining_quantity: 20, price: 10),
|
||
|
Rex::Server::Messages::OrderBookUpdateEvent.new(side: :buy, price: 10, quantity: 20),
|
||
|
Rex::Server::Messages::OrderCreatedEvent.new(id: 2, user_id: 2, side: :sell, quantity: 22, remaining_quantity: 22, price: 9),
|
||
|
Rex::Server::Messages::OrderBookUpdateEvent.new(side: :sell, price: 9, quantity: 22),
|
||
|
Rex::Server::Messages::TradeEvent.new(id: 1, price: 9, quantity: 20),
|
||
|
Rex::Server::Messages::OrderFillEvent.new(id: 1, user_id: 1, price: 10, side: :buy, remaining_quantity: 0),
|
||
|
Rex::Server::Messages::OrderFillEvent.new(id: 2, user_id: 2, price: 9, side: :sell, remaining_quantity: 2),
|
||
|
Rex::Server::Messages::OrderBookUpdateEvent.new(side: :buy, price: 10, quantity: 0),
|
||
|
Rex::Server::Messages::OrderBookUpdateEvent.new(side: :sell, price: 9, quantity: 2)
|
||
|
])
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe "cancel order request" do
|
||
|
context "when order is not existent" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::CancelOrderRequest.new(1, 1)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns nothing" do
|
||
|
expect(outbox.messages).to be_empty
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context "when order exists" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 1,
|
||
|
price: 10,
|
||
|
quantity: 20,
|
||
|
side: :buy
|
||
|
),
|
||
|
Rex::Server::Messages::CancelOrderRequest.new(1, 1)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns a cancelled order event and updates the order book" do
|
||
|
expect(outbox.messages.last(2)).to eq([
|
||
|
Rex::Server::Messages::OrderCancelledEvent.new(id: 1, user_id: 1, side: :buy, remaining_quantity: 20, price: 10),
|
||
|
Rex::Server::Messages::OrderBookUpdateEvent.new(side: :buy, price: 10, quantity: 0)
|
||
|
])
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe "fetch order book request" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 1,
|
||
|
price: 10,
|
||
|
quantity: 20,
|
||
|
side: :buy
|
||
|
),
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 2,
|
||
|
price: 11,
|
||
|
quantity: 22,
|
||
|
side: :sell
|
||
|
),
|
||
|
Rex::Server::Messages::FetchOrderBookRequest.new(3)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns a list limit order book updates" do
|
||
|
expect(outbox.messages.last(2)).to eq([
|
||
|
Rex::Server::Messages::OrderBookFetchEvent.new(
|
||
|
3,
|
||
|
:buy,
|
||
|
10,
|
||
|
20
|
||
|
),
|
||
|
Rex::Server::Messages::OrderBookFetchEvent.new(
|
||
|
3,
|
||
|
:sell,
|
||
|
11,
|
||
|
22
|
||
|
)
|
||
|
])
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe "fetch trades request" do
|
||
|
context "when no trades exist" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::FetchTradesRequest.new(1)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns nothing" do
|
||
|
expect(outbox.messages).to be_empty
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context "when trades exist" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 1,
|
||
|
price: 10,
|
||
|
quantity: 15,
|
||
|
side: :buy
|
||
|
),
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 2,
|
||
|
price: 10,
|
||
|
quantity: 15,
|
||
|
side: :sell
|
||
|
),
|
||
|
Rex::Server::Messages::FetchTradesRequest.new(1)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns trade fetch events" do
|
||
|
expect(outbox.messages.last(1)).to eq([
|
||
|
Rex::Server::Messages::TradeFetchEvent.new(
|
||
|
id: 1,
|
||
|
user_id: 1,
|
||
|
price: 10,
|
||
|
quantity: 15
|
||
|
)
|
||
|
])
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe "fetch orders request" do
|
||
|
context "when user does not have any orders" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::FetchOrdersRequest.new(1)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns nothing" do
|
||
|
expect(outbox.messages).to be_empty
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context "when user has orders" do
|
||
|
let(:messages) do
|
||
|
[
|
||
|
Rex::Server::Messages::CreateOrderRequest.new(
|
||
|
user_id: 1,
|
||
|
price: 10,
|
||
|
quantity: 15,
|
||
|
side: :sell
|
||
|
),
|
||
|
Rex::Server::Messages::FetchOrdersRequest.new(1)
|
||
|
]
|
||
|
end
|
||
|
|
||
|
it "returns the orders" do
|
||
|
expect(outbox.messages.last).to eq(
|
||
|
Rex::Server::Messages::OrderFetchEvent.new(id: 1, user_id: 1, side: :sell, quantity: 15, remaining_quantity: 15, price: 10)
|
||
|
)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|