Skip to content

Commit

Permalink
Support mutations (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
estrada9166 committed Jan 3, 2019
1 parent 99980e0 commit f31186f
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 75 deletions.
20 changes: 18 additions & 2 deletions README.MD
Expand Up @@ -162,6 +162,12 @@ You can select, if you want to save a `json` file with all the queries that wher
to do it, on the options pass `queryFile: true`, if you don't pass anything it is not going
to be saved.

#### Mutations
You can use [`easygraphql-load-tester`](https://github.com/EasyGraphQL/easygraphql-load-tester) to test
your mutations as well; to do it, on the options pass `withMutations: true`, if you don't pass anything it is only
going to test the queries.
*If you set `withMutations: true`, don't forget to add the input values on the args*

#### Options
*This is optional, you can leave the first argument empty, if you don't want to pass any options*
The artillery method will receive some options that will help to create custom queries,
Expand All @@ -171,7 +177,8 @@ and test specific queries.
const options = {
selectedQueries,
customQueries: queries,
queryFile: true
queryFile: true,
withMutations: true
}
```

Expand All @@ -198,7 +205,8 @@ const queries = [

const options = {
selectedQueries: ['getFamilyInfo', 'searchUser'],
customQueries: queries
customQueries: queries,
withMutations: true
}

const testCases = easyGraphQLLoadTester.artillery(options)
Expand Down Expand Up @@ -336,6 +344,12 @@ You can select, if you want to save a `json` file with all the queries that wher
to do it, on the options pass `queryFile: true`, if you don't pass anything it is not going
to be saved.

#### Mutations
You can use [`easygraphql-load-tester`](https://github.com/EasyGraphQL/easygraphql-load-tester) to test
your mutations as well; to do it, on the options pass `withMutations: true`, if you don't pass anything it is only
going to test the queries.
*If you set `withMutations: true`, don't forget to add the input values on the args*

#### Virtual users
You can select how many virtual users do you want for your tests, just pass to the options
`vus: <NUMBER_OF_VUS>`.
Expand All @@ -351,6 +365,7 @@ const options = {
selectedQueries,
customQueries: queries,
queryFile: true,
withMutations: true,
vus: 10,
duration: '10s'
}
Expand Down Expand Up @@ -379,6 +394,7 @@ const queries = [
const options = {
selectedQueries: ['getFamilyInfo', 'searchUser'],
queryFile: true,
withMutations: true,
vus: 10,
duration: '10s'
}
Expand Down
2 changes: 1 addition & 1 deletion examples/artillery/artillery.yml
Expand Up @@ -14,7 +14,7 @@ scenarios:
json:
query: "{{ $loopElement.query }}"
- log: "----------------------------------"
- log: "Sent a request to the Query: {{ $loopElement.name }}"
- log: "Sent a request to the {{ $loopElement.operation }}: {{ $loopElement.name }}"
over: cases


11 changes: 10 additions & 1 deletion examples/artillery/index.js
Expand Up @@ -15,6 +15,15 @@ const args = {
},
searchUser: {
name: 'demo'
},
createUser: {
name: 'demo'
},
createCity: {
input: {
name: 'demo',
country: 'Demo'
}
}
}

Expand All @@ -35,7 +44,7 @@ const queries = [

const testCases = easyGraphQLLoadTester.artillery({
customQueries: queries,
queryFile: true
withMutations: true
})

module.exports = {
Expand Down
11 changes: 11 additions & 0 deletions examples/artillery/schema.gql
Expand Up @@ -16,8 +16,19 @@ type Test {
email: String!
}

input CityInput {
name: String!
country: String!
}

type Query {
getFamilyInfo: FamilyInfo!
searchUser(name: String!): User!
getFamilyInfoByIsLocal(isLocal: Boolean!, test: [String]!, age: Int!, name: String!): FamilyInfo!
getMe: Boolean!
}

type Mutation {
createUser(name: String!): User!
createCity(input: CityInput!): User!
}
65 changes: 22 additions & 43 deletions lib/loadTesting.js
Expand Up @@ -3,7 +3,8 @@
const fs = require('fs')
const schemaParser = require('easygraphql-parser')
const { spawn } = require('child_process')
const { getField, createQueryArguments, createUnionQuery, createQueryToTest } = require('../util')
const create = require('../utils')
const { queryField, mutationField } = require('../utils/schemaDefinition')

class LoadTesting {
constructor (schema, args = {}) {
Expand All @@ -15,57 +16,35 @@ class LoadTesting {
this.arguments = args
}

createQuery (queries, selectedQueries) {
createQuery (queries, selectedQueries, withMutations) {
queries = queries || []
selectedQueries = selectedQueries || []

this.schema.Query.fields.forEach(query => {
if (selectedQueries.length) {
const isQueryToTest = selectedQueries.indexOf(query.name)
if (isQueryToTest < 0) return
}

const nestedType = this.schema[query.type]
const fields = []

let queryHeader
if (query.arguments.length) {
const createdArgs = createQueryArguments(query.arguments, this.arguments[query.name])
queryHeader = `${query.name}(${createdArgs})`
} else {
queryHeader = query.name
}

if (nestedType.type === 'UnionTypeDefinition') {
const unionQueries = []
nestedType.types.forEach(type => {
const newNestedType = this.schema[type]

unionQueries.push(createUnionQuery(newNestedType, this.schema, type))
})

const queryToTest = createQueryToTest(unionQueries, queryHeader)

queries.push(queryToTest)
} else {
nestedType.fields.forEach(field => {
const createdField = getField(field, this.schema)
fields.push(createdField)

const queryToTest = createQueryToTest(fields, queryHeader)

queries.push(queryToTest)
})
const Query = queryField(this.schema)
this.schema[Query].fields.forEach(query => {
const createdQueries = create(this.schema, query, selectedQueries, this.arguments)
if (createdQueries && createdQueries.length > 0) {
queries.push(...createdQueries)
}
})

if (withMutations) {
const Mutation = mutationField(this.schema)
this.schema[Mutation].fields.forEach(mutation => {
const createdQueries = create(this.schema, mutation, selectedQueries, this.arguments, true)
if (createdQueries && createdQueries.length > 0) {
queries.push(...createdQueries)
}
})
}

return queries
}

artillery (options = {}) {
const { customQueries, selectedQueries, queryFile } = options
const { customQueries, selectedQueries, queryFile, withMutations } = options

const queries = this.createQuery(customQueries, selectedQueries)
const queries = this.createQuery(customQueries, selectedQueries, withMutations)

if (queryFile) {
const queryFileName = 'easygraphql-load-tester-queries.json'
Expand All @@ -84,9 +63,9 @@ class LoadTesting {
}
const queryFileName = 'easygraphql-load-tester-queries.json'

const { customQueries, selectedQueries, vus, duration, queryFile } = options
const { customQueries, selectedQueries, vus, duration, queryFile, withMutations } = options

const queries = this.createQuery(customQueries, selectedQueries)
const queries = this.createQuery(customQueries, selectedQueries, withMutations)
const selectedVus = vus || ''

const selectedDuration = duration || ''
Expand Down
23 changes: 20 additions & 3 deletions test/queryGenerator.js
Expand Up @@ -22,6 +22,9 @@ describe('Query generator', () => {
id: '1',
name: 'demo'
}
},
isAdmin: {
username: 'test'
}
}
const loadTest = new EasyGraphQLTester(schema, args)
Expand All @@ -46,6 +49,15 @@ describe('Query generator', () => {
id: '1',
name: 'demo'
}
},
isAdmin: {
username: 'test'
},
createUser: {
input: {
name: 'test',
email: 'test@test.com'
}
}
}
const loadTest = new EasyGraphQLTester(schema, args)
Expand All @@ -60,21 +72,23 @@ describe('Query generator', () => {
}`
}
]
const queries = loadTest.createQuery(myQueries)
const queries = loadTest.createQuery(myQueries, null, true)

