-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unit Tests + BugFixes #15
Conversation
Write index, file, create simple instance, create simple memory store for tests.
@@ -147,7 +152,8 @@ export default class MachinomyServerPlugin extends MiniAccountsPlugin { | |||
accountName, | |||
balance: new BigNumber(0) | |||
}, { | |||
set (obj, prop, val) { | |||
set: (obj, prop, val) => { | |||
obj[prop] = val |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is redundant with the Reflect.set
call. I'm also not familiar enough with Proxy/Reflect to know why this doesn't cause an infinite loop when we set inside of the set handler, but if the tests work then it must not be an issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will change to return true instead of the Reflect.set call -- forgot to update that. Previously, the object property was not set prior to putting the object in the store (thus storing an old object).
I'm not too familiar with proxies either, so I'm not sure why it doesn't cause an infinite loop. In the MDN example linked below, Reflect.set is used within the set handler of the proxy. Yet the interceptions section beneath the example states that Reflect.set triggers the trap as well.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set
src/index.ts
Outdated
@@ -191,7 +197,7 @@ export default class MachinomyServerPlugin extends MiniAccountsPlugin { | |||
if (account.isBlocked) { | |||
throw new Error(`Cannot connect to blocked account ${account.accountName}`) | |||
} | |||
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like there's trailing whitespace here, is lint configured for this repo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handled, thanks. It is -- didn't run the linter before pushing, will do so next time.
src/index.ts
Outdated
@@ -266,20 +271,21 @@ export default class MachinomyServerPlugin extends MiniAccountsPlugin { | |||
account.balance = newBalance | |||
this._log.trace(`account ${account.accountName} debited ${formatAmount(amount, 'eth')}, new balance ${formatAmount(newBalance, 'eth')}`) | |||
|
|||
// Expiry timer for reject | |||
let timer = new Promise(resolve => setTimeout(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure to clear this timer after the Promise.race
@@ -348,7 +354,7 @@ export default class MachinomyServerPlugin extends MiniAccountsPlugin { | |||
|
|||
// isFunding should be toggled after all non-funding related aysnc operations have completed, but before any balance changes occur | |||
if (account.isFunding) { | |||
throw new Trace(`Failed to pay account ${account.accountName}: another funding event was occuring simultaneously.`) | |||
throw new Trace(`another funding event was occuring simultaneously.`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think an in-flight funding transaction should stop packets from being processed. Unless funding has a different meaning here than in the XRP context (adding funds to the channel) it should happen concurrently with traffic on the plugin. An in flight fund should just prevent more fund transactions from being issued until it's done.
test/plugin.test.js
Outdated
const Store = require('./util/memStore') | ||
const BtpPacket = require('btp-packet') | ||
const IlpPacket = require('ilp-packet') | ||
const debug = require('debug')('ilp-plugin-eohereum-asym-server:test') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eohereum -> ethereum
test/plugin.test.js
Outdated
|
||
/* TODO Mock for web3, HDWallet, and Machinomy API. */ | ||
async function createPlugin() { | ||
/* Silence console log output from provider creation. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make an upstream PR to use debug instead of console.log? It's quite strange for a library to use console.log without an option to turn it off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Submitted.
test/plugin.test.js
Outdated
|
||
beforeEach(async () => { | ||
try { | ||
this.plugin = await createPlugin() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure how this works; this
shouldn't be bound to anything in this context because it's an arrow function. I guess it's using the this
of the global scope? Either way, functions in the tests should be changed to function
instead of arrow function syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I did this is because Jest does not share the 'this' context across beforeEach, afterEach, and the test itself (as mocha does).
To get the shared variable access, I either had to use arrow functions with 'this', or define variables as globals (as indicated above). I chose to use 'this' because I thought it would be visually more clear which variables were acting as globals. Can change it to the latter if it you think it is still best to have each test function individually scoped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. I guess I'm just not as familiar with jest. If this is the common way that it's done then that's fine
test/plugin.test.js
Outdated
expect(fee.toNumber()).toBeLessThan(1200000) | ||
})) | ||
} catch (e) { | ||
throw e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
catch(e) { throw e }
seems like a no-op
test/plugin.test.js
Outdated
this.mockAccount.isBlocked = true | ||
try { | ||
await this.plugin._connect(this.mockAccountAddress, {}) | ||
throw Error('Test Error: should trigger catch') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing this, you can do expect(this.plugin._connect(this.mockAccountAddress, {})).to.be.rejectedWith('...')
test/plugin.test.js
Outdated
jest.runOnlyPendingTimers() | ||
await protocolDataResponse | ||
expect(oldBalance).toEqual(this.mockAccount.balance - this.mockIlpPrepare.amount) | ||
} catch (e) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are errors being swallowed? that means this test isn't testing anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intention here (which I did in a couple of other places) was that for longer functions (like handlePrepareResponse), I wanted to test the status of something like a specific like an account's balance. Since it changed so many times over the course of the function, I wanted to capture it during a specific phase -- thus I caught errors which stopped the function early to test the status of the account balance at that point. Do you think it's best to forgoe these tests? I know unit testing logic should not peep inside functions too deeply, but I found this useful in finding a few bugs.
Add jest unit tests for main plugin. WIP -- still have not finished. Create simple memstore for tests. Jest config in package.json to work properly with node (had a bug when not explicitly specifying node environment).
Fee estimation: now returns in gwei instead of wei as intended. Account store: assign anonymous function to proxy to fix `this` context (was not setting to plugin store). Also, set the object property value on the set trap (was not persisting account changes to store). Still a WIP, various TODOs throughout.
Throwing traces fixed (previously not catching). Replace ternary operator logic of _handlePrepareResponse which was not working before. Promise race in _handleCustomData was outputting invalid structure for ILP reject, now properly returns.
* formatAmount fixed to handle negative numbers * channel state should be of 0 not 1 for open channel * added wei <> gwei conversion missing in balance logic * timer adjusted from seconds to milliseconds
8795b9a
to
766b0e4
Compare
Circle on Node 10 is failing when it tries to build sqlite3, a Machinomy dependency--but merging this anyways since we're in the process of removing that. |
Thanks for the big initial push on the plugin @kincaidoneil!
jest unit tests for all functions
fixes for asym-server