hive-stream 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCUMENTATION.md +50 -2
- package/README.md +44 -3
- package/dist/adapters/base.adapter.d.ts +5 -0
- package/dist/adapters/base.adapter.js +9 -0
- package/dist/adapters/base.adapter.js.map +1 -1
- package/dist/adapters/mongodb.adapter.d.ts +6 -6
- package/dist/adapters/mongodb.adapter.js +36 -21
- package/dist/adapters/mongodb.adapter.js.map +1 -1
- package/dist/adapters/postgresql.adapter.d.ts +7 -0
- package/dist/adapters/postgresql.adapter.js +46 -19
- package/dist/adapters/postgresql.adapter.js.map +1 -1
- package/dist/adapters/sqlite.adapter.d.ts +4 -0
- package/dist/adapters/sqlite.adapter.js +10 -0
- package/dist/adapters/sqlite.adapter.js.map +1 -1
- package/dist/api.d.ts +13 -3
- package/dist/api.js +96 -62
- package/dist/api.js.map +1 -1
- package/dist/config.d.ts +7 -1
- package/dist/config.js +7 -1
- package/dist/config.js.map +1 -1
- package/dist/contracts/auctionhouse.contract.d.ts +4 -0
- package/dist/contracts/auctionhouse.contract.js +234 -0
- package/dist/contracts/auctionhouse.contract.js.map +1 -0
- package/dist/contracts/booking.contract.d.ts +4 -0
- package/dist/contracts/booking.contract.js +225 -0
- package/dist/contracts/booking.contract.js.map +1 -0
- package/dist/contracts/bountyboard.contract.d.ts +4 -0
- package/dist/contracts/bountyboard.contract.js +233 -0
- package/dist/contracts/bountyboard.contract.js.map +1 -0
- package/dist/contracts/bundlemarketplace.contract.d.ts +4 -0
- package/dist/contracts/bundlemarketplace.contract.js +195 -0
- package/dist/contracts/bundlemarketplace.contract.js.map +1 -0
- package/dist/contracts/charitymatch.contract.d.ts +4 -0
- package/dist/contracts/charitymatch.contract.js +172 -0
- package/dist/contracts/charitymatch.contract.js.map +1 -0
- package/dist/contracts/coinflip.contract.js +7 -1
- package/dist/contracts/coinflip.contract.js.map +1 -1
- package/dist/contracts/crowdfund.contract.d.ts +4 -0
- package/dist/contracts/crowdfund.contract.js +290 -0
- package/dist/contracts/crowdfund.contract.js.map +1 -0
- package/dist/contracts/dcabot.contract.d.ts +4 -0
- package/dist/contracts/dcabot.contract.js +217 -0
- package/dist/contracts/dcabot.contract.js.map +1 -0
- package/dist/contracts/dice.contract.js +7 -1
- package/dist/contracts/dice.contract.js.map +1 -1
- package/dist/contracts/domainregistry.contract.d.ts +4 -0
- package/dist/contracts/domainregistry.contract.js +232 -0
- package/dist/contracts/domainregistry.contract.js.map +1 -0
- package/dist/contracts/exchange.contract.js +209 -168
- package/dist/contracts/exchange.contract.js.map +1 -1
- package/dist/contracts/fanclub.contract.d.ts +4 -0
- package/dist/contracts/fanclub.contract.js +193 -0
- package/dist/contracts/fanclub.contract.js.map +1 -0
- package/dist/contracts/giftcard.contract.d.ts +4 -0
- package/dist/contracts/giftcard.contract.js +158 -0
- package/dist/contracts/giftcard.contract.js.map +1 -0
- package/dist/contracts/grantrounds.contract.d.ts +4 -0
- package/dist/contracts/grantrounds.contract.js +265 -0
- package/dist/contracts/grantrounds.contract.js.map +1 -0
- package/dist/contracts/groupbuy.contract.d.ts +4 -0
- package/dist/contracts/groupbuy.contract.js +198 -0
- package/dist/contracts/groupbuy.contract.js.map +1 -0
- package/dist/contracts/helpers.d.ts +64 -0
- package/dist/contracts/helpers.js +159 -0
- package/dist/contracts/helpers.js.map +1 -0
- package/dist/contracts/insurancepool.contract.d.ts +4 -0
- package/dist/contracts/insurancepool.contract.js +281 -0
- package/dist/contracts/insurancepool.contract.js.map +1 -0
- package/dist/contracts/invoice.contract.d.ts +4 -0
- package/dist/contracts/invoice.contract.js +193 -0
- package/dist/contracts/invoice.contract.js.map +1 -0
- package/dist/contracts/launchpad.contract.d.ts +4 -0
- package/dist/contracts/launchpad.contract.js +225 -0
- package/dist/contracts/launchpad.contract.js.map +1 -0
- package/dist/contracts/lotto.contract.js +53 -37
- package/dist/contracts/lotto.contract.js.map +1 -1
- package/dist/contracts/multisigtreasury.contract.d.ts +4 -0
- package/dist/contracts/multisigtreasury.contract.js +245 -0
- package/dist/contracts/multisigtreasury.contract.js.map +1 -0
- package/dist/contracts/nft.contract.d.ts +1 -0
- package/dist/contracts/nft.contract.js +236 -192
- package/dist/contracts/nft.contract.js.map +1 -1
- package/dist/contracts/oraclebounty.contract.d.ts +4 -0
- package/dist/contracts/oraclebounty.contract.js +250 -0
- package/dist/contracts/oraclebounty.contract.js.map +1 -0
- package/dist/contracts/payroll.contract.d.ts +4 -0
- package/dist/contracts/payroll.contract.js +232 -0
- package/dist/contracts/payroll.contract.js.map +1 -0
- package/dist/contracts/paywall.contract.d.ts +4 -0
- package/dist/contracts/paywall.contract.js +185 -0
- package/dist/contracts/paywall.contract.js.map +1 -0
- package/dist/contracts/poll.contract.js +2 -0
- package/dist/contracts/poll.contract.js.map +1 -1
- package/dist/contracts/predictionmarket.contract.d.ts +4 -0
- package/dist/contracts/predictionmarket.contract.js +213 -0
- package/dist/contracts/predictionmarket.contract.js.map +1 -0
- package/dist/contracts/proposaltimelock.contract.d.ts +4 -0
- package/dist/contracts/proposaltimelock.contract.js +250 -0
- package/dist/contracts/proposaltimelock.contract.js.map +1 -0
- package/dist/contracts/questpass.contract.d.ts +4 -0
- package/dist/contracts/questpass.contract.js +214 -0
- package/dist/contracts/questpass.contract.js.map +1 -0
- package/dist/contracts/referral.contract.d.ts +4 -0
- package/dist/contracts/referral.contract.js +238 -0
- package/dist/contracts/referral.contract.js.map +1 -0
- package/dist/contracts/rental.contract.d.ts +4 -0
- package/dist/contracts/rental.contract.js +221 -0
- package/dist/contracts/rental.contract.js.map +1 -0
- package/dist/contracts/revenuesplit.contract.d.ts +4 -0
- package/dist/contracts/revenuesplit.contract.js +211 -0
- package/dist/contracts/revenuesplit.contract.js.map +1 -0
- package/dist/contracts/rps.contract.js +17 -1
- package/dist/contracts/rps.contract.js.map +1 -1
- package/dist/contracts/savings.contract.d.ts +4 -0
- package/dist/contracts/savings.contract.js +208 -0
- package/dist/contracts/savings.contract.js.map +1 -0
- package/dist/contracts/subscription.contract.d.ts +4 -0
- package/dist/contracts/subscription.contract.js +241 -0
- package/dist/contracts/subscription.contract.js.map +1 -0
- package/dist/contracts/sweepstakes.contract.d.ts +4 -0
- package/dist/contracts/sweepstakes.contract.js +209 -0
- package/dist/contracts/sweepstakes.contract.js.map +1 -0
- package/dist/contracts/ticketing.contract.d.ts +4 -0
- package/dist/contracts/ticketing.contract.js +185 -0
- package/dist/contracts/ticketing.contract.js.map +1 -0
- package/dist/contracts/tipjar.contract.js +2 -0
- package/dist/contracts/tipjar.contract.js.map +1 -1
- package/dist/contracts/token.contract.js +135 -125
- package/dist/contracts/token.contract.js.map +1 -1
- package/dist/index.d.ts +39 -0
- package/dist/index.js +71 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata.d.ts +7 -0
- package/dist/metadata.js +64 -1
- package/dist/metadata.js.map +1 -1
- package/dist/providers/block-provider.d.ts +22 -0
- package/dist/providers/block-provider.js +3 -0
- package/dist/providers/block-provider.js.map +1 -0
- package/dist/providers/haf-client.d.ts +30 -0
- package/dist/providers/haf-client.js +119 -0
- package/dist/providers/haf-client.js.map +1 -0
- package/dist/providers/haf-provider.d.ts +49 -0
- package/dist/providers/haf-provider.js +256 -0
- package/dist/providers/haf-provider.js.map +1 -0
- package/dist/providers/hive-provider.d.ts +13 -0
- package/dist/providers/hive-provider.js +25 -0
- package/dist/providers/hive-provider.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.js +21 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/streamer.d.ts +21 -1
- package/dist/streamer.js +187 -62
- package/dist/streamer.js.map +1 -1
- package/dist/utils.js +11 -2
- package/dist/utils.js.map +1 -1
- package/package.json +16 -1
- package/.claude/settings.local.json +0 -12
- package/.env.example +0 -3
- package/.travis.yml +0 -11
- package/AGENTS.md +0 -35
- package/CLAUDE.md +0 -75
- package/ecosystem.config.js +0 -17
- package/examples/contracts/README.md +0 -8
- package/examples/contracts/exchange.ts +0 -38
- package/examples/contracts/poll.ts +0 -21
- package/examples/contracts/rps.ts +0 -19
- package/examples/contracts/tipjar.ts +0 -19
- package/jest.config.js +0 -9
- package/test-contract-block.md +0 -19
- package/tests/actions.spec.ts +0 -252
- package/tests/adapters/actions-persistence.spec.ts +0 -144
- package/tests/adapters/postgresql.adapter.spec.ts +0 -127
- package/tests/adapters/sqlite.adapter.spec.ts +0 -181
- package/tests/config-input.spec.ts +0 -90
- package/tests/contracts/coinflip.contract.spec.ts +0 -94
- package/tests/contracts/dice.contract.spec.ts +0 -87
- package/tests/contracts/entrants.json +0 -729
- package/tests/contracts/exchange.contract.spec.ts +0 -84
- package/tests/contracts/lotto.contract.spec.ts +0 -59
- package/tests/contracts/nft.contract.spec.ts +0 -948
- package/tests/contracts/token.contract.spec.ts +0 -90
- package/tests/exchanges/coingecko.exchange.spec.ts +0 -169
- package/tests/exchanges/exchange.base.spec.ts +0 -246
- package/tests/helpers/mock-adapter.ts +0 -214
- package/tests/helpers/mock-fetch.ts +0 -165
- package/tests/hive-chain-features.spec.ts +0 -319
- package/tests/hive-rates.spec.ts +0 -443
- package/tests/integration/hive-rates.integration.spec.ts +0 -35
- package/tests/metadata.spec.ts +0 -63
- package/tests/setup.ts +0 -30
- package/tests/streamer-actions.spec.ts +0 -274
- package/tests/streamer.spec.ts +0 -342
- package/tests/types/rates.spec.ts +0 -216
- package/tests/utils.spec.ts +0 -113
- package/tsconfig.build.json +0 -4
- package/tslint.json +0 -21
- package/wallaby.js +0 -26
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import { TimeAction } from '../src/actions';
|
|
2
|
-
import { Streamer } from '../src/streamer';
|
|
3
|
-
import { action, defineContract } from '../src/contracts/contract';
|
|
4
|
-
|
|
5
|
-
describe('Streamer Time-based Actions', () => {
|
|
6
|
-
let streamer: Streamer;
|
|
7
|
-
let mockAdapter: any;
|
|
8
|
-
let mockContract: any;
|
|
9
|
-
let testHandler: jest.Mock;
|
|
10
|
-
let asyncTestHandler: jest.Mock;
|
|
11
|
-
|
|
12
|
-
beforeEach(async () => {
|
|
13
|
-
mockAdapter = {
|
|
14
|
-
create: jest.fn().mockResolvedValue(true),
|
|
15
|
-
destroy: jest.fn().mockResolvedValue(true),
|
|
16
|
-
loadActions: jest.fn().mockResolvedValue([]),
|
|
17
|
-
loadState: jest.fn().mockResolvedValue({ lastBlockNumber: 0, actions: [] }),
|
|
18
|
-
saveState: jest.fn().mockResolvedValue(true),
|
|
19
|
-
processBlock: jest.fn().mockResolvedValue(true),
|
|
20
|
-
processOperation: jest.fn().mockResolvedValue(true),
|
|
21
|
-
processTransfer: jest.fn().mockResolvedValue(true),
|
|
22
|
-
processCustomJson: jest.fn().mockResolvedValue(true),
|
|
23
|
-
find: jest.fn().mockResolvedValue([]),
|
|
24
|
-
findOne: jest.fn().mockResolvedValue(null),
|
|
25
|
-
insert: jest.fn().mockResolvedValue(true),
|
|
26
|
-
replace: jest.fn().mockResolvedValue(true)
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
testHandler = jest.fn();
|
|
30
|
-
asyncTestHandler = jest.fn().mockResolvedValue(true);
|
|
31
|
-
|
|
32
|
-
mockContract = defineContract({
|
|
33
|
-
name: 'testcontract',
|
|
34
|
-
hooks: {
|
|
35
|
-
create: jest.fn(),
|
|
36
|
-
destroy: jest.fn()
|
|
37
|
-
},
|
|
38
|
-
actions: {
|
|
39
|
-
testMethod: action(testHandler, { trigger: 'time' }),
|
|
40
|
-
asyncTestMethod: action(asyncTestHandler, { trigger: 'time' })
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
streamer = new Streamer({
|
|
45
|
-
JSON_ID: 'testing',
|
|
46
|
-
DEBUG_MODE: false
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
await streamer.registerAdapter(mockAdapter);
|
|
50
|
-
await streamer.registerContract(mockContract);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
afterEach(async () => {
|
|
54
|
-
await streamer.stop();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
describe('Action Registration', () => {
|
|
58
|
-
test('Should register a new action successfully', async () => {
|
|
59
|
-
const action = new TimeAction('1m', 'test-action', 'testcontract', 'testMethod');
|
|
60
|
-
|
|
61
|
-
await streamer.registerAction(action);
|
|
62
|
-
|
|
63
|
-
const actions = streamer.getActions();
|
|
64
|
-
expect(actions).toHaveLength(1);
|
|
65
|
-
expect(actions[0].id).toBe('test-action');
|
|
66
|
-
expect(mockAdapter.saveState).toHaveBeenCalled();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test('Should not register duplicate action IDs', async () => {
|
|
70
|
-
const action1 = new TimeAction('1m', 'test-action', 'testcontract', 'testMethod');
|
|
71
|
-
const action2 = new TimeAction('5m', 'test-action', 'testcontract', 'testMethod');
|
|
72
|
-
|
|
73
|
-
await streamer.registerAction(action1);
|
|
74
|
-
await streamer.registerAction(action2);
|
|
75
|
-
|
|
76
|
-
const actions = streamer.getActions();
|
|
77
|
-
expect(actions).toHaveLength(1);
|
|
78
|
-
expect(actions[0].timeValue).toBe('1m'); // First one should remain
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('Should throw error when registering action for non-existent contract', async () => {
|
|
82
|
-
const action = new TimeAction('1m', 'test-action', 'nonexistent', 'testMethod');
|
|
83
|
-
|
|
84
|
-
await expect(streamer.registerAction(action)).rejects.toThrow(
|
|
85
|
-
'Contract \'nonexistent\' not found for action \'test-action\''
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test('Should throw error when registering action for non-existent action', async () => {
|
|
90
|
-
const action = new TimeAction('1m', 'test-action', 'testcontract', 'nonexistentMethod');
|
|
91
|
-
|
|
92
|
-
await expect(streamer.registerAction(action)).rejects.toThrow(
|
|
93
|
-
'Action \'nonexistentMethod\' not found in contract \'testcontract\' for action \'test-action\''
|
|
94
|
-
);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
describe('Action Management', () => {
|
|
99
|
-
beforeEach(async () => {
|
|
100
|
-
const action1 = new TimeAction('1m', 'action1', 'testcontract', 'testMethod');
|
|
101
|
-
const action2 = new TimeAction('5m', 'action2', 'testcontract', 'testMethod');
|
|
102
|
-
await streamer.registerAction(action1);
|
|
103
|
-
await streamer.registerAction(action2);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('Should remove action by ID', async () => {
|
|
107
|
-
const result = await streamer.removeAction('action1');
|
|
108
|
-
|
|
109
|
-
expect(result).toBe(true);
|
|
110
|
-
expect(streamer.getActions()).toHaveLength(1);
|
|
111
|
-
expect(streamer.getAction('action1')).toBeUndefined();
|
|
112
|
-
expect(mockAdapter.saveState).toHaveBeenCalled();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('Should return false when removing non-existent action', async () => {
|
|
116
|
-
const result = await streamer.removeAction('nonexistent');
|
|
117
|
-
|
|
118
|
-
expect(result).toBe(false);
|
|
119
|
-
expect(streamer.getActions()).toHaveLength(2);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test('Should get action by ID', () => {
|
|
123
|
-
const action = streamer.getAction('action1');
|
|
124
|
-
|
|
125
|
-
expect(action).toBeDefined();
|
|
126
|
-
expect(action?.id).toBe('action1');
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test('Should return undefined for non-existent action', () => {
|
|
130
|
-
const action = streamer.getAction('nonexistent');
|
|
131
|
-
|
|
132
|
-
expect(action).toBeUndefined();
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test('Should enable and disable actions', async () => {
|
|
136
|
-
const action = streamer.getAction('action1');
|
|
137
|
-
expect(action?.enabled).toBe(true);
|
|
138
|
-
|
|
139
|
-
const result1 = await streamer.setActionEnabled('action1', false);
|
|
140
|
-
expect(result1).toBe(true);
|
|
141
|
-
expect(action?.enabled).toBe(false);
|
|
142
|
-
|
|
143
|
-
const result2 = await streamer.setActionEnabled('action1', true);
|
|
144
|
-
expect(result2).toBe(true);
|
|
145
|
-
expect(action?.enabled).toBe(true);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test('Should reset action date', async () => {
|
|
149
|
-
const action = streamer.getAction('action1');
|
|
150
|
-
const originalDate = action?.date;
|
|
151
|
-
|
|
152
|
-
// Wait a bit to ensure time difference
|
|
153
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
154
|
-
|
|
155
|
-
const result = await streamer.resetAction('action1');
|
|
156
|
-
|
|
157
|
-
expect(result).toBe(true);
|
|
158
|
-
expect(action?.date.getTime()).toBeGreaterThan(originalDate?.getTime() || 0);
|
|
159
|
-
expect(mockAdapter.saveState).toHaveBeenCalled();
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe('Action Execution', () => {
|
|
164
|
-
let testAction: TimeAction;
|
|
165
|
-
|
|
166
|
-
beforeEach(async () => {
|
|
167
|
-
testAction = new TimeAction('1m', 'test-action', 'testcontract', 'testMethod', { testData: 'value' });
|
|
168
|
-
await streamer.registerAction(testAction);
|
|
169
|
-
|
|
170
|
-
// Mock the blockchain time to be in the future to trigger execution
|
|
171
|
-
streamer['latestBlockchainTime'] = new Date(Date.now() + 120000); // 2 minutes in future
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
test('Should execute action when time threshold is met', async () => {
|
|
175
|
-
// Set action date to past to trigger execution
|
|
176
|
-
testAction.date = new Date(Date.now() - 120000); // 2 minutes ago
|
|
177
|
-
|
|
178
|
-
await streamer['processActions']();
|
|
179
|
-
|
|
180
|
-
expect(testHandler).toHaveBeenCalledWith({ testData: 'value' }, expect.any(Object));
|
|
181
|
-
expect(testAction.executionCount).toBe(1);
|
|
182
|
-
expect(testAction.lastExecution).toBeInstanceOf(Date);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
test('Should not execute action when time threshold is not met', async () => {
|
|
186
|
-
// Reset the action date to be very recent to ensure it doesn't execute
|
|
187
|
-
testAction.date = new Date(Date.now() - 10000); // Only 10 seconds ago (less than 1 minute)
|
|
188
|
-
|
|
189
|
-
// Also ensure blockchain time is current, not in the future
|
|
190
|
-
streamer['latestBlockchainTime'] = new Date();
|
|
191
|
-
|
|
192
|
-
await streamer['processActions']();
|
|
193
|
-
|
|
194
|
-
expect(testHandler).not.toHaveBeenCalled();
|
|
195
|
-
expect(testAction.executionCount).toBe(0);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
test('Should not execute disabled actions', async () => {
|
|
199
|
-
testAction.date = new Date(Date.now() - 120000); // 2 minutes ago
|
|
200
|
-
testAction.disable();
|
|
201
|
-
|
|
202
|
-
await streamer['processActions']();
|
|
203
|
-
|
|
204
|
-
expect(testHandler).not.toHaveBeenCalled();
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test('Should not execute actions that have reached max executions', async () => {
|
|
208
|
-
testAction.date = new Date(Date.now() - 120000); // 2 minutes ago
|
|
209
|
-
testAction.maxExecutions = 1;
|
|
210
|
-
testAction.executionCount = 1;
|
|
211
|
-
|
|
212
|
-
await streamer['processActions']();
|
|
213
|
-
|
|
214
|
-
expect(testHandler).not.toHaveBeenCalled();
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
test('Should handle contract method errors gracefully', async () => {
|
|
218
|
-
testHandler.mockImplementation(() => {
|
|
219
|
-
throw new Error('Contract method error');
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
testAction.date = new Date(Date.now() - 120000); // 2 minutes ago
|
|
223
|
-
|
|
224
|
-
// Should not throw, but log error
|
|
225
|
-
await expect(streamer['processActions']()).resolves.toBeUndefined();
|
|
226
|
-
|
|
227
|
-
expect(testHandler).toHaveBeenCalled();
|
|
228
|
-
// Action should not increment execution count on error
|
|
229
|
-
expect(testAction.executionCount).toBe(0);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
test('Should clean up completed actions', async () => {
|
|
233
|
-
testAction.maxExecutions = 1;
|
|
234
|
-
testAction.date = new Date(Date.now() - 120000); // 2 minutes ago
|
|
235
|
-
|
|
236
|
-
await streamer['processActions']();
|
|
237
|
-
|
|
238
|
-
expect(testHandler).toHaveBeenCalled();
|
|
239
|
-
expect(streamer.getActions()).toHaveLength(0); // Action should be removed
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
describe('Action Frequencies', () => {
|
|
244
|
-
const testCases = [
|
|
245
|
-
{ timeValue: '3s', expectedSeconds: 3 },
|
|
246
|
-
{ timeValue: '30s', expectedSeconds: 30 },
|
|
247
|
-
{ timeValue: '1m', expectedSeconds: 60 },
|
|
248
|
-
{ timeValue: 'minute', expectedSeconds: 60 },
|
|
249
|
-
{ timeValue: '15m', expectedSeconds: 900 },
|
|
250
|
-
{ timeValue: '1h', expectedSeconds: 3600 },
|
|
251
|
-
{ timeValue: 'hourly', expectedSeconds: 3600 },
|
|
252
|
-
{ timeValue: '24h', expectedSeconds: 86400 },
|
|
253
|
-
{ timeValue: 'daily', expectedSeconds: 86400 },
|
|
254
|
-
{ timeValue: 'week', expectedSeconds: 604800 }
|
|
255
|
-
];
|
|
256
|
-
|
|
257
|
-
testCases.forEach(({ timeValue, expectedSeconds }) => {
|
|
258
|
-
test(`Should execute ${timeValue} action after ${expectedSeconds} seconds`, async () => {
|
|
259
|
-
const action = new TimeAction(timeValue, `test-${timeValue}`, 'testcontract', 'testMethod');
|
|
260
|
-
action.date = new Date(Date.now() - (expectedSeconds * 1000 + 1000)); // Past the threshold
|
|
261
|
-
|
|
262
|
-
await streamer.registerAction(action);
|
|
263
|
-
|
|
264
|
-
// Mock blockchain time
|
|
265
|
-
streamer['latestBlockchainTime'] = new Date();
|
|
266
|
-
|
|
267
|
-
await streamer['processActions']();
|
|
268
|
-
|
|
269
|
-
expect(testHandler).toHaveBeenCalled();
|
|
270
|
-
expect(action.executionCount).toBe(1);
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
});
|
package/tests/streamer.spec.ts
DELETED
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
import { TimeAction } from '../src/actions';
|
|
2
|
-
import { Streamer } from '../src/streamer';
|
|
3
|
-
import { action as contractAction, defineContract } from '../src/contracts/contract';
|
|
4
|
-
import { createMockAdapter } from './helpers/mock-adapter';
|
|
5
|
-
|
|
6
|
-
describe('Streamer', () => {
|
|
7
|
-
let sut: Streamer;
|
|
8
|
-
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
sut = new Streamer({
|
|
11
|
-
JSON_ID: 'testing'
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
await sut.registerAdapter(createMockAdapter());
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
afterEach(async () => {
|
|
18
|
-
await sut.stop();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe('Adapters', () => {
|
|
22
|
-
test('Registers adapter and calls the create lifecycle method', async () => {
|
|
23
|
-
const adapter = {
|
|
24
|
-
create: jest.fn().mockResolvedValue(true),
|
|
25
|
-
destroy: jest.fn(),
|
|
26
|
-
loadActions: jest.fn().mockResolvedValue([]),
|
|
27
|
-
loadState: jest.fn().mockResolvedValue(null),
|
|
28
|
-
saveState: jest.fn().mockResolvedValue(true),
|
|
29
|
-
processBlock: jest.fn(),
|
|
30
|
-
processOperation: jest.fn(),
|
|
31
|
-
processTransfer: jest.fn(),
|
|
32
|
-
processCustomJson: jest.fn(),
|
|
33
|
-
find: jest.fn(),
|
|
34
|
-
findOne: jest.fn(),
|
|
35
|
-
insert: jest.fn(),
|
|
36
|
-
replace: jest.fn(),
|
|
37
|
-
addEvent: jest.fn(),
|
|
38
|
-
client: null,
|
|
39
|
-
db: null
|
|
40
|
-
} as any;
|
|
41
|
-
|
|
42
|
-
await sut.registerAdapter(adapter);
|
|
43
|
-
|
|
44
|
-
expect(adapter.create).toHaveBeenCalled();
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
describe('Actions', () => {
|
|
49
|
-
test('Registers a new action', async () => {
|
|
50
|
-
const mockContract = defineContract({
|
|
51
|
-
name: 'testcontract',
|
|
52
|
-
actions: {
|
|
53
|
-
testmethod: contractAction(jest.fn(), { trigger: 'time' })
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
await sut.registerContract(mockContract);
|
|
58
|
-
|
|
59
|
-
const adapter = {
|
|
60
|
-
create: jest.fn().mockResolvedValue(true),
|
|
61
|
-
destroy: jest.fn(),
|
|
62
|
-
loadActions: jest.fn().mockResolvedValue([]),
|
|
63
|
-
loadState: jest.fn().mockResolvedValue(null),
|
|
64
|
-
saveState: jest.fn().mockResolvedValue(true),
|
|
65
|
-
processBlock: jest.fn(),
|
|
66
|
-
processOperation: jest.fn(),
|
|
67
|
-
processTransfer: jest.fn(),
|
|
68
|
-
processCustomJson: jest.fn(),
|
|
69
|
-
find: jest.fn(),
|
|
70
|
-
findOne: jest.fn(),
|
|
71
|
-
insert: jest.fn(),
|
|
72
|
-
replace: jest.fn(),
|
|
73
|
-
client: null,
|
|
74
|
-
db: null
|
|
75
|
-
} as any;
|
|
76
|
-
|
|
77
|
-
await sut.registerAdapter(adapter);
|
|
78
|
-
|
|
79
|
-
const action = new TimeAction('1m', 'testoneminute', 'testcontract', 'testmethod');
|
|
80
|
-
|
|
81
|
-
await sut.registerAction(action);
|
|
82
|
-
|
|
83
|
-
const foundAction = sut['actions'].find(a => a.id === 'testoneminute');
|
|
84
|
-
|
|
85
|
-
expect(foundAction).not.toBeUndefined();
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test('Does not allow duplicate actions of the same id', async () => {
|
|
89
|
-
const mockContract = defineContract({
|
|
90
|
-
name: 'testcontract',
|
|
91
|
-
actions: {
|
|
92
|
-
testmethod: contractAction(jest.fn(), { trigger: 'time' })
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
await sut.registerContract(mockContract);
|
|
97
|
-
|
|
98
|
-
const adapter = {
|
|
99
|
-
create: jest.fn().mockResolvedValue(true),
|
|
100
|
-
destroy: jest.fn(),
|
|
101
|
-
loadActions: jest.fn().mockResolvedValue([]),
|
|
102
|
-
loadState: jest.fn().mockResolvedValue(null),
|
|
103
|
-
saveState: jest.fn().mockResolvedValue(true),
|
|
104
|
-
processBlock: jest.fn(),
|
|
105
|
-
processOperation: jest.fn(),
|
|
106
|
-
processTransfer: jest.fn(),
|
|
107
|
-
processCustomJson: jest.fn(),
|
|
108
|
-
find: jest.fn(),
|
|
109
|
-
findOne: jest.fn(),
|
|
110
|
-
insert: jest.fn(),
|
|
111
|
-
replace: jest.fn(),
|
|
112
|
-
client: null,
|
|
113
|
-
db: null
|
|
114
|
-
} as any;
|
|
115
|
-
|
|
116
|
-
await sut.registerAdapter(adapter);
|
|
117
|
-
|
|
118
|
-
const action = new TimeAction('1m', 'testoneminute', 'testcontract', 'testmethod');
|
|
119
|
-
const action2 = new TimeAction('1m', 'testoneminute', 'testcontract', 'testmethod');
|
|
120
|
-
|
|
121
|
-
await sut.registerAction(action);
|
|
122
|
-
await sut.registerAction(action2);
|
|
123
|
-
|
|
124
|
-
expect(sut['actions'].length).toStrictEqual(1);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('Registers actions loaded from adapter loadActions call', async () => {
|
|
128
|
-
const mockContract = defineContract({
|
|
129
|
-
name: 'testcontract',
|
|
130
|
-
actions: {
|
|
131
|
-
testmethod: contractAction(jest.fn(), { trigger: 'time' })
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
await sut.registerContract(mockContract);
|
|
136
|
-
|
|
137
|
-
const adapter = {
|
|
138
|
-
create: jest.fn().mockResolvedValue(true),
|
|
139
|
-
destroy: jest.fn(),
|
|
140
|
-
loadActions: jest.fn().mockResolvedValue([{
|
|
141
|
-
timeValue: '1m',
|
|
142
|
-
id: 'testoneminute',
|
|
143
|
-
contractName: 'testcontract',
|
|
144
|
-
contractAction: 'testmethod',
|
|
145
|
-
payload: {},
|
|
146
|
-
date: new Date().toISOString(),
|
|
147
|
-
enabled: true,
|
|
148
|
-
executionCount: 0
|
|
149
|
-
}]),
|
|
150
|
-
loadState: jest.fn().mockResolvedValue(null),
|
|
151
|
-
saveState: jest.fn().mockResolvedValue(true),
|
|
152
|
-
processBlock: jest.fn(),
|
|
153
|
-
processOperation: jest.fn(),
|
|
154
|
-
processTransfer: jest.fn(),
|
|
155
|
-
processCustomJson: jest.fn(),
|
|
156
|
-
find: jest.fn(),
|
|
157
|
-
findOne: jest.fn(),
|
|
158
|
-
insert: jest.fn(),
|
|
159
|
-
replace: jest.fn(),
|
|
160
|
-
client: null,
|
|
161
|
-
db: null
|
|
162
|
-
} as any;
|
|
163
|
-
|
|
164
|
-
await sut.registerAdapter(adapter);
|
|
165
|
-
|
|
166
|
-
const action = new TimeAction('1h', 'testonehour', 'testcontract', 'testmethod');
|
|
167
|
-
|
|
168
|
-
await sut.registerAction(action);
|
|
169
|
-
|
|
170
|
-
const foundAction = sut['actions'].find(a => a.id === 'testoneminute');
|
|
171
|
-
|
|
172
|
-
expect(foundAction).not.toBeUndefined();
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
describe('Contracts', () => {
|
|
177
|
-
test('Should register a new contract', async () => {
|
|
178
|
-
const contract = defineContract({
|
|
179
|
-
name: 'testcontract',
|
|
180
|
-
actions: {
|
|
181
|
-
myMethod: contractAction(jest.fn())
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
await sut.registerContract(contract);
|
|
186
|
-
|
|
187
|
-
expect(sut['contracts'].length).toStrictEqual(1);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
test('Should register a new contract and call its create hook', async () => {
|
|
191
|
-
const createHook = jest.fn();
|
|
192
|
-
const contract = defineContract({
|
|
193
|
-
name: 'testcontract',
|
|
194
|
-
hooks: {
|
|
195
|
-
create: createHook
|
|
196
|
-
},
|
|
197
|
-
actions: {
|
|
198
|
-
myMethod: contractAction(jest.fn())
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
await sut.registerContract(contract);
|
|
203
|
-
|
|
204
|
-
expect(createHook).toHaveBeenCalled();
|
|
205
|
-
expect(sut['contracts'].length).toStrictEqual(1);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
test('Should unregister a registered contract', async () => {
|
|
209
|
-
const contract = defineContract({
|
|
210
|
-
name: 'testcontract',
|
|
211
|
-
actions: {
|
|
212
|
-
myMethod: contractAction(jest.fn())
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
await sut.registerContract(contract);
|
|
217
|
-
await sut.unregisterContract('testcontract');
|
|
218
|
-
|
|
219
|
-
expect(sut['contracts'].length).toStrictEqual(0);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
test('Should unregister a registered contract and call its destroy hook', async () => {
|
|
223
|
-
const destroyHook = jest.fn();
|
|
224
|
-
const contract = defineContract({
|
|
225
|
-
name: 'testcontract',
|
|
226
|
-
hooks: {
|
|
227
|
-
destroy: destroyHook
|
|
228
|
-
},
|
|
229
|
-
actions: {
|
|
230
|
-
myMethod: contractAction(jest.fn())
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
await sut.registerContract(contract);
|
|
235
|
-
await sut.unregisterContract('testcontract');
|
|
236
|
-
|
|
237
|
-
expect(destroyHook).toHaveBeenCalled();
|
|
238
|
-
expect(sut['contracts'].length).toStrictEqual(0);
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
test('Start method should resume from previous block number', async () => {
|
|
243
|
-
// Override config to not have a preset LAST_BLOCK_NUMBER
|
|
244
|
-
sut.setConfig({ LAST_BLOCK_NUMBER: 0 });
|
|
245
|
-
|
|
246
|
-
const adapter = {
|
|
247
|
-
create: jest.fn().mockResolvedValue(true),
|
|
248
|
-
destroy: jest.fn(),
|
|
249
|
-
loadActions: jest.fn().mockResolvedValue([]),
|
|
250
|
-
loadState: jest.fn().mockResolvedValue({ lastBlockNumber: 509992 }),
|
|
251
|
-
saveState: jest.fn().mockResolvedValue(true),
|
|
252
|
-
processBlock: jest.fn(),
|
|
253
|
-
processOperation: jest.fn(),
|
|
254
|
-
processTransfer: jest.fn(),
|
|
255
|
-
processCustomJson: jest.fn(),
|
|
256
|
-
find: jest.fn(),
|
|
257
|
-
findOne: jest.fn(),
|
|
258
|
-
insert: jest.fn(),
|
|
259
|
-
replace: jest.fn(),
|
|
260
|
-
client: null,
|
|
261
|
-
db: null
|
|
262
|
-
} as any;
|
|
263
|
-
|
|
264
|
-
await sut.registerAdapter(adapter);
|
|
265
|
-
|
|
266
|
-
jest.spyOn(sut as any, 'getBlock').mockImplementation(() => true);
|
|
267
|
-
jest.spyOn(sut as any, 'getLatestBlock').mockImplementation(() => true);
|
|
268
|
-
|
|
269
|
-
await sut.start();
|
|
270
|
-
|
|
271
|
-
expect(sut['lastBlockNumber']).toStrictEqual(509992);
|
|
272
|
-
|
|
273
|
-
sut.stop();
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
test('Start method should respect RESUME_FROM_STATE false', async () => {
|
|
277
|
-
sut.setConfig({ LAST_BLOCK_NUMBER: 123, RESUME_FROM_STATE: false });
|
|
278
|
-
|
|
279
|
-
const adapter = {
|
|
280
|
-
create: jest.fn().mockResolvedValue(true),
|
|
281
|
-
destroy: jest.fn(),
|
|
282
|
-
loadActions: jest.fn().mockResolvedValue([]),
|
|
283
|
-
loadState: jest.fn().mockResolvedValue({ lastBlockNumber: 999 }),
|
|
284
|
-
saveState: jest.fn().mockResolvedValue(true),
|
|
285
|
-
processBlock: jest.fn(),
|
|
286
|
-
processOperation: jest.fn(),
|
|
287
|
-
processTransfer: jest.fn(),
|
|
288
|
-
processCustomJson: jest.fn(),
|
|
289
|
-
find: jest.fn(),
|
|
290
|
-
findOne: jest.fn(),
|
|
291
|
-
insert: jest.fn(),
|
|
292
|
-
replace: jest.fn(),
|
|
293
|
-
client: null,
|
|
294
|
-
db: null
|
|
295
|
-
} as any;
|
|
296
|
-
|
|
297
|
-
await sut.registerAdapter(adapter);
|
|
298
|
-
|
|
299
|
-
jest.spyOn(sut as any, 'getBlock').mockImplementation(() => true);
|
|
300
|
-
jest.spyOn(sut as any, 'getLatestBlock').mockImplementation(() => true);
|
|
301
|
-
|
|
302
|
-
await sut.start();
|
|
303
|
-
|
|
304
|
-
expect(sut['lastBlockNumber']).toStrictEqual(123);
|
|
305
|
-
|
|
306
|
-
sut.stop();
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
test('getBlock should process multiple blocks per batch when behind', async () => {
|
|
310
|
-
const adapter = createMockAdapter();
|
|
311
|
-
await sut.registerAdapter(adapter);
|
|
312
|
-
|
|
313
|
-
sut.setConfig({ CATCH_UP_BATCH_SIZE: 3, BLOCK_CHECK_INTERVAL: 1, DEBUG_MODE: false });
|
|
314
|
-
sut['lastBlockNumber'] = 10;
|
|
315
|
-
|
|
316
|
-
const mockBlock = {
|
|
317
|
-
block_id: 'block-id',
|
|
318
|
-
previous: 'prev-id',
|
|
319
|
-
transaction_ids: ['trx-1'],
|
|
320
|
-
timestamp: '2023-01-01T00:00:00',
|
|
321
|
-
transactions: []
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
sut['client'] = {
|
|
325
|
-
database: {
|
|
326
|
-
getDynamicGlobalProperties: jest.fn().mockResolvedValue({
|
|
327
|
-
head_block_number: 20,
|
|
328
|
-
time: '2023-01-01T00:00:00'
|
|
329
|
-
}),
|
|
330
|
-
getBlock: jest.fn().mockResolvedValue(mockBlock)
|
|
331
|
-
}
|
|
332
|
-
} as any;
|
|
333
|
-
|
|
334
|
-
const loadBlockSpy = jest.spyOn(sut as any, 'loadBlock');
|
|
335
|
-
|
|
336
|
-
await (sut as any).getBlock();
|
|
337
|
-
clearTimeout(sut['blockNumberTimeout']);
|
|
338
|
-
|
|
339
|
-
expect(loadBlockSpy).toHaveBeenCalledTimes(3);
|
|
340
|
-
expect(sut['lastBlockNumber']).toStrictEqual(13);
|
|
341
|
-
});
|
|
342
|
-
});
|