Creating dynamic POST /users calls with Gatling in Scala - performance

I am using Gatling to generate a large number of users to test performance issues on my product. I need to be able to dynamically create users with unique fields (like 'email'). So, I'm generating a random number and using it, but it isn't being re-instantiated each time, so the email is only unique on the first pass.
object Users {
def r = new scala.util.Random;
def randNumb() = r.nextInt(Integer.MAX_VALUE)
val numb = randNumb()
val createUser = {
exec(http("Create User")
.post("/users")
.body(StringBody(raw"""{"email": "qa_user_$numb#company.com" }""")))
}
}
val runCreateUsers = scenario("Create Users").exec(Users.createUser)
setUp(
runCreateUsers.inject(constantUsersPerSec(10) during(1 seconds))
).protocols(httpConf)
Where should I be defining my random numbers? How can I pass it into createUser?

Use a feeder:
object Users {
val createUser = exec(http("Create User")
.post("/users")
.body(StringBody("""{"email": "qa_user_${numb}#Marqeta.com" }""")))
}
val numbers = Iterator.continually(Map("numb" -> scala.util.Random.nextInt(Int.MaxValue)))
val runCreateUsers = scenario("Create Users")
.feed(numbers)
.exec(Users.createUser)
...

Related

SonarCloud coverage stating that class property with JsonProperty annotation not covered by tests

I have a Kotlin project with Spring, and I created a class that looks like the following:
#JsonIgnoreProperties(ignoreUnknown = true)
data class Response(
val id: String,
#JsonProperty("quantity_of_days")
val quantityOfDays: Int,
)
And my SonarCloud reports state that the quantityOfDays line is not covered by tests:
This line is accessed multiple times inside my tests, and I even created one specifically to instantiate an object of that class. However, this line is still marked as not covered.
I wonder if it has something to do with the annotation, and if so, how do I ignore or force this line to be covered?
Ok so, it was necessary to write some very specific tests to cover that:
class ResponseTest {
#Test
fun `create response from json with underline attribute`() {
val id = "123"
val quantityOfDays = 1
val response = Response(id, quantityOfDays)
val value = Mapper.objectMapper.readValue(
"""
{
"id": "$id",
"quantity_of_days": $quantityOfDays
}
""".trimIndent(), Response::class.java)
assertThat(value).isEqualTo(response)
}
#Test
fun `create response from json with camel case attribute`() {
val response = ResponseBuilder().build()
val json = Mapper.objectMapper.writeValueAsString(response)
val value = Mapper.objectMapper.readValue(json, Response::class.java)
assertThat(value).isEqualTo(response)
}
}
I am not sure if that is the best solution, maybe there is a way to make the coverage ignore that in specific, but I could not find it. But it works.

Springboot Mongo reactive repository unable to update nested list

I wanted to update a nested list but I experience a strange behavior where I have to call method twice to get it done...
Here is my POJO:
#Document(collection = "company")
data class Company (
val id: ObjectId,
#Indexed(unique=true)
val name: String,
val customers: MutableList<Customer> = mutableListOf()
//other fields
)
Below is my function from custom repository to do the job which I based on this tutorial
override fun addCustomer(customer: Customer): Mono<Company> {
val query = Query(Criteria.where("employees.keycloakId").`is`(customer.createdBy))
val update = Update().addToSet("customers", customer)
val upsertOption = FindAndModifyOptions.options().upsert(true)
//if I uncomment below this will work...
//mongoTemplate.findAndModify(query, update, upsertOption, Company::class.java).block()
return mongoTemplate.findAndModify(query, update, upsertOption, Company::class.java)
}
In order to actually add this customer I have to either uncomment the block call above or call the method two times in the debugger while running integration tests which is quite confusing to me
Here is the failing test
#Test
fun addCustomer() {
//given
val company = fixture.company
val initialCustomerSize = company.customers.size
companyRepository.save(company).block()
val customerToAdd = CustomerReference(id = ObjectId.get(),
keycloakId = "dummy",
username = "customerName",
email = "email",
createdBy = company.employees[0].keycloakId)
//when, then
StepVerifier.create(companyCustomRepositoryImpl.addCustomer(customerToAdd))
.assertNext { updatedCompany -> assertThat(updatedCompany.customers).hasSize(initialCustomerSize + 1) }
.verifyComplete()
}
java.lang.AssertionError:
Expected size:<3> but was:<2> in:
I found out the issue.
By default mongo returns entity with state of before update. To override it I had to add:
val upsertOption = FindAndModifyOptions.options()
.returnNew(true)
.upsert(true)

Mutations - batch creation of objects

