Artifact Content
Not logged in

Artifact 31fc8733460841b91f576cacd493cd94218be6c1:


'use strict'

const _ = require('lodash')
const nock = require('nock')
nock.enableNetConnect(['localhost'])
const appHelper = require('./helpers/app')
const logger = require('../src/common/log')
const logHelper = require('./helpers/log')
const wsHelper = require('./helpers/ws')
const sinon = require('sinon')
const IlpPacket = require('ilp-packet')
const { assert } = require('chai')
const { serializeCcpRouteUpdateRequest } = require('ilp-protocol-ccp')

const mockPlugin = require('./mocks/mockPlugin')
const mock = require('mock-require')
mock('ilp-plugin-mock', mockPlugin)

const START_DATE = 1434412800000 // June 16, 2015 00:00:00 GMT

const env = _.cloneDeep(process.env)

describe('Subscriptions', function () {
  logHelper(logger)

  beforeEach(async function () {
    appHelper.create(this)
    await this.backend.connect()
    await this.accounts.connect()
    await this.routeBroadcaster.reloadLocalRoutes()
    await this.middlewareManager.setup()

    const testAccounts = ['test.cad-ledger', 'test.usd-ledger', 'test.eur-ledger', 'test.cny-ledger']
    for (let accountId of testAccounts) {
      this.routeBroadcaster.add(accountId)
      await this.accounts.getPlugin(accountId)._dataHandler(serializeCcpRouteUpdateRequest({
        speaker: accountId,
        routingTableId: 'c951b674-c6f5-42ca-83a3-39a8d4e293b3',
        currentEpochIndex: 1,
        fromEpochIndex: 0,
        toEpochIndex: 1,
        holdDownTime: 45000,
        withdrawnRoutes: [],
        newRoutes: [{
          prefix: accountId,
          path: [accountId],
          auth: Buffer.from('dvlOlr8MjK5denVE+B47Mb6ecvJTwGNaC/lPsEwYlP8=', 'base64'),
          props: []
        }]
      }))
    }

    nock('http://usd-ledger.example').get('/')
      .reply(200, {
        currency_code: 'doesn\'t matter, the connector will ignore this',
        currency_scale: 4
      })

    nock('http://eur-ledger.example').get('/')
      .reply(200, {
        currency_code: 'doesn\'t matter, the connector will ignore this',
        currency_scale: 4
      })

    nock('http://usd-ledger.example').get('/accounts/mark')
      .reply(200, {
        ledger: 'http://usd-ledger.example',
        name: 'mark',
        connector: 'http://localhost'
      })

    nock('http://eur-ledger.example').get('/accounts/mark')
      .reply(200, {
        ledger: 'http://eur-ledger.example',
        name: 'mark',
        connector: 'http://localhost'
      })

    nock('http://cad-ledger.example:1000').get('/accounts/mark')
      .reply(200, {
        ledger: 'http://cad-ledger.example:1000',
        name: 'mark',
        connector: 'http://localhost'
      })

    nock('http://cny-ledger.example').get('/accounts/mark')
      .reply(200, {
        ledger: 'http://cny-ledger.example',
        name: 'mark',
        connector: 'http://localhost'
      })

    this.setTimeout = setTimeout
    this.clock = sinon.useFakeTimers(START_DATE)

    this.wsCadLedger = new wsHelper.Server('ws://cad-ledger.example:1000/accounts/mark/transfers')
    this.wsUsdLedger = new wsHelper.Server('ws://usd-ledger.example/accounts/mark/transfers')
    this.wsEurLedger = new wsHelper.Server('ws://eur-ledger.example/accounts/mark/transfers')
    this.wsEurLedger.on('connection', () => null)
    this.wsCnyLedger = new wsHelper.Server('ws://cny-ledger.example/accounts/mark/transfers')

    this.transferUsdPrepared = _.cloneDeep(require('./data/transferUsdPrepared.json'))
    this.transferEurProposed = _.cloneDeep(require('./data/transferEurProposed.json'))
  })

  afterEach(async function () {
    nock.cleanAll()
    this.clock.restore()
    process.env = _.cloneDeep(env)
    this.wsCadLedger.close()
    this.wsUsdLedger.close()
    this.wsEurLedger.close()
    this.wsCnyLedger.close()
  })

  it('should initiate and complete a universal mode payment', async function () {
    const sourceAccount = 'test.usd-ledger'
    const destinationAccount = 'test.eur-ledger'
    const destination = 'test.eur-ledger.bob'
    const executionCondition = Buffer.from('uzoYx3K6u+Nt6kZjbN6KmH0yARfhkj9e17eQfpSeB7U=', 'base64')
    const expiresAt = new Date('2015-06-16T00:00:11.000Z')
    const data = Buffer.from('BABA', 'base64')
    const sourceAmount = '10700'
    const destinationAmount = '10081'
    const ilpFulfill = {
      fulfillment: Buffer.from('HS8e5Ew02XKAglyus2dh2Ohabuqmy3HDM8EXMLz22ok', 'base64'),
      data: Buffer.from('ABAB', 'base64')
    }
    const sendStub = sinon.stub(this.accounts.getPlugin(destinationAccount), 'sendData')
      .resolves(IlpPacket.serializeIlpFulfill(ilpFulfill))

    const result = await this.accounts.getPlugin(sourceAccount)
      ._dataHandler(IlpPacket.serializeIlpPrepare({
        amount: sourceAmount,
        executionCondition,
        expiresAt,
        destination,
        data
      }))

    sinon.assert.calledOnce(sendStub)
    sinon.assert.calledWith(sendStub, sinon.match(packet => assert.deepEqual(IlpPacket.deserializeIlpPrepare(packet), {
      amount: destinationAmount,
      executionCondition,
      expiresAt: new Date(expiresAt - 1000),
      destination,
      data
    }) || true))
    assert.deepEqual(IlpPacket.deserializeIlpFulfill(result), ilpFulfill)
  })

  it('should notify the backend of a successful payment', async function () {
    const sourceAccount = 'test.usd-ledger'
    const destinationAccount = 'test.eur-ledger'
    const destination = 'test.eur-ledger.bob'
    const executionCondition = Buffer.from('uzoYx3K6u+Nt6kZjbN6KmH0yARfhkj9e17eQfpSeB7U=', 'base64')
    const expiresAt = new Date('2015-06-16T00:00:11.000Z')
    const data = Buffer.from('BABA', 'base64')
    const sourceAmount = '10700'
    const destinationAmount = '10081'
    const ilpFulfill = {
      fulfillment: Buffer.from('HS8e5Ew02XKAglyus2dh2Ohabuqmy3HDM8EXMLz22ok', 'base64'),
      data: Buffer.from('ABAB', 'base64')
    }
    sinon.stub(this.accounts.getPlugin(destinationAccount), 'sendData')
      .resolves(IlpPacket.serializeIlpFulfill(ilpFulfill))
    sinon.stub(this.accounts.getPlugin(destinationAccount), 'sendMoney')
      .resolves()
    const backendSpy = sinon.spy(this.backend, 'submitPayment')

    await this.accounts.getPlugin(sourceAccount)
      ._dataHandler(IlpPacket.serializeIlpPrepare({
        amount: sourceAmount,
        executionCondition,
        expiresAt,
        destination,
        data
      }))

    sinon.assert.calledOnce(backendSpy)
    sinon.assert.calledWith(backendSpy, {
      sourceAccount,
      sourceAmount,
      destinationAccount,
      destinationAmount
    })
  })
})