Skip to content

Commit 65e147b

Browse files
SQS-375 | Unit test createFormattedLimitOrder
Implements requested improvements: Define error messages as types
1 parent e4ce755 commit 65e147b

File tree

2 files changed

+70
-36
lines changed

2 files changed

+70
-36
lines changed

orderbook/usecase/orderbook_usecase.go

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
orderbookgrpcclientdomain "github.com/osmosis-labs/sqs/domain/orderbook/grpcclient"
1616
"github.com/osmosis-labs/sqs/log"
1717
"github.com/osmosis-labs/sqs/orderbook/telemetry"
18+
"github.com/osmosis-labs/sqs/orderbook/types"
1819
"github.com/osmosis-labs/sqs/sqsdomain"
1920
"go.uber.org/zap"
2021

@@ -262,33 +263,44 @@ func (o *orderbookUseCaseImpl) createFormattedLimitOrder(
262263
tickForOrder, ok := o.orderbookRepository.GetTickByID(poolID, order.TickId)
263264
if !ok {
264265
telemetry.GetTickByIDNotFoundCounter.Inc()
265-
return orderbookdomain.LimitOrder{}, fmt.Errorf("tick not found %s, %d", orderbookAddress, order.TickId)
266+
return orderbookdomain.LimitOrder{}, types.TickForOrderbookNotFoundError{
267+
OrderbookAddress: orderbookAddress,
268+
TickID: order.TickId,
269+
}
266270
}
267271

268272
tickState := tickForOrder.TickState
269273
unrealizedCancels := tickForOrder.UnrealizedCancels
270274

271-
// Parse quantity as int64
272275
quantity, err := strconv.ParseInt(order.Quantity, 10, 64)
273276
if err != nil {
274-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing quantity: %w", err)
277+
return orderbookdomain.LimitOrder{}, types.ParsingQuantityError{
278+
Quantity: order.Quantity,
279+
Err: err,
280+
}
275281
}
276282

277283
// Convert quantity to decimal for the calculations
278284
quantityDec := osmomath.NewDec(quantity)
279285

280286
placedQuantity, err := strconv.ParseInt(order.PlacedQuantity, 10, 64)
281287
if err != nil {
282-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing placed quantity: %w", err)
288+
return orderbookdomain.LimitOrder{}, types.ParsingPlacedQuantityError{
289+
PlacedQuantity: order.PlacedQuantity,
290+
Err: err,
291+
}
283292
}
284293

285294
if placedQuantity == 0 || placedQuantity < 0 {
286-
return orderbookdomain.LimitOrder{}, fmt.Errorf("placed quantity is 0 or negative")
295+
return orderbookdomain.LimitOrder{}, types.InvalidPlacedQuantityError{PlacedQuantity: placedQuantity}
287296
}
288297

289298
placedQuantityDec, err := osmomath.NewDecFromStr(order.PlacedQuantity)
290299
if err != nil {
291-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing placed quantity: %w", err)
300+
return orderbookdomain.LimitOrder{}, types.ParsingPlacedQuantityError{
301+
PlacedQuantity: order.PlacedQuantity,
302+
Err: err,
303+
}
292304
}
293305

294306
// Calculate percent claimed
@@ -297,38 +309,56 @@ func (o *orderbookUseCaseImpl) createFormattedLimitOrder(
297309
// Calculate normalization factor for price
298310
normalizationFactor, err := o.tokensUsecease.GetSpotPriceScalingFactorByDenom(baseAsset.Symbol, quoteAsset.Symbol)
299311
if err != nil {
300-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error getting spot price scaling factor: %w", err)
312+
return orderbookdomain.LimitOrder{}, types.GettingSpotPriceScalingFactorError{
313+
BaseDenom: baseAsset.Symbol,
314+
QuoteDenom: quoteAsset.Symbol,
315+
Err: err,
316+
}
301317
}
302318

303319
// Determine tick values and unrealized cancels based on order direction
304320
var tickEtas, tickUnrealizedCancelled int64
305321
if order.OrderDirection == "bid" {
306322
tickEtas, err = strconv.ParseInt(tickState.BidValues.EffectiveTotalAmountSwapped, 10, 64)
307323
if err != nil {
308-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing bid effective total amount swapped: %w", err)
324+
return orderbookdomain.LimitOrder{}, types.ParsingTickValuesError{
325+
Field: "EffectiveTotalAmountSwapped (bid)",
326+
Err: err,
327+
}
309328
}
310329

311330
tickUnrealizedCancelled, err = strconv.ParseInt(unrealizedCancels.BidUnrealizedCancels.String(), 10, 64)
312331
if err != nil {
313-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing bid unrealized cancels: %w", err)
332+
return orderbookdomain.LimitOrder{}, types.ParsingUnrealizedCancelsError{
333+
Field: "BidUnrealizedCancels",
334+
Err: err,
335+
}
314336
}
315337
} else {
316338
tickEtas, err = strconv.ParseInt(tickState.AskValues.EffectiveTotalAmountSwapped, 10, 64)
317339
if err != nil {
318-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing ask effective total amount swapped: %w", err)
340+
return orderbookdomain.LimitOrder{}, types.ParsingTickValuesError{
341+
Field: "EffectiveTotalAmountSwapped (ask)",
342+
Err: err,
343+
}
319344
}
320345

321346
tickUnrealizedCancelled, err = strconv.ParseInt(unrealizedCancels.AskUnrealizedCancels.String(), 10, 64)
322347
if err != nil {
323-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing ask unrealized cancels: %w", err)
348+
return orderbookdomain.LimitOrder{}, types.ParsingUnrealizedCancelsError{
349+
Field: "AskUnrealizedCancels",
350+
Err: err,
351+
}
324352
}
325353
}
326354

327355
// Calculate total ETAs and total filled
328-
329356
etas, err := strconv.ParseInt(order.Etas, 10, 64)
330357
if err != nil {
331-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing etas: %w", err)
358+
return orderbookdomain.LimitOrder{}, types.ParsingEtasError{
359+
Etas: order.Etas,
360+
Err: err,
361+
}
332362
}
333363

334364
tickTotalEtas := tickEtas + tickUnrealizedCancelled
@@ -341,19 +371,19 @@ func (o *orderbookUseCaseImpl) createFormattedLimitOrder(
341371
// Calculate percent filled using
342372
percentFilled, err := osmomath.NewDecFromStr(strconv.FormatFloat(math.Min(float64(totalFilled)/float64(placedQuantity), 1), 'f', -1, 64))
343373
if err != nil {
344-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error calculating percent filled: %w", err)
374+
return orderbookdomain.LimitOrder{}, types.CalculatingPercentFilledError{Err: err}
345375
}
346376

347377
// Determine order status based on percent filled
348378
status, err := order.Status(percentFilled.MustFloat64())
349379
if err != nil {
350-
return orderbookdomain.LimitOrder{}, fmt.Errorf("mapping order status: %w", err)
380+
return orderbookdomain.LimitOrder{}, types.MappingOrderStatusError{Err: err}
351381
}
352382

353383
// Calculate price based on tick ID
354384
price, err := clmath.TickToPrice(order.TickId)
355385
if err != nil {
356-
return orderbookdomain.LimitOrder{}, fmt.Errorf("converting tick to price: %w", err)
386+
return orderbookdomain.LimitOrder{}, types.ConvertingTickToPriceError{TickID: order.TickId, Err: err}
357387
}
358388

359389
// Calculate output based on order direction
@@ -370,7 +400,10 @@ func (o *orderbookUseCaseImpl) createFormattedLimitOrder(
370400
// Convert placed_at to a nano second timestamp
371401
placedAt, err := strconv.ParseInt(order.PlacedAt, 10, 64)
372402
if err != nil {
373-
return orderbookdomain.LimitOrder{}, fmt.Errorf("error parsing placed_at: %w", err)
403+
return orderbookdomain.LimitOrder{}, types.ParsingPlacedAtError{
404+
PlacedAt: order.PlacedAt,
405+
Err: err,
406+
}
374407
}
375408
placedAt = time.Unix(0, placedAt).Unix()
376409

orderbook/usecase/orderbook_usecase_test.go

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
cltypes "github.com/osmosis-labs/osmosis/v25/x/concentrated-liquidity/types"
1010
"github.com/osmosis-labs/sqs/domain/mocks"
1111
orderbookdomain "github.com/osmosis-labs/sqs/domain/orderbook"
12+
"github.com/osmosis-labs/sqs/orderbook/types"
1213
orderbookusecase "github.com/osmosis-labs/sqs/orderbook/usecase"
1314

1415
"github.com/osmosis-labs/osmosis/osmomath"
@@ -58,15 +59,15 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
5859
quoteAsset orderbookdomain.Asset
5960
baseAsset orderbookdomain.Asset
6061
setupMocks func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock)
61-
expectedError string
62+
expectedError error
6263
expectedOrder orderbookdomain.LimitOrder
6364
}{
6465
{
6566
name: "tick not found",
6667
order: orderbookdomain.Order{
6768
TickId: 99, // Non-existent tick ID
6869
},
69-
expectedError: "tick not found",
70+
expectedError: &types.TickForOrderbookNotFoundError{},
7071
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
7172
orderbookRepo.GetTickByIDFunc = func(poolID uint64, tickID int64) (orderbookdomain.OrderbookTick, bool) {
7273
return orderbookdomain.OrderbookTick{}, false
@@ -78,7 +79,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
7879
order: orderbookdomain.Order{
7980
Quantity: "invalid", // Invalid quantity
8081
},
81-
expectedError: "error parsing quantity",
82+
expectedError: &types.ParsingQuantityError{},
8283
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
8384
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("6431", 935, "ask")
8485
},
@@ -91,7 +92,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
9192
Etas: "500",
9293
ClaimBounty: "10",
9394
},
94-
expectedError: "error parsing quantity",
95+
expectedError: &types.ParsingQuantityError{},
9596
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
9697
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("500", 100, "bid")
9798
},
@@ -102,7 +103,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
102103
Quantity: "1000",
103104
PlacedQuantity: "invalid", // Invalid placed quantity
104105
},
105-
expectedError: "error parsing placed quantity",
106+
expectedError: &types.ParsingPlacedQuantityError{},
106107
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
107108
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("813", 1331, "bid")
108109
},
@@ -115,7 +116,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
115116
Etas: "500",
116117
ClaimBounty: "10",
117118
},
118-
expectedError: "error parsing placed quantity",
119+
expectedError: &types.ParsingPlacedQuantityError{},
119120
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
120121
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("500", 100, "bid")
121122
},
@@ -126,7 +127,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
126127
Quantity: "1000",
127128
PlacedQuantity: "0", // division by zero
128129
},
129-
expectedError: "placed quantity is 0 or negative",
130+
expectedError: &types.InvalidPlacedQuantityError{},
130131
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
131132
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("813", 1331, "bid")
132133
},
@@ -137,7 +138,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
137138
Quantity: "931",
138139
PlacedQuantity: "183",
139140
},
140-
expectedError: "error getting spot price scaling factor",
141+
expectedError: &types.GettingSpotPriceScalingFactorError{},
141142
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
142143
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("130", 13, "ask")
143144
tokensUsecase.GetSpotPriceScalingFactorByDenomFunc = func(baseDenom, quoteDenom string) (osmomath.Dec, error) {
@@ -152,7 +153,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
152153
PlacedQuantity: "131",
153154
OrderDirection: "bid",
154155
},
155-
expectedError: "error parsing bid effective total amount swapped",
156+
expectedError: &types.ParsingTickValuesError{},
156157
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
157158
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("invalid", 13, "bid")
158159
},
@@ -164,7 +165,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
164165
PlacedQuantity: "131",
165166
OrderDirection: "ask",
166167
},
167-
expectedError: "error parsing ask effective total amount swapped",
168+
expectedError: &types.ParsingTickValuesError{},
168169
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
169170
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("invalid", 1, "ask")
170171
},
@@ -176,7 +177,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
176177
PlacedQuantity: "153",
177178
OrderDirection: "bid",
178179
},
179-
expectedError: "error parsing bid unrealized cancels",
180+
expectedError: &types.ParsingUnrealizedCancelsError{},
180181
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
181182
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("15", 0, "bid")
182183
},
@@ -188,7 +189,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
188189
PlacedQuantity: "313",
189190
OrderDirection: "ask",
190191
},
191-
expectedError: "error parsing ask unrealized cancels",
192+
expectedError: &types.ParsingUnrealizedCancelsError{},
192193
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
193194
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("13", 0, "ask")
194195
},
@@ -201,7 +202,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
201202
OrderDirection: "bid",
202203
Etas: "invalid", // Invalid ETAs
203204
},
204-
expectedError: "error parsing etas",
205+
expectedError: &types.ParsingEtasError{},
205206
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
206207
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("386", 830, "bid")
207208
},
@@ -215,7 +216,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
215216
Etas: "9223372036854775808", // overflow value for int64
216217
ClaimBounty: "10",
217218
},
218-
expectedError: "error parsing etas",
219+
expectedError: &types.ParsingEtasError{},
219220
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
220221
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("500", 100, "bid")
221222
},
@@ -229,7 +230,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
229230
OrderDirection: "ask",
230231
Etas: "100",
231232
},
232-
expectedError: "converting tick to price",
233+
expectedError: &types.ConvertingTickToPriceError{},
233234
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
234235
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("190", 150, "ask")
235236
},
@@ -244,7 +245,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
244245
Etas: "100",
245246
PlacedAt: "invalid", // Invalid timestamp
246247
},
247-
expectedError: "error parsing placed_at",
248+
expectedError: &types.ParsingPlacedAtError{},
248249
setupMocks: func(orderbookRepo *mocks.OrderbookRepositoryMock, tokensUsecase *mocks.TokensUsecaseMock) {
249250
orderbookRepo.GetTickByIDFunc = getTickByIDFunc("100", 100, "ask")
250251
tokensUsecase.GetSpotPriceScalingFactorByDenomFunc = func(baseDenom, quoteDenom string) (osmomath.Dec, error) {
@@ -273,7 +274,7 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
273274
return osmomath.NewDec(1), nil
274275
}
275276
},
276-
expectedError: "",
277+
expectedError: nil,
277278
expectedOrder: orderbookdomain.LimitOrder{
278279
TickId: 1,
279280
OrderId: 1,
@@ -319,9 +320,9 @@ func (s *OrderbookUsecaseTestSuite) TestCreateFormattedLimitOrder() {
319320
result, err := usecase.CreateFormattedLimitOrder(tc.poolID, tc.order, tc.quoteAsset, tc.baseAsset, "someOrderbookAddress")
320321

321322
// Assert the results
322-
if tc.expectedError != "" {
323+
if tc.expectedError != nil {
323324
s.Assert().Error(err)
324-
s.Assert().Contains(err.Error(), tc.expectedError)
325+
s.Assert().ErrorAs(err, tc.expectedError)
325326
} else {
326327
s.Assert().NoError(err)
327328
s.Assert().Equal(tc.expectedOrder, result)

0 commit comments

Comments
 (0)