# 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