I want to use graphene to create many people in one go.
The document only mention the way to create one person like this:
class CreatePerson(graphene.Mutation):
class Input:
name = graphene.String()
age = graphene.Int()
ok = graphene.Boolean()
person = graphene.Field(lambda: Person)
#staticmethod
def mutate(root, args, context, info):
person = Person(name=args.get('name'), age=args.get('age'), mobile=args.get('mobile'))
ok = True
return CreatePerson(person=person, ok=ok)
are there any ways to get it done?
Instead of using a mutation that creates a list of objects, you can also call a mutation that creates one objects multiple times in one GraphQL request. This is accomplished using GraphQL Aliases:
mutation {
c001: createPerson(
name: "Donald Duck"
age: 42
) {
id
}
c002: createPerson(
name: "Daisy Duck"
age: 43
) {
id
}
c003: createPerson(
name: "Mickey Mouse"
age: 44
) {
id
}
}
I can figure out a solution base on the answer of Jan Hančič
There is a type called graphene.InputObjectType to use in this case
The solution can be
class PersonInput(InputObjectType):
name = graphene.String()
age = graphene.Int()
class CreatePeople(graphene.Mutation):
class Input:
people = graphene.List(PersonInput)
people = graphene.List(lambda: Person)
#staticmethod
def mutate(root, args, context, info):
people = [Person.objects.create(name=person.name, age=person.age) for person in args.get('people')]
return CreatePeople(people=people)
Make your mutation input a list and return a list of created people. Something like this:
class CreatePerson(graphene.Mutation):
class Input:
name = graphene.List(graphene.String)
ok = graphene.Boolean()
people = graphene.List(Person)
#staticmethod
def mutate(root, args, context, info):
people = [Person(name=name) for name in args.get('name)]
ok = True
return CreatePerson(people=people, ok=ok)
Receive a list of input, create all instances and return them all
The model node/type should be like-
class UserType(DjangoObjectType):
class Meta:
model = User
interfaces = (CustomGrapheneNode, )
filter_fields = {}
only_fields = (
'name',
'email'
)
Define Input fields
class UserInput(graphene.InputObjectType):
name = graphene.String(required=True)
password = graphene.String(required=True)
Mutation class
class CreateUser(graphene.Mutation):
users = graphene.List(UserType)
class Input:
data = graphene.List(UserInput)
Output = graphene.List(UserType)
def mutate(self, info, data):
users = []
for item in data:
user = User.objects.create(name=data['name'],
password=data['password'])
users.append(user)
return users
make this mutation callable by main schema
class Mutation():
create_user = CreateUser.Field()
the Mutation Query view will be as -
mutation{
createUser(data:[{name:"john", password:"1234"},
{name:"john", password:"1234"}]) {
user{
name
}
}
}

Grails unique constraint not working on multiple fields

I've read a lot about uniqueness and constraints in Grails (but maybe not enough)
I can't make the unique constraint to work on multiple fields as explained here:
http://grails.org/doc/1.3.7/ref/Constraints/unique.html
(I'm using grails 1.3.9)
I have 2 domain classes:
class Dog {
static constraints = {
humanSsn(unique: ['name', 'breed'])
//I also tried with just 2 fields, didn't work either.
}
Integer humanSsn
String name
String breed
}
class Human {
static constraints = {
ssn(unique: true)
}
Integer ssn
String name
}
It is a legacy DB, so I cant modify the tables.
When I save a Human, I (just to test) save two dogs with the same name, breed and humanSsn
def humanoInstance = new Humano(params)
if (humanoInstance.save(flush: true)) {
def newDog = new Dog()
def newDogTwo = new Dog()
newDog.name = "n1"
newDog.breed = "b1"
newDog.humanSsn = humanInstance.ssn
println newDog.validate()
println newDog.getErrors()
newDog.save(failOnError:true)
newDogTwo.name = "n1"
newDogTwo.breed = "b1"
newDogTwo.humanSsn = humanInstance.ssn
println newDogTwo.validate()
println newDogTwo.getErrors()
newDogTwo.save(failOnError:true)
}
But it saves anyway the 2 dogs without complaining nor throwing any errors.
true
org.springframework.validation.BeanPropertyBindingResult: 0 error
true
org.springframework.validation.BeanPropertyBindingResult: 0 error
What am I doing wrong?
Thanks in advance.
it may be due to validation works on database level
and newDog.save(failOnError:true) doesnot save dog object immediately
have you try
newDog.save(flush:true)
for first dog and then
newDogTwo.save(failOnError:true)
it should work

There are many similar dao methods in anorm, is it right?

I'm using Play2 with anorm. I think the spirit of anorm is write plain sqls, no magic behind.
But I quickly found I have write a lot of similar dao methods. For example:
case class User(id:Pk[String], username:String, email:String, realname:String, city:String, website:String)
object User {
val simple = get[Pk[String]]("id") ~ get[String]("username") ~ ... get[String]("website") map {
case id ~ username ~ ... ~ website = User(id, username, ..., website)
}
def findByUsername(username:String) = DB.withConnection { implicit connection =>
SQL("select * from users where username={username}").on('username->username).as(simple.singleOpt)
}
def findByEmail(email:String) = DB.withConnection { implicit connection =>
SQL("select * from users where email={email}").on('email->email).as(simple.singleOpt)
}
def findById(id:String) = DB.withConnection { implicit connection =>
SQL("select * from users where id={id}").on('id->id).as(simple.singleOpt)
}
def findByRealname(keyword:String) = DB.withConnection { implicit connection =>
SQL("select * from users where realname like {keyword}").on('keyword->"%"+keyword+"%").as(simple *)
}
// more similar methods
}
There methods are almost the same, exception the where clause has small difference.
So I created a findWhere() method as:
def findWhere(conditon, values:Any*) = ...
That I can call it in actions:
User.findWhere("id=?", id)
User.findWhere("username=?", username)
It works, but I don't think it's recommended by anorm.
What's the best way to solve this problem?
Why do you believe it is not recommended or ok?
Anorm only cares of receiving a SQL query and parsing the result into a case class. If due to your constraints/design you generate that SQL request dinamically, that makes no difference.
The only issue I see is witht he '?' char, which is nto the way Anorm works. I believe it would me more like:
User.findWhere("username", username)
def findWhere(field: String, value: String) = {
SQL("select * from users where "+ field +"={"+ field +"}").on(Symbol(field)->value).as(simple.singleOpt)
}
This is a simple example, extend as required.

Resources