code.vegaprotocol.io/vega@v0.79.0/datanode/broker/mocks/broker_drop_in_mock.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package mocks
    17  
    18  import (
    19  	"sync"
    20  
    21  	"code.vegaprotocol.io/vega/core/events"
    22  
    23  	"github.com/golang/mock/gomock"
    24  )
    25  
    26  // MockBroker - drop in mock that allows us to check the events themselves in unit tests (and as such ensure the state changes are correct)
    27  // We're only overriding the Send and SendBatch functions. The way in which this is done shouldn't be a problem, even when using DoAndReturn, but you never know...
    28  type MockBroker struct {
    29  	// embed the broker mock here... this is how we can end up with a drop-in replacement
    30  	*MockTestInterface
    31  
    32  	// settlement has a TestConcurrent test, which causes data race on this wrapped mock
    33  	mu *sync.Mutex
    34  	// all events in a map per type
    35  	// the last of each event type
    36  	// and last events for each event type by ID (e.g. latest order event given the order ID)
    37  	allEvts    map[events.Type][]events.Event
    38  	lastEvts   map[events.Type]events.Event
    39  	lastEvtsID map[events.Type]map[string]events.Event
    40  }
    41  
    42  func NewMockBroker(ctrl *gomock.Controller) *MockBroker {
    43  	mbi := NewMockTestInterface(ctrl)
    44  	return &MockBroker{
    45  		MockTestInterface: mbi,
    46  		mu:                &sync.Mutex{},
    47  		allEvts:           map[events.Type][]events.Event{},
    48  		lastEvts:          map[events.Type]events.Event{},
    49  		lastEvtsID:        map[events.Type]map[string]events.Event{},
    50  	}
    51  }
    52  
    53  // Send - first call Send on the underlying mock, then add the argument to the various maps.
    54  func (b *MockBroker) Send(event events.Event) {
    55  	// first call the regular mock
    56  	b.MockTestInterface.Send(event)
    57  	b.mu.Lock()
    58  	t := event.Type()
    59  	s, ok := b.allEvts[t]
    60  	if !ok {
    61  		s = []events.Event{}
    62  	}
    63  	s = append(s, event)
    64  	b.allEvts[t] = s
    65  	b.lastEvts[t] = event
    66  	if ok, id := isIDEvt(event); ok {
    67  		m, ok := b.lastEvtsID[t]
    68  		if !ok {
    69  			m = map[string]events.Event{}
    70  		}
    71  		m[id] = event
    72  		b.lastEvtsID[t] = m
    73  	}
    74  	b.mu.Unlock()
    75  }
    76  
    77  // GetAllByType returns all events of a given type the mock has received.
    78  func (b *MockBroker) GetAllByType(t events.Type) []events.Event {
    79  	b.mu.Lock()
    80  	allEvts := b.allEvts
    81  	b.mu.Unlock()
    82  	if s, ok := allEvts[t]; ok {
    83  		return s
    84  	}
    85  	return nil
    86  }
    87  
    88  // GetLastByType returns the most recent event for a given type. If SendBatch was called, this is the last event of the batch.
    89  func (b *MockBroker) GetLastByType(t events.Type) events.Event {
    90  	b.mu.Lock()
    91  	defer b.mu.Unlock()
    92  	return b.lastEvts[t]
    93  }
    94  
    95  // GetLastByTypeAndID returns the last event of a given type, for a specific identified (party, market, order, etc...)
    96  // list of implemented events - and ID's used:
    97  //   - Order (by order ID)
    98  //   - Account (by account ID)
    99  //   - Asset (by asset ID)
   100  //   - Auction (by market ID)
   101  //   - Deposit (party ID)
   102  //   - Proposal (proposal ID)
   103  //   - LP (by party ID)
   104  //   - MarginLevels (party ID)
   105  //   - MarketData (market ID)
   106  //   - PosRes (market ID)
   107  //   - RiskFactor (market ID)
   108  //   - SettleDistressed (party ID)
   109  //   - Vote (currently PartyID, might want to use proposalID, too?)
   110  //   - Withdrawal (PartyID)
   111  func (b *MockBroker) GetLastByTypeAndID(t events.Type, id string) events.Event {
   112  	b.mu.Lock()
   113  	m, ok := b.lastEvtsID[t]
   114  	b.mu.Unlock()
   115  	if !ok {
   116  		return nil
   117  	}
   118  	return m[id]
   119  }
   120  
   121  // @TODO loss socialization. Given that this is something that would impact several parties, there's most likely
   122  // no real point to filtering by ID.
   123  // Not implemented yet, but worth considering:
   124  //   - Trade
   125  //   - TransferResponse
   126  //
   127  // Implemented events:
   128  //   - Order (by order ID)
   129  //   - Account (by account ID)
   130  //   - Asset (by asset ID)
   131  //   - Auction (by market ID)
   132  //   - Deposit (party ID)
   133  //   - Proposal (proposal ID)
   134  //   - LP (by party ID)
   135  //   - MarginLevels (party ID)
   136  //   - MarketData (market ID)
   137  //   - PosRes (market ID)
   138  //   - RiskFactor (market ID)
   139  //   - SettleDistressed (party ID)
   140  //   - Vote (currently PartyID, might want to use proposalID, too?)
   141  //   - Withdrawal (PartyID)
   142  func isIDEvt(e events.Event) (bool, string) {
   143  	switch et := e.(type) {
   144  	case *events.Order:
   145  		return true, et.Order().Id
   146  	case events.Order:
   147  		return true, et.Order().Id
   148  	case *events.Acc:
   149  		return true, et.Account().Id
   150  	case events.Acc:
   151  		return true, et.Account().Id
   152  	case *events.Asset:
   153  		return true, et.Asset().Id
   154  	case events.Asset:
   155  		return true, et.Asset().Id
   156  	case *events.Auction:
   157  		return true, et.MarketID()
   158  	case events.Auction:
   159  		return true, et.MarketID()
   160  	case *events.Deposit:
   161  		return true, et.Deposit().PartyId
   162  	case events.Deposit:
   163  		return true, et.Deposit().PartyId
   164  	case *events.Proposal:
   165  		return true, et.ProposalID()
   166  	case events.Proposal:
   167  		return true, et.ProposalID()
   168  	case *events.LiquidityProvision:
   169  		return true, et.PartyID()
   170  	case events.LiquidityProvision:
   171  		return true, et.PartyID()
   172  	case *events.MarginLevels:
   173  		return true, et.PartyID()
   174  	case events.MarginLevels:
   175  		return true, et.PartyID()
   176  	case *events.MarketData:
   177  		return true, et.MarketID()
   178  	case events.MarketData:
   179  		return true, et.MarketID()
   180  	case *events.PosRes:
   181  		return true, et.MarketID()
   182  	case events.PosRes:
   183  		return true, et.MarketID()
   184  	case *events.RiskFactor:
   185  		return true, et.MarketID()
   186  	case events.RiskFactor:
   187  		return true, et.MarketID()
   188  	case *events.SettleDistressed:
   189  		return true, et.PartyID()
   190  	case events.SettleDistressed:
   191  		return true, et.PartyID()
   192  	case *events.Vote:
   193  		return true, et.PartyID()
   194  	case events.Vote:
   195  		return true, et.PartyID()
   196  	case *events.Withdrawal:
   197  		return true, et.PartyID()
   198  	case events.Withdrawal:
   199  		return true, et.PartyID()
   200  	}
   201  	return false, ""
   202  }