276 lines
10 KiB
JavaScript
276 lines
10 KiB
JavaScript
/* istanbul ignore file */
|
|
const chai = require( 'chai' )
|
|
const chaiHttp = require( 'chai-http' )
|
|
const assert = require( 'assert' )
|
|
|
|
const appRoot = require( 'app-root-path' )
|
|
const { init, startHttp } = require( `${appRoot}/app` )
|
|
const knex = require( `${appRoot}/db/knex` )
|
|
const { createPersonalAccessToken } = require( '../../core/services/tokens' )
|
|
const { createWebhook, getStreamWebhooks, getLastWebhookEvents, getWebhook, updateWebhook, deleteWebhook, dispatchStreamEvent } = require( '../services/webhooks' )
|
|
const { createUser } = require( '../../core/services/users' )
|
|
const { createStream, getStream, grantPermissionsStream } = require( '../../core/services/streams' )
|
|
|
|
const expect = chai.expect
|
|
chai.use( chaiHttp )
|
|
|
|
const port = 3420
|
|
const serverAddress = `http://localhost:${port}`
|
|
|
|
|
|
describe( 'Webhooks @webhooks', () => {
|
|
let testServer
|
|
|
|
let userOne = {
|
|
name: 'User',
|
|
email: 'user@gmail.com',
|
|
password: 'jdsadjsadasfdsa'
|
|
}
|
|
|
|
let streamOne = {
|
|
name: 'streamOne',
|
|
description: 'stream',
|
|
isPublic: true
|
|
}
|
|
|
|
let webhookOne = {
|
|
streamId: null, // filled in `before`
|
|
url: 'http://localhost:42/non-existent',
|
|
description: 'test wh',
|
|
secret: 'secret',
|
|
enabled: true,
|
|
triggers: [ 'commit_create', 'commit_update' ]
|
|
}
|
|
|
|
before( async ( ) => {
|
|
await knex.migrate.rollback( )
|
|
await knex.migrate.latest( )
|
|
let { app } = await init()
|
|
let { server } = await startHttp( app, port )
|
|
testServer = server
|
|
|
|
userOne.id = await createUser( userOne )
|
|
streamOne.ownerId = userOne.id
|
|
streamOne.id = await createStream( streamOne )
|
|
|
|
webhookOne.streamId = streamOne.id
|
|
} )
|
|
|
|
after( async ( ) => {
|
|
// await knex.migrate.rollback( )
|
|
testServer.close( )
|
|
} )
|
|
|
|
describe( 'Create, Read, Update, Delete Webhooks', ( ) => {
|
|
it( 'Should create a webhook', async ( ) => {
|
|
webhookOne.id = await createWebhook( webhookOne )
|
|
expect( webhookOne ).to.have.property( 'id' )
|
|
expect( webhookOne.id ).to.not.be.null
|
|
} )
|
|
|
|
it( 'Should get a webhook', async ( ) => {
|
|
let webhook = await getWebhook( { id: webhookOne.id } )
|
|
expect( webhook ).to.not.be.null
|
|
expect( webhook ).to.have.property( 'url' )
|
|
expect( webhook.url ).to.equal( webhookOne.url )
|
|
} )
|
|
|
|
it( 'Should update a webhook', async ( ) => {
|
|
let newUrl = 'http://localhost:42/new-url'
|
|
await updateWebhook( { id: webhookOne.id, url: newUrl } )
|
|
let webhook = await getWebhook( { id: webhookOne.id } )
|
|
expect( webhook ).to.not.be.null
|
|
expect( webhook ).to.have.property( 'url' )
|
|
expect( webhook.url ).to.equal( newUrl )
|
|
} )
|
|
|
|
it( 'Should delete a webhook', async ( ) => {
|
|
await deleteWebhook( { id: webhookOne.id } )
|
|
let webhook = await getWebhook( { id: webhookOne.id } )
|
|
expect( webhook ).to.be.undefined
|
|
} )
|
|
|
|
it( 'Should get webhooks for stream', async ( ) => {
|
|
let streamWebhooks = await getStreamWebhooks( { streamId: streamOne.id } )
|
|
expect( streamWebhooks ).to.have.lengthOf( 0 )
|
|
|
|
webhookOne.id = await createWebhook( webhookOne )
|
|
streamWebhooks = await getStreamWebhooks( { streamId: streamOne.id } )
|
|
expect( streamWebhooks ).to.have.lengthOf( 1 )
|
|
expect( streamWebhooks[ 0 ] ).to.have.property( 'url' )
|
|
expect( streamWebhooks[ 0 ].url ).to.equal( webhookOne.url )
|
|
} )
|
|
|
|
it( 'Should dispatch and get events', async () => {
|
|
await dispatchStreamEvent( { streamId: streamOne.id, event: 'commit_create', eventPayload: { test: 'payload123' } } )
|
|
let lastEvents = await getLastWebhookEvents( { webhookId: webhookOne.id } )
|
|
expect( lastEvents ).to.have.lengthOf( 1 )
|
|
expect( JSON.parse( lastEvents[ 0 ].payload ).test ).to.equal( 'payload123' )
|
|
} )
|
|
} )
|
|
|
|
describe( 'GraphQL API Webhooks @webhooks-api', () => {
|
|
let userTwo = {
|
|
name: 'User2',
|
|
email: 'user2@gmail.com',
|
|
password: 'jdsadjsadasfdsa'
|
|
}
|
|
|
|
let webhookTwo = {
|
|
streamId: null,
|
|
url: 'http://localhost:42/non-existent-two',
|
|
description: 'test wh no 2',
|
|
secret: 'secret',
|
|
enabled: true,
|
|
triggers: [ 'commit_create', 'commit_update' ]
|
|
}
|
|
|
|
let streamTwo = {
|
|
name: 'streamTwo',
|
|
description: 'stream',
|
|
isPublic: true
|
|
}
|
|
|
|
before( async () => {
|
|
userTwo.id = await createUser( userTwo )
|
|
streamTwo.ownerId = userTwo.id
|
|
streamTwo.id = await createStream( streamTwo )
|
|
webhookTwo.streamId = streamTwo.id
|
|
|
|
|
|
userOne.token = `Bearer ${( await createPersonalAccessToken( userOne.id, 'userOne test token', [ 'streams:read', 'streams:write' ] ) )}`
|
|
userTwo.token = `Bearer ${( await createPersonalAccessToken( userTwo.id, 'userTwo test token', [ 'streams:read', 'streams:write' ] ) )}`
|
|
await grantPermissionsStream( { streamId: streamTwo.id, userId: userOne.id, role: 'stream:contributor' } )
|
|
} )
|
|
|
|
it( 'Should create a webhook', async () => {
|
|
const res = await sendRequest( userTwo.token, { query: 'mutation createWebhook($webhook: WebhookCreateInput!) { webhookCreate( webhook: $webhook ) }', variables: { webhook: webhookTwo } } )
|
|
expect( noErrors( res ) )
|
|
expect( res.body.data.webhookCreate ).to.not.be.null
|
|
webhookTwo.id = res.body.data.webhookCreate
|
|
} )
|
|
|
|
it( 'Should get stream webhooks and the previous events', async () => {
|
|
await dispatchStreamEvent( { streamId: streamTwo.id, event: 'commit_create', eventPayload: { test: 'payload321' } } )
|
|
const res = await sendRequest( userTwo.token, { query: `query {
|
|
stream(id: "${streamTwo.id}") {
|
|
webhooks { totalCount items { id url enabled
|
|
history { totalCount items { status statusInfo payload } } }
|
|
}
|
|
}
|
|
}` } )
|
|
expect( noErrors( res ) )
|
|
let webhooks = res.body.data.stream.webhooks
|
|
|
|
expect( webhooks.totalCount ).to.equal( 1 )
|
|
expect( webhooks.items[ 0 ].url ).to.equal( webhookTwo.url )
|
|
expect( webhooks.items[ 0 ].history.totalCount ).to.equal( 1 )
|
|
expect( JSON.parse( webhooks.items[ 0 ].history.items[ 0 ].payload ).test ).to.equal( 'payload321' )
|
|
} )
|
|
|
|
it( 'Should update a webhook', async () => {
|
|
const res = await sendRequest( userTwo.token, {
|
|
query: `mutation { webhookUpdate(webhook: { id: "${webhookTwo.id}", streamId: "${streamTwo.id}", description: "updated webhook", enabled: false })
|
|
}` } )
|
|
let webhook = await getWebhook( { id: webhookTwo.id } )
|
|
expect( noErrors( res ) )
|
|
expect( res.body.data.webhookUpdate ).to.equal( 'true' )
|
|
expect( webhook.description ).to.equal( 'updated webhook' )
|
|
expect( webhook.enabled ).to.equal( false )
|
|
} )
|
|
|
|
it( 'Should *not* update or delete a webhook if the stream id and webhook id do not match', async () => {
|
|
const res1 = await sendRequest( userOne.token, {
|
|
query: `mutation { webhookDelete(webhook: { id: "${webhookTwo.id}", streamId: "${streamOne.id}" } ) }`
|
|
} )
|
|
expect( res1.body.errors ).to.exist
|
|
expect( res1.body.errors[ 0 ].message ).to.equal( 'The webhook id and stream id do not match. Please check your inputs.' )
|
|
expect( res1.body.errors[ 0 ].extensions.code ).to.equal( 'FORBIDDEN' )
|
|
|
|
const res2 = await sendRequest( userOne.token, {
|
|
query: `mutation { webhookUpdate(webhook: { id: "${webhookTwo.id}", streamId: "${streamOne.id}", description: "updated webhook", enabled: false }) }`
|
|
} )
|
|
expect( res2.body.errors ).to.exist
|
|
expect( res2.body.errors[ 0 ].message ).to.equal( 'The webhook id and stream id do not match. Please check your inputs.' )
|
|
expect( res2.body.errors[ 0 ].extensions.code ).to.equal( 'FORBIDDEN' )
|
|
} )
|
|
|
|
it( 'Should delete a webhook', async () => {
|
|
const res = await sendRequest( userTwo.token, {
|
|
query: `mutation { webhookDelete(webhook: { id: "${webhookTwo.id}", streamId: "${streamTwo.id}" } ) }`
|
|
} )
|
|
expect( noErrors( res ) )
|
|
expect( res.body.data.webhookDelete ).to.equal( 'true' )
|
|
} )
|
|
|
|
it( 'Should *not* create a webhook if user is not a stream owner', async () => {
|
|
delete webhookTwo.id
|
|
const res = await sendRequest( userOne.token, {
|
|
query: 'mutation createWebhook($webhook: WebhookCreateInput!) { webhookCreate( webhook: $webhook ) }',
|
|
variables: { webhook: webhookTwo }
|
|
} )
|
|
expect( res.body.errors ).to.exist
|
|
expect( res.body.errors[ 0 ].extensions.code ).to.equal( 'FORBIDDEN' )
|
|
} )
|
|
|
|
it( 'Should *not* get a webhook if the user is not a stream owner', async () => {
|
|
const res = await sendRequest( userOne.token, { query: `query {
|
|
stream(id: "${streamTwo.id}") { webhooks { totalCount items { id url enabled } } }
|
|
}` } )
|
|
expect( res.body.errors ).to.exist
|
|
expect( res.body.errors[ 0 ].extensions.code ).to.equal( 'FORBIDDEN' )
|
|
} )
|
|
|
|
|
|
it( 'Should have a webhook limit for streams', async ( ) => {
|
|
let limit = 100
|
|
for ( let i = 0; i < limit - 1; i++ ) {
|
|
await createWebhook( webhookOne )
|
|
}
|
|
|
|
try {
|
|
await createWebhook( webhookOne )
|
|
} catch ( err ) {
|
|
if ( err.toString().indexOf( 'Maximum' ) > -1 ) return
|
|
}
|
|
|
|
assert.fail( 'Configured more webhooks than the limit' )
|
|
} )
|
|
|
|
it( 'Should cleanup stream webhooks', async ( ) => {
|
|
// just cleanup the 99 extra webhooks added before (not a real test)
|
|
let streamWebhooks = await getStreamWebhooks( { streamId: streamOne.id } )
|
|
for ( let webhook of streamWebhooks ) {
|
|
if ( webhook.id != webhookOne.id ) {
|
|
await deleteWebhook( { id: webhook.id } )
|
|
}
|
|
}
|
|
|
|
streamWebhooks = await getStreamWebhooks( { streamId: streamOne.id } )
|
|
expect( streamWebhooks ).to.have.lengthOf( 1 )
|
|
expect( streamWebhooks[ 0 ] ).to.have.property( 'id' )
|
|
expect( streamWebhooks[ 0 ].id ).to.equal( webhookOne.id )
|
|
} )
|
|
} )
|
|
} )
|
|
|
|
|
|
/**
|
|
* Sends a graphql request. Convenience wrapper.
|
|
* @param {string} auth the user's token
|
|
* @param {string} obj the query/mutation to send
|
|
* @return {Promise} the awaitable request
|
|
*/
|
|
function sendRequest( auth, obj, address = serverAddress ) {
|
|
return chai.request( address ).post( '/graphql' ).set( 'Authorization', auth ).send( obj )
|
|
}
|
|
|
|
/**
|
|
* Checks the response body for errors. To be used in expect assertions.
|
|
* Will throw an error if 'errors' exist.
|
|
* @param {*} res
|
|
*/
|
|
function noErrors( res ) {
|
|
if ( 'errors' in res.body ) throw new Error( `Failed GraphQL request: ${res.body.errors[ 0 ].message}` )
|
|
}
|