expect(queries).to.exist
expect(queries).to.be.a('array')
expect(queries[0].name).to.includes('myNewQuery')
expect(queries[1].name).to.includes('getMe')
expect(queries[queries.length - 1].name).to.includes('getUser')
expect(queries[queries.length - 1].name).to.includes('where: {')
expect(queries[queries.length - 1].name).to.includes('createUser')
})

it('Should initialize constructor with selectedQueries queries', () => {
const args = {
getUserByUsername: {
username: 'Test',
id: 1
},
isAdmin: {
username: 'test'
}
}
const loadTest = new EasyGraphQLTester(schema, args)
Expand Down Expand Up @@ -176,6 +190,9 @@ describe('Query generator', () => {
id: '1',
name: 'demo'
}
},
isAdmin: {
username: 'test'
}
}

Expand Down
16 changes: 16 additions & 0 deletions test/schema/schema.gql
@@ -1,3 +1,8 @@
enum Roles {
ADMIN
USER
}

type Family {
name: String!
ages: [Int]!
Expand All @@ -14,6 +19,7 @@ type Me {
apiKey: String!
users: [User]!
verified: Boolean!
role: Roles!
}

type User {
Expand All @@ -29,8 +35,18 @@ input UserInfoInput {
name: String!
}

type UserInput {
name: String!
email: String!
}

type Query {
getMe: Me
getUserByUsername(username: String!, id: Int!): User
isAdmin(username: String!): Boolean!
getUser(where: UserInfoInput!): User
}

type Mutation {
createUser(input: UserInput!): User!
}
13 changes: 0 additions & 13 deletions util/constants.js

This file was deleted.

54 changes: 54 additions & 0 deletions utils/index.js
@@ -0,0 +1,54 @@
'use strict'

const { getField, createQueryArguments, createUnionQuery, createQueryToTest } = require('./util')

function create (schema, query, selectedQueries, args, isMutation) {
if (selectedQueries.length) {
const isQueryToTest = selectedQueries.indexOf(query.name)
if (isQueryToTest < 0) return
}

let queryHeader
if (query.arguments.length) {
const createdArgs = createQueryArguments(query.arguments, args[query.name])
queryHeader = `${query.name}(${createdArgs})`
} else {
queryHeader = query.name
}

const queriesToTest = []
if (['ID', 'String', 'Int', 'Float', 'Boolean'].indexOf(query.type) >= 0) {
const queryToTest = createQueryToTest([], queryHeader, isMutation)
queriesToTest.push(queryToTest)
return queriesToTest
}

const nestedType = schema[query.type]
const fields = []

if (nestedType.type === 'UnionTypeDefinition') {
const unionQueries = []
nestedType.types.forEach(type => {
const newNestedType = schema[type]

unionQueries.push(createUnionQuery(newNestedType, schema, type))
})

const queryToTest = createQueryToTest(unionQueries, queryHeader, isMutation)

queriesToTest.push(queryToTest)
} else {
nestedType.fields.forEach(field => {
const createdField = getField(field, schema)
fields.push(createdField)

const queryToTest = createQueryToTest(fields, queryHeader, isMutation)

queriesToTest.push(queryToTest)
})
}

return queriesToTest
}

module.exports = create

0 comments on commit f31186f

Please sign in to comment.