chore: add market-depth-provider unit tests (#1839)
This commit is contained in:
parent
ee3b9a56c9
commit
786b85fde2
@ -7,7 +7,7 @@ import {
|
|||||||
ThemeContext,
|
ThemeContext,
|
||||||
getNumberFormat,
|
getNumberFormat,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import dataProvider from './market-depth-provider';
|
import { marketDepthProvider } from './market-depth-provider';
|
||||||
import {
|
import {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@ -115,7 +115,7 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { data, error, loading } = useDataProvider({
|
const { data, error, loading } = useDataProvider({
|
||||||
dataProvider,
|
dataProvider: marketDepthProvider,
|
||||||
update,
|
update,
|
||||||
variables,
|
variables,
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export * from './__generated___/MarketDepth';
|
export * from './__generated___/MarketDepth';
|
||||||
export * from './depth-chart';
|
export * from './depth-chart';
|
||||||
export * from './market-depth-provider';
|
export { marketDepthProvider } from './market-depth-provider';
|
||||||
export * from './orderbook-container';
|
export * from './orderbook-container';
|
||||||
export * from './orderbook-data';
|
export * from './orderbook-data';
|
||||||
export * from './orderbook-manager';
|
export * from './orderbook-manager';
|
||||||
|
76
libs/market-depth/src/lib/market-depth-provider.spec.ts
Normal file
76
libs/market-depth/src/lib/market-depth-provider.spec.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { update } from './market-depth-provider';
|
||||||
|
import { captureException } from '@sentry/react';
|
||||||
|
|
||||||
|
const reload = jest.fn();
|
||||||
|
jest.mock('@sentry/react', () => {
|
||||||
|
const original = jest.requireActual('@sentry/react'); // Step 2.
|
||||||
|
return {
|
||||||
|
...original,
|
||||||
|
captureException: jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('./orderbook-data', () => ({
|
||||||
|
updateLevels: jest.fn((arg) => arg),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('market depth provider update', () => {
|
||||||
|
it('omits overlapping updates', () => {
|
||||||
|
const data = {
|
||||||
|
id: '1',
|
||||||
|
depth: {
|
||||||
|
sequenceNumber: '1',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const delta = {
|
||||||
|
marketId: '2',
|
||||||
|
sequenceNumber: '',
|
||||||
|
previousSequenceNumber: '',
|
||||||
|
};
|
||||||
|
const updatedData = update(data, [delta], reload);
|
||||||
|
expect(updatedData).toBe(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('omits not matching market', () => {
|
||||||
|
const data = {
|
||||||
|
id: '1',
|
||||||
|
depth: {
|
||||||
|
sequenceNumber: '10',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const delta = [
|
||||||
|
{
|
||||||
|
marketId: '1',
|
||||||
|
sequenceNumber: '5',
|
||||||
|
previousSequenceNumber: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
marketId: '1',
|
||||||
|
sequenceNumber: '10',
|
||||||
|
previousSequenceNumber: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
expect(update(data, delta.slice(0, 1), reload)).toBe(data);
|
||||||
|
expect(update(data, delta.slice(1, 2), reload)).toBe(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('restarts and captureException when there is gap in updates', () => {
|
||||||
|
const data = {
|
||||||
|
id: '1',
|
||||||
|
depth: {
|
||||||
|
sequenceNumber: '10',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const delta = [
|
||||||
|
{
|
||||||
|
marketId: '1',
|
||||||
|
sequenceNumber: '16',
|
||||||
|
previousSequenceNumber: '12',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const updatedData = update(data, delta, reload);
|
||||||
|
expect(updatedData).toBe(data);
|
||||||
|
expect(reload).toBeCalled();
|
||||||
|
expect(captureException).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
@ -12,40 +12,34 @@ import type {
|
|||||||
MarketDepthUpdateSubscription,
|
MarketDepthUpdateSubscription,
|
||||||
} from './__generated___/MarketDepth';
|
} from './__generated___/MarketDepth';
|
||||||
|
|
||||||
const sequenceNumbers: Record<string, number> = {};
|
export const update: Update<
|
||||||
|
|
||||||
const update: Update<
|
|
||||||
ReturnType<typeof getData>,
|
ReturnType<typeof getData>,
|
||||||
ReturnType<typeof getDelta>
|
ReturnType<typeof getDelta>
|
||||||
> = (data, deltas, reload) => {
|
> = (data, deltas, reload) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return data;
|
||||||
}
|
}
|
||||||
for (const delta of deltas) {
|
for (const delta of deltas) {
|
||||||
if (delta.marketId !== data.id) {
|
if (delta.marketId !== data.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const currentSequenceNumber = Number(delta.sequenceNumber);
|
if (Number(delta.sequenceNumber) <= Number(data.depth.sequenceNumber)) {
|
||||||
if (currentSequenceNumber <= sequenceNumbers[delta.marketId]) {
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
if (
|
if (delta.previousSequenceNumber !== data.depth.sequenceNumber) {
|
||||||
delta.previousSequenceNumber !==
|
|
||||||
sequenceNumbers[delta.marketId].toString()
|
|
||||||
) {
|
|
||||||
captureException(
|
captureException(
|
||||||
new Error(
|
new Error(
|
||||||
`Sequence number gap in marketsDepthUpdate for {data.id}, {sequenceNumbers[delta.marketId]} - {delta.previousSequenceNumber}`
|
`Sequence number gap in marketsDepthUpdate for {data.id}, {sequenceNumbers[delta.marketId]} - {delta.previousSequenceNumber}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
delete sequenceNumbers[delta.marketId];
|
|
||||||
reload();
|
reload();
|
||||||
return;
|
return data;
|
||||||
}
|
}
|
||||||
sequenceNumbers[delta.marketId] = Number(currentSequenceNumber);
|
|
||||||
const updatedData = {
|
const updatedData = {
|
||||||
...data,
|
...data,
|
||||||
depth: { ...data.depth },
|
depth: {
|
||||||
|
...data.depth,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if (delta.buy) {
|
if (delta.buy) {
|
||||||
updatedData.depth.buy = updateLevels(data.depth.buy ?? [], delta.buy);
|
updatedData.depth.buy = updateLevels(data.depth.buy ?? [], delta.buy);
|
||||||
@ -53,19 +47,14 @@ const update: Update<
|
|||||||
if (delta.sell) {
|
if (delta.sell) {
|
||||||
updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell);
|
updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell);
|
||||||
}
|
}
|
||||||
|
updatedData.depth.sequenceNumber = delta.sequenceNumber;
|
||||||
return updatedData;
|
return updatedData;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (responseData: MarketDepthQuery) => {
|
const getData = (responseData: MarketDepthQuery) => responseData.market;
|
||||||
if (responseData.market?.id) {
|
|
||||||
sequenceNumbers[responseData.market.id] = Number(
|
|
||||||
responseData.market.depth.sequenceNumber
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return responseData.market;
|
|
||||||
};
|
|
||||||
const getDelta = (subscriptionData: MarketDepthUpdateSubscription) =>
|
const getDelta = (subscriptionData: MarketDepthUpdateSubscription) =>
|
||||||
subscriptionData.marketsDepthUpdate;
|
subscriptionData.marketsDepthUpdate;
|
||||||
|
|
||||||
@ -76,5 +65,3 @@ export const marketDepthProvider = makeDataProvider({
|
|||||||
getData,
|
getData,
|
||||||
getDelta,
|
getDelta,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default marketDepthProvider;
|
|
||||||
|
@ -2,7 +2,7 @@ import throttle from 'lodash/throttle';
|
|||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Orderbook } from './orderbook';
|
import { Orderbook } from './orderbook';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import marketDepthProvider from './market-depth-provider';
|
import { marketDepthProvider } from './market-depth-provider';
|
||||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
||||||
import type { MarketData } from '@vegaprotocol/market-list';
|
import type { MarketData } from '@vegaprotocol/market-list';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import throttle from 'lodash/throttle';
|
import throttle from 'lodash/throttle';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import dataProvider from './market-depth-provider';
|
import { marketDepthProvider } from './market-depth-provider';
|
||||||
import type { MarketDepthQuery } from './__generated___/MarketDepth';
|
import type { MarketDepthQuery } from './__generated___/MarketDepth';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -39,7 +39,7 @@ export const useOrderBookData = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { data, error, loading } = useDataProvider({
|
const { data, error, loading } = useDataProvider({
|
||||||
dataProvider,
|
dataProvider: marketDepthProvider,
|
||||||
update,
|
update,
|
||||||
variables,
|
variables,
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user