Skip to content

Commit

Permalink
feat(backend): support Open Payments connection as receiver (#603)
Browse files Browse the repository at this point in the history
* chore(backend): include asset details in connection

* chore(backend): generalize client service receiver resolution

* feat(backend): support Open Payments connection as receiver

* chore(backend): remove auth from test SPSP/connections endpoint

Auth is only required on mocked payment pointer endpoints.

* chore(backend): remove auth header from connection query

* chore(backend): update Open Payments OpenAPI spec

* chore(backend): make test receiver url https

* chore(backend): query Open Payments with http in development mode

* chore(backend): swap incoming payment receiver checks
  • Loading branch information
wilsonianb authored Sep 23, 2022
1 parent ae08f55 commit 9dea96b
Show file tree
Hide file tree
Showing 19 changed files with 539 additions and 373 deletions.
2 changes: 1 addition & 1 deletion packages/backend/src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export const Config = {

openPaymentsSpec: envString(
'OPEN_PAYMENTS_SPEC',
'https://raw.githubusercontent.com/interledger/open-payments/bc90cb63e99e56b85abe25f2018393c7b21f6648/open-api-spec.yaml'
'https://raw.githubusercontent.com/interledger/open-payments/499d551e36fb42614feeadd4aa3af90bb2a4fcff/open-api-spec.yaml'
),
authServerSpec: envString(
'AUTH_SERVER_SPEC',
Expand Down
110 changes: 68 additions & 42 deletions packages/backend/src/open_payments/client/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ describe('Open Payments Client Service', (): void => {
let clientService: OpenPaymentsClientService
let knex: Knex

const CONNECTION_PATH = 'connections'
const INCOMING_PAYMENT_PATH = 'incoming-payments'

beforeAll(async (): Promise<void> => {
deps = await initIocContainer(Config)
appContainer = await createTestApp(deps)
Expand All @@ -35,74 +38,97 @@ describe('Open Payments Client Service', (): void => {
afterAll(async (): Promise<void> => {
await appContainer.shutdown()
})
describe('incomingPayment.get', (): void => {
test.each`
incomingAmount | description | externalRef
${undefined} | ${undefined} | ${undefined}
${BigInt(123)} | ${'Test'} | ${'#123'}
`(
'resolves incoming payment from Open Payments server',
async ({ incomingAmount, description, externalRef }): Promise<void> => {
describe.each`
urlPath | description
${CONNECTION_PATH} | ${'connection'}
${INCOMING_PAYMENT_PATH} | ${'incoming payment'}
`('receiver.get - $description', ({ urlPath }): void => {
if (urlPath === CONNECTION_PATH) {
test('resolves connection from Open Payments server', async (): Promise<void> => {
const paymentPointer = await createPaymentPointer(deps, {
mockServerPort: appContainer.openPaymentsPort
})
const incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
description,
incomingAmount: incomingAmount && {
value: incomingAmount,
assetCode: paymentPointer.asset.code,
assetScale: paymentPointer.asset.scale
},
externalRef
paymentPointerId: paymentPointer.id
})
const resolvedPayment = await clientService.incomingPayment.get(
incomingPayment.url
const receiver = await clientService.receiver.get(
`${Config.openPaymentsUrl}/${urlPath}/${incomingPayment.connectionId}`
)
paymentPointer.scope.isDone()
expect(resolvedPayment).toEqual({
...incomingPayment.toJSON(),
id: incomingPayment.url,
paymentPointer: incomingPayment.paymentPointer.url,
ilpStreamConnection: {
id: `${Config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`,
ilpAddress: expect.any(String),
sharedSecret: expect.any(String)
}
})
}
)
expect(receiver.assetCode).toEqual(paymentPointer.asset.code)
expect(receiver.assetScale).toEqual(paymentPointer.asset.scale)
expect(receiver.incomingAmount).toBeUndefined()
expect(receiver.receivedAmount).toBeUndefined()
expect(receiver.ilpAddress).toEqual(expect.any(String))
expect(receiver.sharedSecret).toEqual(expect.any(Buffer))
})
} else {
test.each`
incomingAmount | description | externalRef
${undefined} | ${undefined} | ${undefined}
${BigInt(123)} | ${'Test'} | ${'#123'}
`(
'resolves incoming payment from Open Payments server',
async ({ incomingAmount, description, externalRef }): Promise<void> => {
const paymentPointer = await createPaymentPointer(deps, {
mockServerPort: appContainer.openPaymentsPort
})
const incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
description,
incomingAmount: incomingAmount && {
value: incomingAmount,
assetCode: paymentPointer.asset.code,
assetScale: paymentPointer.asset.scale
},
externalRef
})
const receiver = await clientService.receiver.get(incomingPayment.url)
paymentPointer.scope.isDone()
expect(receiver.assetCode).toEqual(paymentPointer.asset.code)
expect(receiver.assetScale).toEqual(paymentPointer.asset.scale)
expect(receiver.incomingAmount).toEqual(
incomingPayment.incomingAmount
)
expect(receiver.receivedAmount).toEqual(
incomingPayment.receivedAmount
)
expect(receiver.ilpAddress).toEqual(expect.any(String))
expect(receiver.sharedSecret).toEqual(expect.any(Buffer))
}
)
}
test.each`
statusCode
${404}
${500}
`(
'returns undefined for unsuccessful request ($statusCode)',
async ({ statusCode }): Promise<void> => {
const incomingPaymentUrl = new URL(
`${faker.internet.url()}/incoming-payments/${uuid()}`
const receiverUrl = new URL(
`${faker.internet.url()}/${urlPath}/${uuid()}`
)
const scope = nock(incomingPaymentUrl.host)
.get(incomingPaymentUrl.pathname)
const scope = nock(receiverUrl.host)
.get(receiverUrl.pathname)
.reply(statusCode)
scope.isDone()
await expect(
clientService.incomingPayment.get(incomingPaymentUrl.href)
clientService.receiver.get(receiverUrl.href)
).resolves.toBeUndefined()
}
)
test('returns undefined for invalid incoming payment response', async (): Promise<void> => {
const incomingPaymentUrl = new URL(
`${faker.internet.url()}/incoming-payments/${uuid()}`
test(`returns undefined for invalid response`, async (): Promise<void> => {
const receiverUrl = new URL(
`${faker.internet.url()}/${urlPath}/${uuid()}`
)
const scope = nock(incomingPaymentUrl.host)
.get(incomingPaymentUrl.pathname)
const scope = nock(receiverUrl.host)
.get(receiverUrl.pathname)
.reply(200, () => ({
validPayment: 0
validReceiver: 0
}))
scope.isDone()
await expect(
clientService.incomingPayment.get(incomingPaymentUrl.href)
clientService.receiver.get(receiverUrl.href)
).resolves.toBeUndefined()
})
})
Expand Down
Loading

0 comments on commit 9dea96b

Please sign in to comment.