From 9715129284c5cdeb535f15c4578c56cdd4fdb1c3 Mon Sep 17 00:00:00 2001 From: Dimitrie Stefanescu Date: Mon, 20 Jul 2020 00:58:00 +0100 Subject: [PATCH] feat(gql): (re-)implemented some commits & re-organized gql tests --- modules/core/graph/resolvers/commits.js | 35 +- .../graph/schemas/branchesAndCommits.graphql | 3 +- modules/core/migrations/000-core.js | 4 +- modules/core/services/streams.js | 5 +- modules/core/tests/graph.spec.js | 397 ++++++++++-------- 5 files changed, 257 insertions(+), 187 deletions(-) diff --git a/modules/core/graph/resolvers/commits.js b/modules/core/graph/resolvers/commits.js index 6df4b34160..2fff5870b4 100644 --- a/modules/core/graph/resolvers/commits.js +++ b/modules/core/graph/resolvers/commits.js @@ -9,6 +9,7 @@ const { createCommitByBranchId, updateCommit, deleteCommit, + getCommitById, getCommitsByBranchId, getCommitsByBranchName, getCommitsByUserId, @@ -26,33 +27,59 @@ const { module.exports = { Query: {}, Stream: { + async commit( parent, args, context, info ) { throw new ApolloError( 'not implemented' ) } + }, User: { + async commits( parent, args, context, info ) { // TODO throw new ApolloError( 'not implemented' ) } + }, Branch: { + async commits( parent, args, context, info ) { throw new ApolloError( 'not implemented' ) } + }, Mutation: { + async commitCreate( parent, args, context, info ) { - throw new ApolloError('not implemented') + await validateServerRole( context, 'server:user' ) + await validateScopes( context.scopes, 'streams:write' ) + await authorizeResolver( context.userId, args.commit.streamId, 'stream:contributor' ) + return await createCommitByBranchName( { ...args.commit, authorId: context.userId } ) }, + async commitUpdate( parent, args, context, info ) { - throw new ApolloError('not implemented') + await validateServerRole( context, 'server:user' ) + await validateScopes( context.scopes, 'streams:write' ) + await authorizeResolver( context.userId, args.commit.streamId, 'stream:contributor' ) + + let commit = await getCommitById( { id: args.commit.id } ) + if ( commit.author !== context.userId ) + throw new AuthorizationError( 'Only the author of a commit may update it.' ) + return await updateCommit( { ...args.commit } ) }, + async commitDelete( parent, args, context, info ) { - throw new ApolloError('not implemented') - + await validateServerRole( context, 'server:user' ) + await validateScopes( context.scopes, 'streams:write' ) + await authorizeResolver( context.userId, args.commit.streamId, 'stream:contributor' ) + + let commit = await getCommitById( { id: args.commit.id } ) + if ( commit.author !== context.userId ) + throw new AuthorizationError( 'Only the author of a commit may delete it.' ) + + return await deleteCommit( { id: args.commit.id } ) } } } \ No newline at end of file diff --git a/modules/core/graph/schemas/branchesAndCommits.graphql b/modules/core/graph/schemas/branchesAndCommits.graphql index b0edd957b0..e95347e177 100644 --- a/modules/core/graph/schemas/branchesAndCommits.graphql +++ b/modules/core/graph/schemas/branchesAndCommits.graphql @@ -83,8 +83,9 @@ input BranchDeleteInput { input CommitCreateInput { streamId: String! branchName: String! - objectReference: String! + objectId: String! message: String + previousCommitIds: [String] } input CommitUpdateInput { diff --git a/modules/core/migrations/000-core.js b/modules/core/migrations/000-core.js index 58efe27c23..13ba190c0d 100644 --- a/modules/core/migrations/000-core.js +++ b/modules/core/migrations/000-core.js @@ -147,8 +147,8 @@ exports.up = async knex => { // - one ancestor (simple sequential push) // - more ancestors (result of a merge) await knex.schema.createTable( 'parent_commits', table => { - table.string( 'parent', 10 ).references( 'id' ).inTable( 'commits' ).notNullable( ) - table.string( 'child', 10 ).references( 'id' ).inTable( 'commits' ).notNullable( ) + table.string( 'parent', 10 ).references( 'id' ).inTable( 'commits' ).notNullable( ).onDelete( 'cascade' ) + table.string( 'child', 10 ).references( 'id' ).inTable( 'commits' ).notNullable( ).onDelete( 'cascade' ) table.unique( [ 'parent', 'child' ], 'commit_parent_child_index' ) } ) diff --git a/modules/core/services/streams.js b/modules/core/services/streams.js index 7ac831847f..7444e1f061 100644 --- a/modules/core/services/streams.js +++ b/modules/core/services/streams.js @@ -33,7 +33,10 @@ module.exports = { }, async updateStream( { streamId, name, description } ) { - let [ res ] = await Streams( ).returning( 'id' ).where( { id: streamId } ).update( { name, description } ) + let [ res ] = await Streams( ) + .returning( 'id' ) + .where( { id: streamId } ) + .update( { name, description } ) return res }, diff --git a/modules/core/tests/graph.spec.js b/modules/core/tests/graph.spec.js index 2667639158..c01fd21346 100644 --- a/modules/core/tests/graph.spec.js +++ b/modules/core/tests/graph.spec.js @@ -62,8 +62,8 @@ describe( 'GraphQL API Core', ( ) => { let objIds // some commits - let c1 = { description: 'test first commit' } - let c2 = { description: 'test second commit' } + let c1 = {} + let c2 = {} // some branches let b1 = { name: 'branch 1', description: 'test branch' } @@ -72,216 +72,268 @@ describe( 'GraphQL API Core', ( ) => { describe( 'Mutations', ( ) => { - it( 'Should create some api tokens', async ( ) => { - const res1 = await sendRequest( userA.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:read", "users:read", "tokens:read" ]) }` } ) - expect( res1 ).to.be.json - expect( res1.body.errors ).to.not.exist - expect( res1.body.data.apiTokenCreate ).to.be.a( 'string' ) + describe( 'Users & Api tokens', ( ) => { + it( 'Should create some api tokens', async ( ) => { + const res1 = await sendRequest( userA.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:read", "users:read", "tokens:read" ]) }` } ) + expect( res1 ).to.be.json + expect( res1.body.errors ).to.not.exist + expect( res1.body.data.apiTokenCreate ).to.be.a( 'string' ) - token1 = `Bearer ${res1.body.data.apiTokenCreate}` + token1 = `Bearer ${res1.body.data.apiTokenCreate}` - const res2 = await sendRequest( userA.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:write", "streams:read", "users:email"]) }` } ) - token2 = `Bearer ${res2.body.data.apiTokenCreate}` + const res2 = await sendRequest( userA.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:write", "streams:read", "users:email"]) }` } ) + token2 = `Bearer ${res2.body.data.apiTokenCreate}` - const res3 = await sendRequest( userB.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:write", "streams:read", "users:email"]) }` } ) - token3 = `Bearer ${res3.body.data.apiTokenCreate}` - } ) + const res3 = await sendRequest( userB.token, { query: `mutation { apiTokenCreate(name:"Token 1", scopes: ["streams:write", "streams:read", "users:email"]) }` } ) + token3 = `Bearer ${res3.body.data.apiTokenCreate}` + } ) - it( 'Should revoke an api token that the user owns', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation{ apiTokenRevoke(token:"${token2}")}` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data.apiTokenRevoke ).to.equal( true ) - } ) + it( 'Should revoke an api token that the user owns', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation{ apiTokenRevoke(token:"${token2}")}` } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data.apiTokenRevoke ).to.equal( true ) + } ) - it( 'Should fail to revoke an api token that I do not own', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation{ apiTokenRevoke(token:"${token3}")}` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.exist - } ) + it( 'Should fail to revoke an api token that I do not own', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation{ apiTokenRevoke(token:"${token3}")}` } ) + expect( res ).to.be.json + expect( res.body.errors ).to.exist + } ) - it( 'Should fail to create a stream with an invalid scope token', async ( ) => { - // Note: token1 has only stream read access - const res = await sendRequest( token1, { query: `mutation { streamCreate(stream: { name: "INVALID TS1 (u A) Private", description: "Hello World", isPublic:false } ) }` } ) - expect( res.body.errors ).to.exist - } ) + it( 'Should fail to create a stream with an invalid scope token', async ( ) => { + // Note: token1 has only stream read access + const res = await sendRequest( token1, { query: `mutation { streamCreate(stream: { name: "INVALID TS1 (u A) Private", description: "Hello World", isPublic:false } ) }` } ) + expect( res.body.errors ).to.exist + } ) - it( 'Should edit my profile', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation($user:UserEditInput!) { userEdit( user: $user) } `, variables: { user: { name: 'Miticå', bio: 'He never really knows what he is doing.' } } } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data.userEdit ).to.equal( true ) + it( 'Should edit my profile', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation($user:UserEditInput!) { userEdit( user: $user) } `, variables: { user: { name: 'Miticå', bio: 'He never really knows what he is doing.' } } } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data.userEdit ).to.equal( true ) + } ) } ) - it( 'Should create some streams', async ( ) => { - const resS1 = await sendRequest( userA.token, { query: `mutation { streamCreate(stream: { name: "TS1 (u A) Private", description: "Hello World", isPublic:false } ) }` } ) - expect( resS1 ).to.be.json - expect( resS1.body.errors ).to.not.exist - expect( resS1.body.data ).to.have.property( 'streamCreate' ) - expect( resS1.body.data.streamCreate ).to.be.a( 'string' ) - ts1 = resS1.body.data.streamCreate + describe( 'Streams', ( ) => { + it( 'Should create some streams', async ( ) => { + const resS1 = await sendRequest( userA.token, { query: `mutation { streamCreate(stream: { name: "TS1 (u A) Private", description: "Hello World", isPublic:false } ) }` } ) + expect( resS1 ).to.be.json + expect( resS1.body.errors ).to.not.exist + expect( resS1.body.data ).to.have.property( 'streamCreate' ) + expect( resS1.body.data.streamCreate ).to.be.a( 'string' ) + ts1 = resS1.body.data.streamCreate - const resS2 = await sendRequest( userA.token, { query: `mutation { streamCreate(stream: { name: "TS2 (u A)", description: "Hello Darkness", isPublic:true } ) }` } ) - ts2 = resS2.body.data.streamCreate + const resS2 = await sendRequest( userA.token, { query: `mutation { streamCreate(stream: { name: "TS2 (u A)", description: "Hello Darkness", isPublic:true } ) }` } ) + ts2 = resS2.body.data.streamCreate - const resS3 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS3 (u B) Private", description: "Hello Pumba", isPublic:false } ) }` } ) - ts3 = resS3.body.data.streamCreate + const resS3 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS3 (u B) Private", description: "Hello Pumba", isPublic:false } ) }` } ) + ts3 = resS3.body.data.streamCreate - const resS4 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS4 (u B)", description: "Hello Julian", isPublic:true } ) }` } ) - ts4 = resS4.body.data.streamCreate + const resS4 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS4 (u B)", description: "Hello Julian", isPublic:true } ) }` } ) + ts4 = resS4.body.data.streamCreate - const resS5 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS5 (u B)", description: "Hello King", isPublic:true } ) }` } ) - ts5 = resS5.body.data.streamCreate - } ) + const resS5 = await sendRequest( userB.token, { query: `mutation { streamCreate(stream: { name: "TS5 (u B)", description: "Hello King", isPublic:true } ) }` } ) + ts5 = resS5.body.data.streamCreate + } ) - it( 'Should update a stream', async ( ) => { - const resS1 = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts1}" name: "TS1 (u A) Private UPDATED", description: "Hello World, Again!", isPublic:false } ) }` } ) - // console.log( resS1.body.errors ) - expect( resS1 ).to.be.json - expect( resS1.body.errors ).to.not.exist - expect( resS1.body.data ).to.have.property( 'streamUpdate' ) - expect( resS1.body.data.streamUpdate ).to.equal( true ) - } ) + it( 'Should update a stream', async ( ) => { + const resS1 = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts1}" name: "TS1 (u A) Private UPDATED", description: "Hello World, Again!", isPublic:false } ) }` } ) + // console.log( resS1.body.errors ) + expect( resS1 ).to.be.json + expect( resS1.body.errors ).to.not.exist + expect( resS1.body.data ).to.have.property( 'streamUpdate' ) + expect( resS1.body.data.streamUpdate ).to.equal( true ) + } ) - it( 'Should grant some permissions', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:owner") }` } ) + it( 'Should grant some permissions', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:owner") }` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data.streamGrantPermission ).to.equal( true ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data.streamGrantPermission ).to.equal( true ) - const res2 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts5}", userId: "${userA.id}" role: "stream:owner") }` } ) - const res3 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts3}", userId: "${userC.id}" role: "stream:owner") }` } ) - } ) + const res2 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts5}", userId: "${userA.id}" role: "stream:owner") }` } ) + const res3 = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts3}", userId: "${userC.id}" role: "stream:owner") }` } ) + } ) - it( 'Should fail to grant permissions if not owner', async ( ) => { - const res = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:owner") }` } ) + it( 'Should fail to grant permissions if not owner', async ( ) => { + const res = await sendRequest( userB.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:owner") }` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.exist - } ) + expect( res ).to.be.json + expect( res.body.errors ).to.exist + } ) - it( 'Should fail to grant myself permissions', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userA.id}" role: "stream:owner") }` } ) + it( 'Should fail to grant myself permissions', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userA.id}" role: "stream:owner") }` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.exist - } ) + expect( res ).to.be.json + expect( res.body.errors ).to.exist + } ) - it( 'Should update permissions', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:reviewer") }` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data.streamGrantPermission ).to.equal( true ) - } ) + it( 'Should update permissions', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation{ streamGrantPermission( streamId: "${ts1}", userId: "${userB.id}" role: "stream:reviewer") }` } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data.streamGrantPermission ).to.equal( true ) + } ) - it( 'Should revoke permissions', async ( ) => { - // first test if we can get it - const res = await sendRequest( userC.token, { query: `query { stream(id:"${ts3}") { id name } }` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data.stream.name ).to.equal( 'TS3 (u B) Private' ) + it( 'Should revoke permissions', async ( ) => { + // first test if we can get it + const res = await sendRequest( userC.token, { query: `query { stream(id:"${ts3}") { id name } }` } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data.stream.name ).to.equal( 'TS3 (u B) Private' ) - const revokeRes = await sendRequest( userB.token, { query: `mutation { streamRevokePermission( streamId: "${ts3}", userId:"${userC.id}")} ` } ) - expect( revokeRes ).to.be.json - expect( revokeRes.body.errors ).to.not.exist - expect( revokeRes.body.data.streamRevokePermission ).to.equal( true ) + const revokeRes = await sendRequest( userB.token, { query: `mutation { streamRevokePermission( streamId: "${ts3}", userId:"${userC.id}")} ` } ) + expect( revokeRes ).to.be.json + expect( revokeRes.body.errors ).to.not.exist + expect( revokeRes.body.data.streamRevokePermission ).to.equal( true ) - const resNotAuth = await sendRequest( userC.token, { query: `query { stream(id:"${ts3}") { id name role } }` } ) - expect( resNotAuth ).to.be.json - expect( resNotAuth.body.errors ).to.exist + const resNotAuth = await sendRequest( userC.token, { query: `query { stream(id:"${ts3}") { id name role } }` } ) + expect( resNotAuth ).to.be.json + expect( resNotAuth.body.errors ).to.exist - } ) + } ) - it( 'Should fail to edit/write on a public stream if no access is provided', async ( ) => { - // ts4 is a public stream from uesrB - const res = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts4}" name: "HACK", description: "Hello World, Again!", isPublic:false } ) }` } ) - expect( res.body.errors ).to.exist - } ) + it( 'Should fail to edit/write on a public stream if no access is provided', async ( ) => { + // ts4 is a public stream from uesrB + const res = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts4}" name: "HACK", description: "Hello World, Again!", isPublic:false } ) }` } ) + expect( res.body.errors ).to.exist + } ) - it( 'Should fail editing a private stream if no access has been granted', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts3}" name: "HACK", description: "Hello World, Again!", isPublic:false } ) }` } ) + it( 'Should fail editing a private stream if no access has been granted', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation { streamUpdate(stream: {id:"${ts3}" name: "HACK", description: "Hello World, Again!", isPublic:false } ) }` } ) - expect( res.body.errors ).to.exist - } ) + expect( res.body.errors ).to.exist + } ) - it( 'Should create some objects', async ( ) => { - let objs = [ ] - for ( let i = 0; i < 500; i++ ) { - if ( i % 2 === 0 ) objs.push( { applicationId: i, type: 'Point', x: i, y: 1, z: i * 0.42, extra: { super: true, arr: [ 1, 2, 3, 4 ] } } ) - else if ( i % 3 === 0 ) objs.push( { applicationId: i, type: 'Line', start: { x: i, y: 1, z: i * 0.42 }, end: { x: 0, y: 2, z: i * i }, extra: { super: false, arr: [ 12, 23, 34, 42, { imp: [ 'possible', 'this', 'sturcture', 'is' ] } ] } } ) - else objs.push( { cool: [ 's', 't', [ 'u', 'f', 'f', i ], { that: true } ], iValue: i + i / 3 } ) - } + it( 'Should fail to delete a stream because of permissions', async ( ) => { + const res = await sendRequest( userB.token, { query: `mutation { streamDelete( id:"${ts1}")}` } ) + expect( res ).to.be.json - const res = await sendRequest( userA.token, { query: `mutation($objs:[JSONObject]!) { objectCreate(streamId:"${ts1}", objects: $objs) }`, variables: { objs: objs } } ) + expect( res.body.errors ).to.exist + expect( res.body.errors[ 0 ].extensions.code ).to.equal( 'FORBIDDEN' ) + } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data.objectCreate ).to.have.lengthOf( objs.length ) + it( 'Should delete a stream', async ( ) => { + const res = await sendRequest( userB.token, { query: `mutation { streamDelete( id:"${ts4}")}` } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data ).to.have.property( 'streamDelete' ) + expect( res.body.data.streamDelete ).to.equal( true ) - objIds = res.body.data.objectCreate + } ) } ) - it( 'Should create several commits', async ( ) => { - c1.id = crypto.createHash( 'md5' ).update( JSON.stringify( c1 ) ).digest( 'hex' ) - let res = await sendRequest( userA.token, { query: `mutation($commit:JSONObject!) { commitCreate(streamId:"${ts1}", commit:$commit) }`, variables: { commit: c1 } } ) + describe( 'Objects, Commits & Branches', ( ) => { - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data ).to.have.property( 'commitCreate' ) - expect( res.body.data.commitCreate ).to.be.a( 'string' ) - c1.id = res.body.data.commitCreate + it( 'Should create some objects', async ( ) => { + let objs = [ ] + for ( let i = 0; i < 500; i++ ) { + if ( i % 2 === 0 ) objs.push( { applicationId: i, type: 'Point', x: i, y: 1, z: i * 0.42, extra: { super: true, arr: [ 1, 2, 3, 4 ] } } ) + else if ( i % 3 === 0 ) objs.push( { applicationId: i, type: 'Line', start: { x: i, y: 1, z: i * 0.42 }, end: { x: 0, y: 2, z: i * i }, extra: { super: false, arr: [ 12, 23, 34, 42, { imp: [ 'possible', 'this', 'sturcture', 'is' ] } ] } } ) + else objs.push( { cool: [ 's', 't', [ 'u', 'f', 'f', i ], { that: true } ], iValue: i + i / 3 } ) + } - res = await sendRequest( userA.token, { query: `mutation($commit:JSONObject!) { commitCreate(streamId:"${ts1}", commit:$commit) }`, variables: { commit: c2 } } ) - c2.id = res.body.data.commitCreate - } ) + const res = await sendRequest( userA.token, { query: `mutation( $objs: [JSONObject]! ) { objectCreate( streamId:"${ts1}", objects: $objs ) }`, variables: { objs: objs } } ) - it( 'Should create several branches', async ( ) => { - const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b1 } } ) - expect( res1 ).to.be.json - expect( res1.body.errors ).to.not.exist - expect( res1.body.data ).to.have.property( 'branchCreate' ) - expect( res1.body.data.branchCreate ).to.be.a( 'string' ) - b1.id = res1.body.data.branchCreate + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data.objectCreate ).to.have.lengthOf( objs.length ) - const res2 = await sendRequest( userB.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b2 } } ) - b2.id = res2.body.data.branchCreate + objIds = res.body.data.objectCreate + } ) - const res3 = await sendRequest( userB.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b3 } } ) - b3.id = res3.body.data.branchCreate - } ) + it( 'Should create several commits', async ( ) => { + c1.message = 'what a message for a first commit' + c1.streamId = ts1 + c1.objectId = objIds[ 0 ] + c1.branchName = 'master' + + let res = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitCreateInput! ) { commitCreate( commit: $myCommit ) }`, variables: { myCommit: c1 } } ) + + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data ).to.have.property( 'commitCreate' ) + expect( res.body.data.commitCreate ).to.be.a( 'string' ) + c1.id = res.body.data.commitCreate + + c2.message = 'what a message for a second commit' + c2.streamId = ts1 + c2.objectId = objIds[ 1 ] + c2.branchName = 'master' + c2.previousCommitIds = [ c1.id ] + + res = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitCreateInput! ) { commitCreate( commit: $myCommit ) }`, variables: { myCommit: c2 } } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data ).to.have.property( 'commitCreate' ) + expect( res.body.data.commitCreate ).to.be.a( 'string' ) + + c2.id = res.body.data.commitCreate + } ) - it( 'Should update a branch', async ( ) => { - const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchUpdateInput!) { branchUpdate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: { id: b1.id, commits: [ c1.id ] } } } ) - expect( res1 ).to.be.json - expect( res1.body.errors ).to.not.exist - expect( res1.body.data ).to.have.property( 'branchUpdate' ) - expect( res1.body.data.branchUpdate ).to.equal( true ) - } ) + it( 'Should update a commit', async ( ) => { + let updatePayload = { + streamId: ts1, + id: c1.id, + message: 'first commit' + } + let res = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitUpdateInput! ) { commitUpdate( commit: $myCommit ) }`, variables: { myCommit: updatePayload } } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data ).to.have.property( 'commitUpdate' ) + + let res2 = await sendRequest( userB.token, { query: `mutation( $myCommit: CommitUpdateInput! ) { commitUpdate( commit: $myCommit ) }`, variables: { myCommit: updatePayload } } ) + expect( res2 ).to.be.json + expect( res2.body.errors ).to.exist + } ) - it( 'Should delete a branch', async ( ) => { - const res = await sendRequest( userA.token, { query: `mutation { branchDelete(streamId:"${ts1}", branchId:"${b2.id}")}` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data ).to.have.property( 'branchDelete' ) - expect( res.body.data.branchDelete ).to.equal( true ) - } ) + it( 'Should delete a commit', async ( ) => { + let payload = { streamId: ts1, id: c2.id } - it( 'Should fail to delete a stream because of permissions', async ( ) => { - const res = await sendRequest( userB.token, { query: `mutation { streamDelete( id:"${ts1}")}` } ) - expect( res ).to.be.json + let res = await sendRequest( userB.token, { query: `mutation( $myCommit: CommitDeleteInput! ) { commitDelete( commit: $myCommit ) }`, variables: { myCommit: payload } } ) + expect( res ).to.be.json + expect( res.body.errors ).to.exist - expect( res.body.errors ).to.exist - expect( res.body.errors[ 0 ].extensions.code ).to.equal( 'FORBIDDEN' ) - } ) + let res2 = await sendRequest( userA.token, { query: `mutation( $myCommit: CommitDeleteInput! ) { commitDelete( commit: $myCommit ) }`, variables: { myCommit: payload } } ) + expect( res2 ).to.be.json + expect( res2.body.errors ).to.not.exist + expect( res2.body.data ).to.have.property( 'commitDelete' ) + } ) - it( 'Should delete a stream', async ( ) => { - const res = await sendRequest( userB.token, { query: `mutation { streamDelete( id:"${ts4}")}` } ) - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data ).to.have.property( 'streamDelete' ) - expect( res.body.data.streamDelete ).to.equal( true ) + it( 'Should create several branches', async ( ) => { + const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b1 } } ) + expect( res1 ).to.be.json + expect( res1.body.errors ).to.not.exist + expect( res1.body.data ).to.have.property( 'branchCreate' ) + expect( res1.body.data.branchCreate ).to.be.a( 'string' ) + b1.id = res1.body.data.branchCreate + + const res2 = await sendRequest( userB.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b2 } } ) + b2.id = res2.body.data.branchCreate + + const res3 = await sendRequest( userB.token, { query: `mutation($branch:BranchCreateInput!) { branchCreate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: b3 } } ) + b3.id = res3.body.data.branchCreate + } ) + + it( 'Should update a branch', async ( ) => { + const res1 = await sendRequest( userA.token, { query: `mutation($branch:BranchUpdateInput!) { branchUpdate(streamId:"${ts1}", branch:$branch) }`, variables: { branch: { id: b1.id, commits: [ c1.id ] } } } ) + expect( res1 ).to.be.json + expect( res1.body.errors ).to.not.exist + expect( res1.body.data ).to.have.property( 'branchUpdate' ) + expect( res1.body.data.branchUpdate ).to.equal( true ) + } ) + + it( 'Should delete a branch', async ( ) => { + const res = await sendRequest( userA.token, { query: `mutation { branchDelete(streamId:"${ts1}", branchId:"${b2.id}")}` } ) + expect( res ).to.be.json + expect( res.body.errors ).to.not.exist + expect( res.body.data ).to.have.property( 'branchDelete' ) + expect( res.body.data.branchDelete ).to.equal( true ) + } ) } ) @@ -410,19 +462,6 @@ describe( 'GraphQL API Core', ( ) => { } ) - it( 'should retrieve a stream tag', async ( ) => { - const res = await sendRequest( userA.token, { query: `query { stream(id:"${ts1}") { tag(id:"${retrievedStream.tags.tags[0].id}") { name description commit { id description author { id name } } } } } ` } ) - - expect( res ).to.be.json - expect( res.body.errors ).to.not.exist - expect( res.body.data.stream.tag ).to.have.property( 'name' ) - expect( res.body.data.stream.tag ).to.have.property( 'description' ) - expect( res.body.data.stream.tag ).to.have.property( 'commit' ) - expect( res.body.data.stream.tag.commit ).to.have.property( 'author' ) - expect( res.body.data.stream.tag.commit.author.name ).to.equal( 'Miticå' ) - - } ) - it( 'should retrieve a stream commit', async ( ) => { const res = await sendRequest( userA.token, { query: `query { stream(id:"${ts1}") { commit(id:"${c2.id}") { id description data } } }` } ) expect( res ).to.be.json