From d746998915df07d65585467c855ebf61f4435f36 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 3 Dec 2019 14:28:27 -0600 Subject: [PATCH 01/62] Not sure how, but somehow I missed the commit that, you know, changed the driver version we use :facepalm: --- build.sbt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index cc5ed16..0567d2e 100644 --- a/build.sbt +++ b/build.sbt @@ -4,8 +4,7 @@ val gatlingVersion = "2.3.0" scalacOptions += "-target:jvm-1.8" -libraryDependencies += "com.datastax.dse" % "dse-java-driver-core" % "1.6.8" -libraryDependencies += "com.datastax.dse" % "dse-java-driver-graph" % "1.6.8" +libraryDependencies += "com.datastax.dse" % "dse-java-driver-core" % "2.3.0" libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "2.18.0" libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.1" libraryDependencies += "org.hdrhistogram" % "HdrHistogram" % "2.1.10" From c1279ecacb98b0cecdc898696c3b08d2981b41e6 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 21 Nov 2019 15:28:19 -0600 Subject: [PATCH 02/62] Picking up some low-hanging fruit, mostly import changes --- src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala | 2 +- .../scala/com/datastax/gatling/plugin/checks/CqlChecks.scala | 2 +- .../com/datastax/gatling/plugin/checks/GenericChecks.scala | 2 +- .../com/datastax/gatling/plugin/checks/GraphChecks.scala | 2 +- .../com/datastax/gatling/plugin/model/DseCqlAttributes.scala | 5 +++-- .../gatling/plugin/model/DseCqlAttributesBuilder.scala | 4 ++-- .../gatling/plugin/model/DseCqlStatementBuilders.scala | 2 +- .../com/datastax/gatling/plugin/model/DseCqlStatements.scala | 3 ++- .../datastax/gatling/plugin/model/DseGraphAttributes.scala | 5 +++-- .../gatling/plugin/model/DseGraphAttributesBuilder.scala | 5 +++-- .../gatling/plugin/model/DseGraphStatementBuilders.scala | 2 +- .../datastax/gatling/plugin/model/DseGraphStatements.scala | 3 +-- .../datastax/gatling/plugin/request/DseRequestActor.scala | 4 ++-- .../com/datastax/gatling/plugin/response/DseResponse.scala | 4 ++-- .../gatling/plugin/response/DseResponseHandler.scala | 4 ++-- .../gatling/plugin/utils/CqlPreparedStatementUtil.scala | 4 ++-- 16 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala b/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala index e1c8863..312201d 100644 --- a/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala +++ b/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala @@ -11,7 +11,7 @@ import java.util.concurrent.atomic.AtomicLong import akka.Done import akka.actor.ActorSystem -import com.datastax.driver.dse.DseSession +import com.datastax.dse.driver.api.core.DseSession import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.request.{CqlRequestActionBuilder, GraphRequestActionBuilder} import com.datastax.gatling.plugin.utils.GatlingTimingSource diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala index 567f533..f4ace84 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.checks -import com.datastax.driver.core.{ResultSet, Row} +import com.datastax.oss.driver.api.core.cql.{ResultSet, Row} import com.datastax.gatling.plugin.response.CqlResponse import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check._ diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala index 13ea365..ef3ea80 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.checks -import com.datastax.driver.core._ +import com.datastax.oss.driver.api.core.cql._ import com.datastax.gatling.plugin.response.DseResponse import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala index d3ed9ac..4d98200 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.checks -import com.datastax.driver.dse.graph._ +import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.response.GraphResponse import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index 455b820..3df1fe2 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -8,8 +8,9 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer -import com.datastax.driver.core.policies.RetryPolicy -import com.datastax.driver.core.{ConsistencyLevel, PagingState, Statement} +import com.datastax.oss.driver.api.core.retry.RetryPolicy +import com.datastax.oss.driver.api.core.{ConsistencyLevel, PagingState} +import com.datastax.oss.driver.api.core.cql.Statement import com.datastax.gatling.plugin.response.{CqlResponse, DseResponse} import io.gatling.core.check.Check diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index b8283ad..3fd8b59 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -6,8 +6,8 @@ package com.datastax.gatling.plugin.model -import com.datastax.driver.core.policies.RetryPolicy -import com.datastax.driver.core.{ConsistencyLevel, PagingState} +import com.datastax.oss.driver.api.core.retry.RetryPolicy +import com.datastax.oss.driver.api.core.{ConsistencyLevel, PagingState} import com.datastax.gatling.plugin.checks.{DseCqlCheck, GenericCheck} import com.datastax.gatling.plugin.request.CqlRequestActionBuilder import io.gatling.core.action.builder.ActionBuilder diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index 1812102..db85bfd 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.driver.core.{PreparedStatement, SimpleStatement} +import com.datastax.oss.driver.api.core.cql.{PreparedStatement, SimpleStatement} import com.datastax.gatling.plugin._ import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.core.session.Expression diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 1561482..3e84053 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -8,7 +8,8 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer -import com.datastax.driver.core._ +import com.datastax.oss.driver.api.core.cql._ +import com.datastax.oss.driver.api.core.`type`.DataType import com.datastax.gatling.plugin.exceptions.DseCqlStatementException import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.commons.validation._ diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index ad1e45f..e26e564 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -6,8 +6,9 @@ package com.datastax.gatling.plugin.model -import com.datastax.driver.core.{ConsistencyLevel, Row} -import com.datastax.driver.dse.graph.{GraphNode, GraphStatement} +import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.cql.Row +import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} /** diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index 427b7e9..6533734 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -6,8 +6,9 @@ package com.datastax.gatling.plugin.model -import com.datastax.driver.core.{ConsistencyLevel, Row} -import com.datastax.driver.dse.graph.GraphNode +import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.cql.Row +import com.datastax.dse.driver.api.core.graph.GraphNode import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} import com.datastax.gatling.plugin.request.GraphRequestActionBuilder import io.gatling.core.action.builder.ActionBuilder diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala index f559562..eca66ce 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.driver.dse.graph.{GraphStatement, SimpleGraphStatement} +import com.datastax.dse.driver.api.core.graph.{GraphStatement, SimpleGraphStatement} import io.gatling.core.session.{Expression, Session} /** diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index af2be96..9c56eec 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -6,8 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.driver.dse.graph.{GraphStatement, SimpleGraphStatement} -import com.datastax.dse.graph.api.DseGraph +import com.datastax.dse.driver.api.core.graph.{DseGraph, GraphStatement, SimpleGraphStatement} import com.datastax.gatling.plugin.exceptions.DseGraphStatementException import io.gatling.commons.validation._ import io.gatling.core.session.{Expression, Session} diff --git a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala index c55c996..125620e 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala @@ -8,8 +8,8 @@ package com.datastax.gatling.plugin.request import akka.actor.Actor -import com.datastax.driver.core.ResultSet -import com.datastax.driver.dse.graph.GraphResultSet +import com.datastax.oss.driver.api.core.cql.ResultSet +import com.datastax.dse.driver.api.core.graph.GraphResultSet import com.google.common.util.concurrent.FutureCallback import com.typesafe.scalalogging.StrictLogging import io.gatling.core.session.Session diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index db03c27..37731db 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -6,8 +6,8 @@ package com.datastax.gatling.plugin.response -import com.datastax.driver.core._ -import com.datastax.driver.dse.graph._ +import com.datastax.oss.driver.api.core.cql._ +import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.typesafe.scalalogging.LazyLogging diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index ebd589e..0a8eb39 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -10,8 +10,8 @@ import java.util.UUID import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem -import com.datastax.driver.core._ -import com.datastax.driver.dse.graph.{GraphProtocol, GraphResultSet, GraphStatement} +import com.datastax.oss.driver.api.core._ +import com.datastax.dse.driver.api.core.graph.{GraphProtocol, GraphResultSet, GraphStatement} import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.datastax.gatling.plugin.utils.{ResponseTime, ResponseTimeBuilder} diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index 9596de1..7c541fe 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -13,8 +13,8 @@ import java.util import java.util.Date import java.util.concurrent.TimeUnit -import com.datastax.driver.core.DataType.Name._ -import com.datastax.driver.core._ +import com.datastax.oss.driver.api.core.`type`.DataType +import com.datastax.oss.driver.api.core.cql._ import com.datastax.driver.dse.geometry._ import com.datastax.driver.dse.geometry.codecs.PointCodec import com.datastax.gatling.plugin.exceptions.CqlTypeException From a83b14618e5ec65e87edb7b7e135141571f25dd2 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 21 Nov 2019 15:38:45 -0600 Subject: [PATCH 03/62] Some more low-hanging fruit, mainly conversions to use the shaded Guava --- .../datastax/gatling/plugin/model/DseGraphAttributes.scala | 2 +- .../gatling/plugin/model/DseGraphAttributesBuilder.scala | 6 +++--- .../datastax/gatling/plugin/request/DseRequestActor.scala | 2 +- .../gatling/plugin/response/DseResponseHandler.scala | 2 +- .../com/datastax/gatling/plugin/utils/FutureUtils.scala | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index e26e564..944809f 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -50,4 +50,4 @@ case class DseGraphAttributes(tag: String, graphSource: Option[String] = None, isSystemQuery: Option[Boolean] = None, graphInternalOptions: Option[Seq[(String, String)]] = None, - graphTransformResults: Option[com.google.common.base.Function[Row, GraphNode]] = None) + graphTransformResults: Option[com.datastax.oss.driver.shaded.guava.common.base.Function[Row, GraphNode]] = None) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index 6533734..9176d9b 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -40,8 +40,8 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * * This permission MUST be granted to the currently logged in user using the CQL statement: `GRANT PROXY.EXECUTE ON * ROLE someRole TO alice`. The user MUST be logged in with - * [[com.datastax.driver.dse.auth.DsePlainTextAuthProvider]] or - * [[com.datastax.driver.dse.auth.DseGSSAPIAuthProvider]] + * [[com.datastax.dse.driver.api.core.auth.DsePlainTextAuthProvider]] or + * [[com.datastax.dse.driver.api.core.auth.DseGSSAPIAuthProvider]] * * @param userOrRole String * @return @@ -130,7 +130,7 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param transform Transform Function * @return */ - def withTransformResults(transform: com.google.common.base.Function[Row, GraphNode]) = { + def withTransformResults(transform: com.datastax.oss.driver.shaded.guava.common.base.Function[Row, GraphNode]) = { DseGraphAttributesBuilder(attr.copy(graphTransformResults = Some(transform))) } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala index 125620e..3b2bc72 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala @@ -10,7 +10,7 @@ package com.datastax.gatling.plugin.request import akka.actor.Actor import com.datastax.oss.driver.api.core.cql.ResultSet import com.datastax.dse.driver.api.core.graph.GraphResultSet -import com.google.common.util.concurrent.FutureCallback +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.FutureCallback import com.typesafe.scalalogging.StrictLogging import io.gatling.core.session.Session diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 0a8eb39..55eeb79 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -15,7 +15,7 @@ import com.datastax.dse.driver.api.core.graph.{GraphProtocol, GraphResultSet, Gr import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.datastax.gatling.plugin.utils.{ResponseTime, ResponseTimeBuilder} -import com.google.common.util.concurrent.FutureCallback +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.FutureCallback import com.typesafe.scalalogging.StrictLogging import io.gatling.commons.stats._ import io.gatling.commons.validation.Failure diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala b/src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala index 8111056..74a2227 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.utils -import com.google.common.util.concurrent.{FutureCallback, Futures, ListenableFuture} +import com.datastax.oss.driver.shaded.guava.common.util.concurrent.{FutureCallback, Futures, ListenableFuture} import scala.concurrent.{Future, Promise} From 3fa0fd447d68b00b15b2148ebfdc3e65732eaa8b Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 25 Nov 2019 09:24:01 -0600 Subject: [PATCH 04/62] Fixing a package rename that was missed in the earlier round --- .../datastax/gatling/plugin/response/DseResponseHandler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 55eeb79..02824c9 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -10,7 +10,7 @@ import java.util.UUID import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem -import com.datastax.oss.driver.api.core._ +import com.datastax.oss.driver.api.core.cql._ import com.datastax.dse.driver.api.core.graph.{GraphProtocol, GraphResultSet, GraphStatement} import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} From ecd60a77a3a2c37af73058d7ecddb6f01717050a Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 25 Nov 2019 09:49:14 -0600 Subject: [PATCH 05/62] Convert usages of Guava's FutureCallback (which aren't actually being used in future-handling code) to a generic callback trait --- .../gatling/plugin/request/DseRequestActor.scala | 4 ++-- .../gatling/plugin/response/DseResponseHandler.scala | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala index 3b2bc72..2736861 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala @@ -10,7 +10,7 @@ package com.datastax.gatling.plugin.request import akka.actor.Actor import com.datastax.oss.driver.api.core.cql.ResultSet import com.datastax.dse.driver.api.core.graph.GraphResultSet -import com.datastax.oss.driver.shaded.guava.common.util.concurrent.FutureCallback +import com.datastax.gatling.plugin.response.SimpleCallback import com.typesafe.scalalogging.StrictLogging import io.gatling.core.session.Session @@ -20,7 +20,7 @@ import scala.util.{Failure, Success, Try} case class SendCqlQuery(dseRequestAction: CqlRequestAction, session: Session) case class SendGraphQuery(dseRequestAction: GraphRequestAction, session: Session) -case class RecordResult[T](t: Try[T], callback: FutureCallback[T]) +case class RecordResult[T](t: Try[T], callback: SimpleCallback[T]) class DseRequestActor extends Actor with StrictLogging { override def receive: Actor.Receive = { diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 02824c9..5c0fb69 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -15,7 +15,6 @@ import com.datastax.dse.driver.api.core.graph.{GraphProtocol, GraphResultSet, Gr import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.datastax.gatling.plugin.utils.{ResponseTime, ResponseTimeBuilder} -import com.datastax.oss.driver.shaded.guava.common.util.concurrent.FutureCallback import com.typesafe.scalalogging.StrictLogging import io.gatling.commons.stats._ import io.gatling.commons.validation.Failure @@ -35,7 +34,13 @@ object DseResponseHandler { .mkString(",") } -abstract class DseResponseHandler[RS, Response <: DseResponse] extends StrictLogging with FutureCallback[RS] { +trait SimpleCallback[RS] { + def onFailure(t: Throwable): Unit + + def onSuccess(result: RS): Unit +} + +abstract class DseResponseHandler[RS, Response <: DseResponse] extends StrictLogging with SimpleCallback[RS] { protected def responseTimeBuilder: ResponseTimeBuilder protected def system: ActorSystem protected def statsEngine: StatsEngine From ce3225b34819d9310cb2d9990dff6bc1a19514b4 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 25 Nov 2019 17:01:33 -0600 Subject: [PATCH 06/62] Trying to fix as much of the base CQL stuff as possible. Big chunks of this are based on/copied wholesale from previous work done by Arthur Landim (https://github.com/datastax/gatling-dse-plugin/pull/17) --- .../plugin/model/DseCqlStatements.scala | 38 ++--- .../utils/CqlPreparedStatementUtil.scala | 159 +++++++++--------- 2 files changed, 98 insertions(+), 99 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 3e84053..d2716da 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -9,19 +9,17 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer import com.datastax.oss.driver.api.core.cql._ -import com.datastax.oss.driver.api.core.`type`.DataType import com.datastax.gatling.plugin.exceptions.DseCqlStatementException import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.commons.validation._ -import io.gatling.core.session.{Session, _} +import io.gatling.core.session._ import scala.collection.JavaConverters._ -import scala.collection.mutable.ArrayBuffer import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseCqlStatement extends DseStatement[Statement] { - def buildFromSession(session: Session): Validation[Statement] +trait DseCqlStatement[T] extends DseStatement[T] { + def buildFromSession(session: Session): Validation[T] } /** @@ -29,7 +27,7 @@ trait DseCqlStatement extends DseStatement[Statement] { * * @param statement the statement to execute */ -case class DseCqlSimpleStatement(statement: SimpleStatement) extends DseCqlStatement { +case class DseCqlSimpleStatement(statement: SimpleStatement) extends DseCqlStatement[SimpleStatement] { def buildFromSession(gatlingSession: Session): Validation[SimpleStatement] = { statement.success } @@ -41,7 +39,7 @@ case class DseCqlSimpleStatement(statement: SimpleStatement) extends DseCqlState * @param preparedStatement the prepared statement on which to bind parameters */ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement) - extends DseCqlStatement { + extends DseCqlStatement[BoundStatement] { def buildFromSession(gatlingSession: Session): Validation[BoundStatement] = bindParams( @@ -58,7 +56,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare * @return */ protected def bindParams(gatlingSession: Session, boundStatement: BoundStatement, - queryParams: Map[String, DataType.Name]): BoundStatement = { + queryParams: Map[String, Int]): BoundStatement = { queryParams.foreach { case (gatlingSessionKey, valType) => cqlTypes.bindParamByName(gatlingSession, boundStatement, valType, gatlingSessionKey) @@ -75,7 +73,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare */ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - params: Expression[AnyRef]*) extends DseCqlStatement { + params: Expression[AnyRef]*) extends DseCqlStatement[BoundStatement] { def buildFromSession(gatlingSession: Session): Validation[BoundStatement] = { val parsedParams: Seq[Validation[AnyRef]] = params.map(param => param(gatlingSession)) @@ -99,7 +97,7 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt */ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - sessionKeys: Seq[String]) extends DseCqlStatement { + sessionKeys: Seq[String]) extends DseCqlStatement[BoundStatement] { /** * Apply the Gatling session params to the Prepared statement @@ -142,16 +140,16 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param statements CQL Prepared Statements */ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, statements: Seq[PreparedStatement]) - extends DseCqlStatement { + extends DseCqlStatement[BatchStatement] { def buildFromSession(gatlingSession: Session): Validation[BatchStatement] = { - val batch = new BatchStatement() + val batch = BatchStatement.builder(DefaultBatchType.LOGGED) statements.foreach(s => - batch.add(bindParams(gatlingSession, s, cqlTypes.getParamsMap(s)))) + batch.addStatement(bindParams(gatlingSession, s, cqlTypes.getParamsMap(s)))) - batch.success + batch.build().success } @@ -164,7 +162,7 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * @return */ protected def bindParams(gatlingSession: Session, statement: PreparedStatement, - queryParams: Map[String, DataType.Name]): BoundStatement = { + queryParams: Map[String, Int]): BoundStatement = { val boundStatement = statement.bind() @@ -185,9 +183,10 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * @param statement SimpleStaten * @param payloadRef session variable for custom payload */ -case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: String) extends DseCqlStatement { +case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: String) + extends DseCqlStatement[SimpleStatement] { - def buildFromSession(gatlingSession: Session): Validation[Statement] = { + def buildFromSession(gatlingSession: Session): Validation[SimpleStatement] = { if (!gatlingSession.contains(payloadRef)) { throw new DseCqlStatementException(s"Passed sessionKey: {$payloadRef} does not exist in Session.") @@ -195,7 +194,7 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: Try { val payload = gatlingSession(payloadRef).as[Map[String, ByteBuffer]].asJava - statement.setOutgoingPayload(payload) + statement.setCustomPayload(payload) } match { case TrySuccess(stmt) => stmt.success case TryFailure(error) => error.getMessage.failure @@ -210,7 +209,8 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: * * @param sessionKey the session key which is associated to a PreparedStatement */ -case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, sessionKey: String) extends DseCqlStatement { +case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, sessionKey: String) + extends DseCqlStatement[BoundStatement] { def buildFromSession(gatlingSession: Session): Validation[BoundStatement] = { if (!gatlingSession.contains(sessionKey)) { diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index 7c541fe..b3aeba5 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -9,16 +9,14 @@ package com.datastax.gatling.plugin.utils import java.math.BigInteger import java.net.InetAddress import java.nio.ByteBuffer +import java.time.{Instant, LocalDate, LocalTime} import java.util -import java.util.Date -import java.util.concurrent.TimeUnit -import com.datastax.oss.driver.api.core.`type`.DataType +import com.datastax.dse.driver.api.core.data.geometry._ import com.datastax.oss.driver.api.core.cql._ -import com.datastax.driver.dse.geometry._ -import com.datastax.driver.dse.geometry.codecs.PointCodec +import com.datastax.oss.protocol.internal.ProtocolConstants.DataType._ import com.datastax.gatling.plugin.exceptions.CqlTypeException -import com.github.nscala_time.time.Imports.DateTime +import com.datastax.oss.driver.api.core.data.{TupleValue, UdtValue} import io.gatling.core.session.Session import scala.collection.JavaConverters._ @@ -31,15 +29,15 @@ trait CqlPreparedStatementUtil { protected val hourMinSecNanoRegEx: Regex = """(\d+):(\d+):(\d+).(\d+{1,9})""".r def bindParamByOrder(gatlingSession: Session, - boundStatement: BoundStatement, paramType: DataType.Name, + boundStatement: BoundStatement, paramType: Int, paramName: String, key: Int): BoundStatement - def bindParamByName(gatlingSession: Session, boundStatement: BoundStatement, paramType: DataType.Name, + def bindParamByName(gatlingSession: Session, boundStatement: BoundStatement, paramType: Int, paramName: String): BoundStatement - def getParamsMap(preparedStatement: PreparedStatement): Map[String, DataType.Name] + def getParamsMap(preparedStatement: PreparedStatement): Map[String, Int] - def getParamsList(preparedStatement: PreparedStatement): List[DataType.Name] + def getParamsList(preparedStatement: PreparedStatement): List[Int] } /** @@ -57,7 +55,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName Gatling Session Attribute Name * @param key Key/Order of param */ - def bindParamByOrder(gatlingSession: Session, boundStatement: BoundStatement, paramType: DataType.Name, + def bindParamByOrder(gatlingSession: Session, boundStatement: BoundStatement, paramType: Int, paramName: String, key: Int): BoundStatement = { if (!gatlingSession.attributes.contains(paramName)) { @@ -67,6 +65,8 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { return boundStatement } + val stringClz = classOf[String] + gatlingSession.attributes.get(paramName) match { case Some(null) => boundStatement.setToNull(paramName) @@ -78,50 +78,50 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { boundStatement case _ => paramType match { - case (VARCHAR | TEXT | ASCII) => + case (VARCHAR | ASCII) => boundStatement.setString(key, asString(gatlingSession, paramName)) case INT => boundStatement.setInt(key, asInteger(gatlingSession, paramName)) case BOOLEAN => - boundStatement.setBool(key, asBoolean(gatlingSession, paramName)) + boundStatement.setBoolean(key, asBoolean(gatlingSession, paramName)) case (UUID | TIMEUUID) => - boundStatement.setUUID(key, asUuid(gatlingSession, paramName)) + boundStatement.setUuid(key, asUuid(gatlingSession, paramName)) case FLOAT => boundStatement.setFloat(key, asFloat(gatlingSession, paramName)) case DOUBLE => boundStatement.setDouble(key, asDouble(gatlingSession, paramName)) case DECIMAL => - boundStatement.setDecimal(key, asDecimal(gatlingSession, paramName)) + boundStatement.setBigDecimal(key, asDecimal(gatlingSession, paramName)) case INET => - boundStatement.setInet(key, asInet(gatlingSession, paramName)) + boundStatement.setInetAddress(key, asInet(gatlingSession, paramName)) case TIMESTAMP => - boundStatement.setTimestamp(key, asTimestamp(gatlingSession, paramName)) + boundStatement.setInstant(key, asInstant(gatlingSession, paramName)) case COUNTER => boundStatement.setLong(key, asCounter(gatlingSession, paramName)) case BIGINT => boundStatement.setLong(key, asBigInt(gatlingSession, paramName)) case BLOB => - boundStatement.setBytes(key, asByte(gatlingSession, paramName)) + boundStatement.setByteBuffer(key, asByte(gatlingSession, paramName)) case VARINT => - boundStatement.setVarint(key, asVarInt(gatlingSession, paramName)) + boundStatement.setBigInteger(key, asVarInt(gatlingSession, paramName)) case LIST => - boundStatement.setList(key, asList(gatlingSession, paramName)) + boundStatement.setList(key, asList(gatlingSession, paramName, stringClz), stringClz) case SET => - boundStatement.setSet(key, asSet(gatlingSession, paramName)) + boundStatement.setSet(key, asSet(gatlingSession, paramName, stringClz), stringClz) case MAP => - boundStatement.setMap(key, asMap(gatlingSession, paramName)) + boundStatement.setMap(key, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) case UDT => - boundStatement.setUDTValue(key, asUdt(gatlingSession, paramName)) + boundStatement.setUdtValue(key, asUdt(gatlingSession, paramName)) case TUPLE => boundStatement.setTupleValue(key, asTuple(gatlingSession, paramName)) case DATE => - boundStatement.setDate(key, asDate(gatlingSession, paramName)) + boundStatement.setLocalDate(key, asLocalDate(gatlingSession, paramName)) case SMALLINT => boundStatement.setShort(key, asSmallInt(gatlingSession, paramName)) case TINYINT => boundStatement.setByte(key, asTinyInt(gatlingSession, paramName)) case TIME => - boundStatement.setTime(key, asTime(gatlingSession, paramName)) + boundStatement.setLocalTime(key, asTime(gatlingSession, paramName)) case CUSTOM => gatlingSession.attributes.get(paramName) match { case Some(p: Point) => @@ -147,7 +147,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramType Type of param ie String, int, boolean * @param paramName Gatling Session Attribute Value */ - def bindParamByName(gatlingSession: Session, boundStatement: BoundStatement, paramType: DataType.Name, + def bindParamByName(gatlingSession: Session, boundStatement: BoundStatement, paramType: Int, paramName: String): BoundStatement = { if (!gatlingSession.attributes.contains(paramName)) { @@ -157,6 +157,8 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { return boundStatement } + val stringClz = classOf[String] + gatlingSession.attributes.get(paramName) match { case Some(null) => boundStatement.setToNull(paramName) @@ -168,50 +170,50 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { boundStatement case _ => paramType match { - case (VARCHAR | TEXT | ASCII) => + case (VARCHAR | ASCII) => boundStatement.setString(paramName, asString(gatlingSession, paramName)) case INT => boundStatement.setInt(paramName, asInteger(gatlingSession, paramName)) case BOOLEAN => - boundStatement.setBool(paramName, asBoolean(gatlingSession, paramName)) + boundStatement.setBoolean(paramName, asBoolean(gatlingSession, paramName)) case (UUID | TIMEUUID) => - boundStatement.setUUID(paramName, asUuid(gatlingSession, paramName)) + boundStatement.setUuid(paramName, asUuid(gatlingSession, paramName)) case FLOAT => boundStatement.setFloat(paramName, asFloat(gatlingSession, paramName)) case DOUBLE => boundStatement.setDouble(paramName, asDouble(gatlingSession, paramName)) case DECIMAL => - boundStatement.setDecimal(paramName, asDecimal(gatlingSession, paramName)) + boundStatement.setBigDecimal(paramName, asDecimal(gatlingSession, paramName)) case INET => - boundStatement.setInet(paramName, asInet(gatlingSession, paramName)) + boundStatement.setInetAddress(paramName, asInet(gatlingSession, paramName)) case TIMESTAMP => - boundStatement.setTimestamp(paramName, asTimestamp(gatlingSession, paramName)) + boundStatement.setInstant(paramName, asInstant(gatlingSession, paramName)) case BIGINT => boundStatement.setLong(paramName, asBigInt(gatlingSession, paramName)) case COUNTER => boundStatement.setLong(paramName, asCounter(gatlingSession, paramName)) case BLOB => - boundStatement.setBytes(paramName, asByte(gatlingSession, paramName)) + boundStatement.setByteBuffer(paramName, asByte(gatlingSession, paramName)) case VARINT => - boundStatement.setVarint(paramName, asVarInt(gatlingSession, paramName)) + boundStatement.setBigInteger(paramName, asVarInt(gatlingSession, paramName)) case LIST => - boundStatement.setList(paramName, asList(gatlingSession, paramName)) + boundStatement.setList(paramName, asList(gatlingSession, paramName, stringClz), stringClz) case SET => - boundStatement.setSet(paramName, asSet(gatlingSession, paramName)) + boundStatement.setSet(paramName, asSet(gatlingSession, paramName, stringClz), stringClz) case MAP => - boundStatement.setMap(paramName, asMap(gatlingSession, paramName)) + boundStatement.setMap(paramName, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) case UDT => - boundStatement.setUDTValue(paramName, asUdt(gatlingSession, paramName)) + boundStatement.setUdtValue(paramName, asUdt(gatlingSession, paramName)) case TUPLE => boundStatement.setTupleValue(paramName, asTuple(gatlingSession, paramName)) case DATE => - boundStatement.setDate(paramName, asDate(gatlingSession, paramName)) + boundStatement.setLocalDate(paramName, asLocalDate(gatlingSession, paramName)) case SMALLINT => boundStatement.setShort(paramName, asSmallInt(gatlingSession, paramName)) case TINYINT => boundStatement.setByte(paramName, asTinyInt(gatlingSession, paramName)) case TIME => - boundStatement.setTime(paramName, asTime(gatlingSession, paramName)) + boundStatement.setLocalTime(paramName, asTime(gatlingSession, paramName)) case CUSTOM => gatlingSession.attributes.get(paramName) match { case Some(p: Point) => @@ -236,10 +238,10 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param preparedStatement CQL Prepared Stated * @return */ - def getParamsMap(preparedStatement: PreparedStatement): Map[String, DataType.Name] = { - val paramVariables = preparedStatement.getVariables + def getParamsMap(preparedStatement: PreparedStatement): Map[String, Int] = { + val paramVariables = preparedStatement.getVariableDefinitions val paramIterator = paramVariables.iterator.asScala - paramIterator.map(p => (p.getName, p.getType.getName)).toMap + paramIterator.map(p => (p.getName.asCql(true), p.getType.getProtocolCode)).toMap } @@ -249,9 +251,9 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param preparedStatement CQL Prepared Stated * @return */ - def getParamsList(preparedStatement: PreparedStatement): List[DataType.Name] = { - val paramVariables = preparedStatement.getVariables - paramVariables.iterator.asScala.map(p => p.getType.getName).toList + def getParamsList(preparedStatement: PreparedStatement): List[Int] = { + val paramVariables = preparedStatement.getVariableDefinitions + paramVariables.iterator.asScala.map(p => p.getType.getProtocolCode).toList } @@ -484,16 +486,16 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asTimestamp(gatlingSession: Session, paramName: String): java.util.Date = { + def asInstant(gatlingSession: Session, paramName: String): Instant = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { case Some(l: Long) => - new Date(l) + Instant.ofEpochMilli(l) case Some(s: String) => - DateTime.parse(s).toDate - case Some(d: Date) => - d + Instant.parse(s) + case Some(i: Instant) => + i case _ => - throw new CqlTypeException(s"$paramName expected to be type of Long, String or java.util.Date") + throw new CqlTypeException(s"$paramName expected to be type of Long, String or java.time.Instant") } } @@ -507,13 +509,13 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asSet(gatlingSession: Session, paramName: String): util.Set[Any] = { + def asSet[T](gatlingSession: Session, paramName: String, elementType: Class[T]): util.Set[T] = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { - case Some(m: Set[Any]@unchecked) => + case Some(m: Set[T]@unchecked) => m.asJava - case Some(s: Seq[Any]@unchecked) => + case Some(s: Seq[T]@unchecked) => s.toSet.asJava - case Some(s: util.Set[Any]@unchecked) => + case Some(s: util.Set[T]@unchecked) => s case _ => throw new CqlTypeException(s"$paramName expected to be type of Set") @@ -530,13 +532,13 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asList(gatlingSession: Session, paramName: String): util.List[Any] = { + def asList[T](gatlingSession: Session, paramName: String, elementType: Class[T]): util.List[T] = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { - case Some(m: List[Any]@unchecked) => + case Some(m: List[T]@unchecked) => m.asJava - case Some(s: Seq[Any]@unchecked) => + case Some(s: Seq[T]@unchecked) => s.toList.asJava - case Some(l: util.List[Any]@unchecked) => + case Some(l: util.List[T]@unchecked) => l case _ => throw new CqlTypeException(s"$paramName expected to be type of List") @@ -553,11 +555,11 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asMap(gatlingSession: Session, paramName: String): util.Map[Any, Any] = { + def asMap[K,V](gatlingSession: Session, paramName: String, keyType: Class[K], valType: Class[V]): util.Map[K,V] = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { - case Some(m: Map[Any, Any]@unchecked) => + case Some(m: Map[K,V]@unchecked) => m.asJava - case Some(mj: util.Map[Any, Any]@unchecked) => + case Some(mj: util.Map[K,V]@unchecked) => mj case _ => throw new CqlTypeException(s"$paramName expected to be type of Set") @@ -695,10 +697,12 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asTime(gatlingSession: Session, paramName: String): Long = { + def asTime(gatlingSession: Session, paramName: String): LocalTime = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { - case Some(l: Long) => + case Some(l: LocalTime) => l + case Some(l: Long) => + LocalTime.ofNanoOfDay(l) case Some(s: String) => s.trim match { case hourMinSecNanoRegEx(hour, min, second, nano) => parseTime(paramName, hour, min, second, nano) @@ -711,7 +715,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { } private def parseTime(paramName: String, hourStr: String, minStr: String, - secStr: String, nanoStr: String = null) = { + secStr: String, nanoStr: String = null): LocalTime = { val hour = Integer.parseInt(hourStr) val min = Integer.parseInt(minStr) @@ -740,13 +744,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { throw new CqlTypeException(s"$paramName Seconds out of bounds.") } - var rawTime: Long = 0 - rawTime += TimeUnit.HOURS.toNanos(hour) - rawTime += TimeUnit.MINUTES.toNanos(min) - rawTime += TimeUnit.SECONDS.toNanos(sec) - rawTime += nanos - - rawTime + LocalTime.of(hour, min, sec, nanos) } @@ -761,16 +759,16 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asDate(gatlingSession: Session, paramName: String): com.datastax.driver.core.LocalDate = { + def asLocalDate(gatlingSession: Session, paramName: String): LocalDate = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { case Some(s: String) => val dateSplit = s.split("-").toList - LocalDate.fromYearMonthDay(dateSplit.head.toInt, dateSplit(1).toInt, dateSplit(2).toInt) + LocalDate.of(dateSplit.head.toInt, dateSplit(1).toInt, dateSplit(2).toInt) case Some(l: Long) => - LocalDate.fromMillisSinceEpoch(l) + LocalDate.ofEpochDay(l) case Some(i: Int) => - LocalDate.fromDaysSinceEpoch(i) - case Some(ld: com.datastax.driver.core.LocalDate) => + LocalDate.ofEpochDay(i) + case Some(ld: LocalDate) => ld case _ => throw new CqlTypeException(s"$paramName expected to be type of String, Long, Int or LocalDate") @@ -807,11 +805,12 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asUdt(gatlingSession: Session, paramName: String): UDTValue = { + def asUdt(gatlingSession: Session, paramName: String): UdtValue = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { - case Some(udt: UDTValue) => + case Some(udt: UdtValue) => udt case _ => + throw new CqlTypeException(s"$paramName expected to be type of UDTValue") } } From f365d98def5ef9b26219a7e4691578654c0275cc Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 26 Nov 2019 09:18:44 -0600 Subject: [PATCH 07/62] Added explicit bounded Statement type to DseCqlAttributes. This type propogates through the statement/attribute level but doesn't make it up to the action level (since the actions don't seem to care about the underlying Statement type their executing... or at least they don't so far). --- .../com/datastax/gatling/plugin/Predef.scala | 2 +- .../plugin/model/DseCqlAttributes.scala | 4 +-- .../model/DseCqlAttributesBuilder.scala | 2 +- .../model/DseCqlStatementBuilders.scala | 31 ++++++++++--------- .../plugin/request/CqlRequestAction.scala | 2 +- .../request/CqlRequestActionBuilder.scala | 2 +- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/Predef.scala b/src/main/scala/com/datastax/gatling/plugin/Predef.scala index ac3f89f..228a254 100644 --- a/src/main/scala/com/datastax/gatling/plugin/Predef.scala +++ b/src/main/scala/com/datastax/gatling/plugin/Predef.scala @@ -36,7 +36,7 @@ trait DsePredefBase extends DseCheckSupport { implicit def protocolBuilder2DseProtocol(builder: DseProtocolBuilder): DseProtocol = builder.build - implicit def cqlRequestAttributes2ActionBuilder(builder: DseCqlAttributesBuilder): ActionBuilder = builder.build() + implicit def cqlRequestAttributes2ActionBuilder(builder: DseCqlAttributesBuilder[_]): ActionBuilder = builder.build() implicit def graphRequestAttributes2ActionBuilder(builder: DseGraphAttributesBuilder): ActionBuilder = builder.build() } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index 3df1fe2..b84acd2 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -37,8 +37,8 @@ import io.gatling.core.check.Check * @param cqlStatements String version of the CQL statement that is sent * */ -case class DseCqlAttributes(tag: String, - statement: DseStatement[Statement], +case class DseCqlAttributes[T <: Statement[_]](tag: String, + statement: DseStatement[T], cl: Option[ConsistencyLevel] = None, cqlChecks: List[Check[CqlResponse]] = List.empty, genericChecks: List[Check[DseResponse]] = List.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 3fd8b59..30600fd 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -18,7 +18,7 @@ import io.gatling.core.action.builder.ActionBuilder * * @param attr Addition Attributes */ -case class DseCqlAttributesBuilder(attr: DseCqlAttributes) { +case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { /** * Builds to final action to run * diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index db85bfd..8467811 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.oss.driver.api.core.cql.{PreparedStatement, SimpleStatement} +import com.datastax.oss.driver.api.core.cql.{BatchStatement, BoundStatement, PreparedStatement, SimpleStatement, SimpleStatementBuilder} import com.datastax.gatling.plugin._ import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.core.session.Expression @@ -29,7 +29,7 @@ case class DseCqlStatementBuilder(tag: String) { * @return */ @deprecated("Replaced by executeStatement(String)") - def executeCql(query: String): DseCqlAttributesBuilder = + def executeCql(query: String): DseCqlAttributesBuilder[SimpleStatement] = executeStatement(query) /** @@ -38,8 +38,8 @@ case class DseCqlStatementBuilder(tag: String) { * @param query Simple string query * @return */ - def executeStatement(query: String): DseCqlAttributesBuilder = - executeStatement(new SimpleStatement(query)) + def executeStatement(query: String): DseCqlAttributesBuilder[SimpleStatement] = + executeStatement(new SimpleStatementBuilder(query).build) /** * Execute a Simple Statement @@ -47,7 +47,7 @@ case class DseCqlStatementBuilder(tag: String) { * @param statement SimpleStatement * @return */ - def executeStatement(statement: SimpleStatement): DseCqlAttributesBuilder = + def executeStatement(statement: SimpleStatement): DseCqlAttributesBuilder[SimpleStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -90,7 +90,7 @@ case class DseCqlStatementBuilder(tag: String) { * * @param preparedStatement CQL Prepared statement with named parameters */ - def executeNamed(preparedStatement: PreparedStatement): DseCqlAttributesBuilder = + def executeNamed(preparedStatement: PreparedStatement): DseCqlAttributesBuilder[BoundStatement] = DsePreparedCqlStatementBuilder(tag, preparedStatement).withSessionParams() /** @@ -98,11 +98,12 @@ case class DseCqlStatementBuilder(tag: String) { * * @param preparedStatements Array of prepared statements */ - def executePreparedBatch(preparedStatements: Array[PreparedStatement]) = DseCqlAttributesBuilder( - DseCqlAttributes( - tag, - DseCqlBoundBatchStatement(CqlPreparedStatementUtil, preparedStatements), - cqlStatements = preparedStatements.map(_.getQueryString) + def executePreparedBatch(preparedStatements: Array[PreparedStatement]) = + DseCqlAttributesBuilder( + DseCqlAttributes( + tag, + DseCqlBoundBatchStatement(CqlPreparedStatementUtil, preparedStatements), + cqlStatements = preparedStatements.map(_.getQueryString) ) ) @@ -113,14 +114,14 @@ case class DseCqlStatementBuilder(tag: String) { * @param payloadSessionKey Session key of the payload from session/feed * @return */ - def executeCustomPayload(statement: SimpleStatement, payloadSessionKey: String): DseCqlAttributesBuilder = + def executeCustomPayload(statement: SimpleStatement, payloadSessionKey: String): DseCqlAttributesBuilder[SimpleStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, DseCqlCustomPayloadStatement(statement, payloadSessionKey), cqlStatements = Seq(statement.getQueryString))) - def executePreparedFromSession(key: String): DseCqlAttributesBuilder = + def executePreparedFromSession(key: String): DseCqlAttributesBuilder[SimpleStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -140,7 +141,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * * @return */ - def withSessionParams(): DseCqlAttributesBuilder = + def withSessionParams(): DseCqlAttributesBuilder[BoundStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -153,7 +154,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * @param params Gatling Session variables * @return */ - def withParams(params: Expression[AnyRef]*): DseCqlAttributesBuilder = + def withParams(params: Expression[AnyRef]*): DseCqlAttributesBuilder[BoundStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index bbf630a..0a046d6 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -49,7 +49,7 @@ class CqlRequestAction(val name: String, val system: ActorSystem, val statsEngine: StatsEngine, val protocol: DseProtocol, - val dseAttributes: DseCqlAttributes, + val dseAttributes: DseCqlAttributes[_], val metricsLogger: MetricsLogger, val dseExecutorService: ExecutorService, val gatlingTimingSource: GatlingTimingSource) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala index 455d1bd..af0a9a6 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala @@ -13,7 +13,7 @@ import io.gatling.core.action.builder.ActionBuilder import io.gatling.core.structure.ScenarioContext import io.gatling.core.util.NameGen -class CqlRequestActionBuilder(val dseAttributes: DseCqlAttributes) extends ActionBuilder with +class CqlRequestActionBuilder(val dseAttributes: DseCqlAttributes[_]) extends ActionBuilder with NameGen { def build(ctx: ScenarioContext, next: Action): Action = { From 192d7bf1ebbcb42033b561ebc253b3bb20ce37c2 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 26 Nov 2019 09:22:53 -0600 Subject: [PATCH 08/62] A few minor fixes --- .../plugin/model/DseCqlStatementBuilders.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index 8467811..ef7a902 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.oss.driver.api.core.cql.{BatchStatement, BoundStatement, PreparedStatement, SimpleStatement, SimpleStatementBuilder} +import com.datastax.oss.driver.api.core.cql.{BoundStatement, PreparedStatement, SimpleStatement, SimpleStatementBuilder} import com.datastax.gatling.plugin._ import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.core.session.Expression @@ -52,7 +52,7 @@ case class DseCqlStatementBuilder(tag: String) { DseCqlAttributes( tag, DseCqlSimpleStatement(statement), - cqlStatements = Seq(statement.getQueryString)) + cqlStatements = Seq(statement.getQuery)) ) /** @@ -103,7 +103,7 @@ case class DseCqlStatementBuilder(tag: String) { DseCqlAttributes( tag, DseCqlBoundBatchStatement(CqlPreparedStatementUtil, preparedStatements), - cqlStatements = preparedStatements.map(_.getQueryString) + cqlStatements = preparedStatements.map(_.getQuery) ) ) @@ -119,7 +119,7 @@ case class DseCqlStatementBuilder(tag: String) { DseCqlAttributes( tag, DseCqlCustomPayloadStatement(statement, payloadSessionKey), - cqlStatements = Seq(statement.getQueryString))) + cqlStatements = Seq(statement.getQuery))) def executePreparedFromSession(key: String): DseCqlAttributesBuilder[SimpleStatement] = DseCqlAttributesBuilder( @@ -146,7 +146,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme DseCqlAttributes( tag, DseCqlBoundStatementNamed(CqlPreparedStatementUtil, prepared), - cqlStatements = Seq(prepared.getQueryString))) + cqlStatements = Seq(prepared.getQuery))) /** * Bind Gatling Session Values to CQL Prepared Statement @@ -159,7 +159,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme DseCqlAttributes( tag, DseCqlBoundStatementWithPassedParams(CqlPreparedStatementUtil, prepared, params: _*), - cqlStatements = Seq(prepared.getQueryString)) + cqlStatements = Seq(prepared.getQuery)) ) /** @@ -173,6 +173,6 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme DseCqlAttributes( tag, DseCqlBoundStatementWithParamList(CqlPreparedStatementUtil, prepared, sessionKeys), - cqlStatements = Seq(prepared.getQueryString)) + cqlStatements = Seq(prepared.getQuery)) ) } From 191524666ffcf6f9e455282d1c07746c673677d4 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 26 Nov 2019 11:27:02 -0600 Subject: [PATCH 09/62] Cleaning up PagingState references, a few other minor cleanups --- .../gatling/plugin/checks/GenericChecks.scala | 4 +- .../plugin/model/DseCqlAttributes.scala | 4 +- .../model/DseCqlAttributesBuilder.scala | 59 ++++++++++++------- .../gatling/plugin/response/DseResponse.scala | 4 +- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala index ef3ea80..01f4bb8 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala @@ -6,6 +6,8 @@ package com.datastax.gatling.plugin.checks +import java.nio.ByteBuffer + import com.datastax.oss.driver.api.core.cql._ import com.datastax.gatling.plugin.response.DseResponse import io.gatling.commons.validation.{SuccessWrapper, Validation} @@ -79,7 +81,7 @@ object GenericChecks { .toCheckBuilder val pagingState = - new GenericResponseExtractor[PagingState]( + new GenericResponseExtractor[ByteBuffer]( "pagingState", r => r.pagingState()) .toCheckBuilder diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index b84acd2..96321a0 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -9,7 +9,7 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer import com.datastax.oss.driver.api.core.retry.RetryPolicy -import com.datastax.oss.driver.api.core.{ConsistencyLevel, PagingState} +import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Statement import com.datastax.gatling.plugin.response.{CqlResponse, DseResponse} import io.gatling.core.check.Check @@ -51,5 +51,5 @@ case class DseCqlAttributes[T <: Statement[_]](tag: String, serialCl: Option[ConsistencyLevel] = None, fetchSize: Option[Int] = None, retryPolicy: Option[RetryPolicy] = None, - pagingState: Option[PagingState] = None, + pagingState: Option[ByteBuffer] = None, cqlStatements: Seq[String] = Seq.empty) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 30600fd..8967a18 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -6,11 +6,13 @@ package com.datastax.gatling.plugin.model +import java.nio.ByteBuffer + import com.datastax.oss.driver.api.core.retry.RetryPolicy -import com.datastax.oss.driver.api.core.{ConsistencyLevel, PagingState} +import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.gatling.plugin.checks.{DseCqlCheck, GenericCheck} import com.datastax.gatling.plugin.request.CqlRequestActionBuilder -import io.gatling.core.action.builder.ActionBuilder +import com.datastax.oss.driver.api.core.cql.Statement /** @@ -18,7 +20,7 @@ import io.gatling.core.action.builder.ActionBuilder * * @param attr Addition Attributes */ -case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { +case class DseCqlAttributesBuilder[T <: Statement[_]](attr: DseCqlAttributes[T]) { /** * Builds to final action to run * @@ -32,20 +34,22 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @param level ConsistencyLevel * @return */ - def withConsistencyLevel(level: ConsistencyLevel) = DseCqlAttributesBuilder(attr.copy(cl = Some(level))) + def withConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(cl = Some(level))) /** * Execute a query as another user or another role, provided the current logged in user has PROXY.EXECUTE permission. * * This permission MUST be granted to the currently logged in user using the CQL statement: `GRANT PROXY.EXECUTE ON * ROLE someRole TO alice`. The user MUST be logged in with - * [[com.datastax.driver.dse.auth.DsePlainTextAuthProvider]] or - * [[com.datastax.driver.dse.auth.DseGSSAPIAuthProvider]] + * [[com.datastax.dse.driver.api.core.auth.DsePlainTextAuthProviderBase]] or + * [[com.datastax.dse.driver.api.core.auth.DseGssApiAuthProviderBase]] * * @param userOrRole String * @return */ - def withUserOrRole(userOrRole: String) = DseCqlAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) + def withUserOrRole(userOrRole: String):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) /** * Override the current system time for write time of query @@ -53,7 +57,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @param epochTsInMs timestamp to use * @return */ - def withDefaultTimestamp(epochTsInMs: Long) = DseCqlAttributesBuilder(attr.copy(defaultTimestamp = Some(epochTsInMs))) + def withDefaultTimestamp(epochTsInMs: Long):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(defaultTimestamp = Some(epochTsInMs))) /** @@ -61,7 +66,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * * @return */ - def withIdempotency() = DseCqlAttributesBuilder(attr.copy(idempotent = Some(true))) + def withIdempotency():DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(idempotent = Some(true))) /** @@ -70,7 +76,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @param readTimeoutInMs time in milliseconds * @return */ - def withReadTimeout(readTimeoutInMs: Int) = DseCqlAttributesBuilder(attr.copy(readTimeout = Some(readTimeoutInMs))) + def withReadTimeout(readTimeoutInMs: Int):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(readTimeout = Some(readTimeoutInMs))) /** @@ -79,16 +86,18 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @param level ConsistencyLevel * @return */ - def withSerialConsistencyLevel(level: ConsistencyLevel) = DseCqlAttributesBuilder(attr.copy(serialCl = Some(level))) + def withSerialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(serialCl = Some(level))) /** - * Define the [[com.datastax.driver.core.policies.RetryPolicy]] to be used for query + * Define the [[com.datastax.oss.driver.api.core.retry.RetryPolicy]] to be used for query * * @param retryPolicy DataStax drivers retry policy * @return */ - def withRetryPolicy(retryPolicy: RetryPolicy) = DseCqlAttributesBuilder(attr.copy(retryPolicy = Some(retryPolicy))) + def withRetryPolicy(retryPolicy: RetryPolicy):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(retryPolicy = Some(retryPolicy))) /** * Set fetchSize of query for paging @@ -96,7 +105,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @param rowCnt number of rows to fetch at one time * @return */ - def withFetchSize(rowCnt: Int) = DseCqlAttributesBuilder(attr.copy(fetchSize = Some(rowCnt))) + def withFetchSize(rowCnt: Int):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(fetchSize = Some(rowCnt))) /** @@ -104,7 +114,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * * @return */ - def withTracingEnabled() = DseCqlAttributesBuilder(attr.copy(enableTrace = Some(true))) + def withTracingEnabled():DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(enableTrace = Some(true))) /** @@ -113,7 +124,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @param pagingState CQL Paging state * @return */ - def withPagingState(pagingState: PagingState) = DseCqlAttributesBuilder(attr.copy(pagingState = Some(pagingState))) + def withPagingState(pagingState: ByteBuffer):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(pagingState = Some(pagingState))) /** @@ -123,7 +135,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @return */ @deprecated("Replaced by withSerialConsistencyLevel") - def serialConsistencyLevel(level: ConsistencyLevel) = withSerialConsistencyLevel(level) + def serialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + withSerialConsistencyLevel(level) /** @@ -134,7 +147,8 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @return */ @deprecated("Replaced by withConsistencyLevel") - def consistencyLevel(level: ConsistencyLevel) = withConsistencyLevel(level) + def consistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + withConsistencyLevel(level) /** @@ -145,9 +159,12 @@ case class DseCqlAttributesBuilder[T](attr: DseCqlAttributes[T]) { * @return */ @deprecated("Replaced by withUserOrRole") - def executeAs(userOrRole: String) = withUserOrRole(userOrRole: String) + def executeAs(userOrRole: String):DseCqlAttributesBuilder[T] = + withUserOrRole(userOrRole: String) - def check(check: DseCqlCheck) = DseCqlAttributesBuilder(attr.copy(cqlChecks = check :: attr.cqlChecks)) + def check(check: DseCqlCheck):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(cqlChecks = check :: attr.cqlChecks)) - def check(check: GenericCheck) = DseCqlAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) + def check(check: GenericCheck):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) } diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 37731db..13eeaff 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -6,6 +6,8 @@ package com.datastax.gatling.plugin.response +import java.nio.ByteBuffer + import com.datastax.oss.driver.api.core.cql._ import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} @@ -22,7 +24,7 @@ abstract class DseResponse { def queriedHost(): Host = executionInfo().getQueriedHost def achievedConsistencyLevel(): ConsistencyLevel = executionInfo().getAchievedConsistencyLevel def speculativeExecutions(): Int = executionInfo().getSpeculativeExecutions - def pagingState(): PagingState = executionInfo().getPagingState + def pagingState(): ByteBuffer = executionInfo().getPagingState def triedHosts(): List[Host] = executionInfo().getTriedHosts.asScala.toList def warnings(): List[String] = executionInfo().getWarnings.asScala.toList def successFullExecutionIndex(): Int = executionInfo().getSuccessfulExecutionIndex From da75ad13afdfd0dbbd33ab0b64214a64b53327a5 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 26 Nov 2019 15:27:43 -0600 Subject: [PATCH 10/62] A few miscellaneous fixes --- .../gatling/plugin/checks/GenericChecks.scala | 3 ++- .../plugin/model/DseCqlStatementBuilders.scala | 2 +- .../gatling/plugin/response/DseResponse.scala | 11 ++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala index 01f4bb8..efa649e 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala @@ -8,8 +8,9 @@ package com.datastax.gatling.plugin.checks import java.nio.ByteBuffer -import com.datastax.oss.driver.api.core.cql._ import com.datastax.gatling.plugin.response.DseResponse +import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.cql._ import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} import io.gatling.core.check._ diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index ef7a902..1a86203 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -121,7 +121,7 @@ case class DseCqlStatementBuilder(tag: String) { DseCqlCustomPayloadStatement(statement, payloadSessionKey), cqlStatements = Seq(statement.getQuery))) - def executePreparedFromSession(key: String): DseCqlAttributesBuilder[SimpleStatement] = + def executePreparedFromSession(key: String): DseCqlAttributesBuilder[BoundStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 13eeaff..1c85d11 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -8,9 +8,10 @@ package com.datastax.gatling.plugin.response import java.nio.ByteBuffer +import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} +import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql._ import com.datastax.dse.driver.api.core.graph._ -import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.typesafe.scalalogging.LazyLogging import scala.collection.JavaConverters._ @@ -23,7 +24,7 @@ abstract class DseResponse { def exhausted(): Boolean def queriedHost(): Host = executionInfo().getQueriedHost def achievedConsistencyLevel(): ConsistencyLevel = executionInfo().getAchievedConsistencyLevel - def speculativeExecutions(): Int = executionInfo().getSpeculativeExecutions + def speculativeExecutions(): Int = executionInfo().getSpeculativeExecutionCount def pagingState(): ByteBuffer = executionInfo().getPagingState def triedHosts(): List[Host] = executionInfo().getTriedHosts.asScala.toList def warnings(): List[String] = executionInfo().getWarnings.asScala.toList @@ -106,12 +107,12 @@ class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttri def getDseAttributes: DseGraphAttributes = dseAttributes } -class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes) extends DseResponse with LazyLogging { +class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes[_]) extends DseResponse with LazyLogging { private lazy val allCqlRows: Seq[Row] = collection.JavaConverters.asScalaBuffer(cqlResultSet.all()) override def executionInfo(): ExecutionInfo = cqlResultSet.getExecutionInfo() override def applied(): Boolean = cqlResultSet.wasApplied() - override def exhausted(): Boolean = cqlResultSet.isExhausted() + override def exhausted(): Boolean = cqlResultSet.isFullyFetched && (cqlResultSet.getAvailableWithoutFetching == 0) /** * Get the number of all rows returned by the query. @@ -150,5 +151,5 @@ class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes) exte allCqlRows.map(row => row.getObject(column)) } - def getDseAttributes: DseCqlAttributes = dseAttributes + def getDseAttributes: DseCqlAttributes[_] = dseAttributes } From cff2478befae14a76509c140f79fcb3161036579 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 26 Nov 2019 17:00:05 -0600 Subject: [PATCH 11/62] Removed unavailable methods for accessing tried and queried hosts and replaced with accessor for coordinator node. Also cleaned up a fair amount of DseResponse. --- .../gatling/plugin/checks/CqlChecks.scala | 8 +- .../plugin/checks/DseCheckSupport.scala | 4 +- .../gatling/plugin/checks/GenericChecks.scala | 27 ++--- .../gatling/plugin/checks/GraphChecks.scala | 6 +- .../gatling/plugin/response/DseResponse.scala | 107 ++++++------------ 5 files changed, 49 insertions(+), 103 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala index f4ace84..b2dd67f 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala @@ -57,17 +57,17 @@ private abstract class ColumnValueExtractor[X] extends CriterionExtractor[CqlRes private class SingleColumnValueExtractor(val criterion: String, val occurrence: Int) extends ColumnValueExtractor[Any] with FindArity { def extract(response: CqlResponse): Validation[Option[Any]] = - response.getCqlResultColumnValues(criterion).lift(occurrence).success + response.getColumnValSeq(criterion).lift(occurrence).success } private class MultipleColumnValueExtractor(val criterion: String) extends ColumnValueExtractor[Seq[Any]] with FindAllArity { def extract(response: CqlResponse): Validation[Option[Seq[Any]]] = - response.getCqlResultColumnValues(criterion).liftSeqOption.success + response.getColumnValSeq(criterion).liftSeqOption.success } private class CountColumnValueExtractor(val criterion: String) extends ColumnValueExtractor[Int] with CountArity { def extract(response: CqlResponse): Validation[Option[Int]] = - response.getCqlResultColumnValues(criterion).liftSeqOption.map(_.size).success + response.getColumnValSeq(criterion).liftSeqOption.map(_.size).success } object CqlChecks { @@ -80,7 +80,7 @@ object CqlChecks { val allRows = new CqlResponseExtractor[Seq[Row]]( "allRows", - r => r.getAllRows) + r => r.getAllRowsSeq) .toCheckBuilder val oneRow = diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala index fe0e808..453e70f 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala @@ -17,13 +17,11 @@ trait DseCheckSupport { // execution info and subsets lazy val executionInfo = GenericChecks.executionInfo - lazy val achievedCL = GenericChecks.achievedConsistencyLevel lazy val pagingState = GenericChecks.pagingState - lazy val queriedHost = GenericChecks.queriedHost lazy val schemaAgreement = GenericChecks.schemaInAgreement lazy val successfulExecutionIndex = GenericChecks.successfulExecutionIndex - lazy val triedHosts = GenericChecks.triedHosts lazy val warnings = GenericChecks.warnings + lazy val coordinator = GenericChecks.coordinator // start CQL only checks lazy val resultSet = CqlChecks.resultSet diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala index efa649e..690d902 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala @@ -11,6 +11,7 @@ import java.nio.ByteBuffer import com.datastax.gatling.plugin.response.DseResponse import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql._ +import com.datastax.oss.driver.api.core.metadata.Node import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} import io.gatling.core.check._ @@ -63,18 +64,6 @@ object GenericChecks { r => r.executionInfo()) .toCheckBuilder - val queriedHost = - new GenericResponseExtractor[Host]( - "queriedHost", - r => r.queriedHost()) - .toCheckBuilder - - val achievedConsistencyLevel = - new GenericResponseExtractor[ConsistencyLevel]( - "achievedConsistencyLevel", - r => r.achievedConsistencyLevel()) - .toCheckBuilder - val speculativeExecutionsExtractor = new GenericResponseExtractor[Int]( "speculativeExecutions", @@ -87,12 +76,6 @@ object GenericChecks { r => r.pagingState()) .toCheckBuilder - val triedHosts = - new GenericResponseExtractor[List[Host]]( - "triedHost", - r => r.triedHosts()) - .toCheckBuilder - val warnings = new GenericResponseExtractor[List[String]]( "warnings", @@ -124,9 +107,15 @@ object GenericChecks { .toCheckBuilder val exhausted = - new GenericResponseExtractor[Boolean]( + new GenericResponseExtractor[Option[Boolean]]( "exhausted", r => r.exhausted()) .toCheckBuilder + + val coordinator = + new GenericResponseExtractor[Node]( + "queriedHost", + r => r.coordinator()) + .toCheckBuilder } diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala index 4d98200..14d9cba 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala @@ -12,6 +12,8 @@ import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} import io.gatling.core.check._ import io.gatling.core.session.{Expression, ExpressionSuccessWrapper, Session} +import org.apache.tinkerpop.gremlin.process.traversal.Path +import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} import scala.collection.mutable @@ -89,13 +91,13 @@ object GraphChecks { .toCheckBuilder def properties(column: String) = - new GraphResponseExtractor[Seq[Property]]( + new GraphResponseExtractor[Seq[Property[_]]]( "properties", r => r.getProperties(column)) .toCheckBuilder def vertexProperties(column: String) = - new GraphResponseExtractor[Seq[Property]]( + new GraphResponseExtractor[Seq[VertexProperty[_]]]( "vertexProperties", r => r.getVertexProperties(column)) .toCheckBuilder diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 1c85d11..a6a556b 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -9,36 +9,35 @@ package com.datastax.gatling.plugin.response import java.nio.ByteBuffer import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} -import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql._ import com.datastax.dse.driver.api.core.graph._ +import com.datastax.oss.driver.api.core.metadata.Node import com.typesafe.scalalogging.LazyLogging +import org.apache.tinkerpop.gremlin.process.traversal.Path +import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} import scala.collection.JavaConverters._ -import scala.util.Try abstract class DseResponse { def executionInfo(): ExecutionInfo def rowCount(): Int def applied(): Boolean - def exhausted(): Boolean - def queriedHost(): Host = executionInfo().getQueriedHost - def achievedConsistencyLevel(): ConsistencyLevel = executionInfo().getAchievedConsistencyLevel + def exhausted(): Option[Boolean] + def coordinator(): Node = executionInfo().getCoordinator def speculativeExecutions(): Int = executionInfo().getSpeculativeExecutionCount def pagingState(): ByteBuffer = executionInfo().getPagingState - def triedHosts(): List[Host] = executionInfo().getTriedHosts.asScala.toList def warnings(): List[String] = executionInfo().getWarnings.asScala.toList def successFullExecutionIndex(): Int = executionInfo().getSuccessfulExecutionIndex def schemaInAgreement(): Boolean = executionInfo().isSchemaInAgreement } - class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttributes) extends DseResponse with LazyLogging { - private lazy val allGraphNodes: Seq[GraphNode] = collection.JavaConverters.asScalaBuffer(graphResultSet.all()) + private lazy val allGraphNodes: Seq[GraphNode] = iterableAsScalaIterable(graphResultSet.all()).toSeq + + override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo().asInstanceOf[ExecutionInfo] - override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo() override def applied(): Boolean = false // graph doesn't support LWTs so always return false - override def exhausted(): Boolean = graphResultSet.isExhausted() + override def exhausted(): Option[Boolean] = Option.empty /** * Get the number of all rows returned by the query. @@ -46,73 +45,44 @@ class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttri */ override def rowCount(): Int = allGraphNodes.size - def getGraphResultSet: GraphResultSet = { - graphResultSet - } + def getGraphResultSet: GraphResultSet = graphResultSet def getAllNodes: Seq[GraphNode] = allGraphNodes - def getOneNode: GraphNode = { - graphResultSet.one() - } - - - def getGraphResultColumnValues(column: String): Seq[Any] = { - if (allGraphNodes.isEmpty) return Seq.empty - - allGraphNodes.map(node => if (node.get(column) != null) node.get(column)) - } - - - def getEdges(name: String): Seq[Edge] = { - val columnValues = collection.mutable.Buffer[Edge]() - graphResultSet.forEach { n => - Try( - if (n.get(name).isEdge) { - columnValues.append(n.get(name).asEdge()) - } - ) - } - columnValues - } + def getOneNode: GraphNode = graphResultSet.one() + def getGraphResultColumnValues(column: String): Iterable[GraphNode] = + allGraphNodes.map(node => node.getByKey(column)) + .filter(_ != null) - def getVertexes(name: String): Seq[Vertex] = { - val columnValues = collection.mutable.Buffer[Vertex]() - graphResultSet.forEach { n => Try(if (n.get(name).isVertex) columnValues.append(n.get(name).asVertex())) } - columnValues + def buildFilterAndMapFn[T](filterFn: GraphNode => Boolean, mapFn: GraphNode => T): String => Seq[T] = + { arg => + iterableAsScalaIterable[GraphNode](graphResultSet).toSeq + .map(graphNode => graphNode.getByKey(arg)) + .filter(filterFn) + .map(mapFn) } + def getEdges: String => Seq[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) - def getPaths(name: String): Seq[Path] = { - val columnValues = collection.mutable.Buffer[Path]() - graphResultSet.forEach { n => Try(columnValues.append(n.get(name).asPath())) } - columnValues - } - + def getVertexes: String => Seq[Vertex] = buildFilterAndMapFn(_.isVertex, _.asVertex) - def getProperties(name: String): Seq[Property] = { - val columnValues = collection.mutable.Buffer[Property]() - graphResultSet.forEach { n => Try(columnValues.append(n.get(name).asProperty())) } - columnValues - } + def getPaths: String => Seq[Path] = buildFilterAndMapFn(_.isPath, _.asPath) + def getProperties: String => Seq[Property[_]] = buildFilterAndMapFn(_.isProperty, _.asProperty) - def getVertexProperties(name: String): Seq[VertexProperty] = { - val columnValues = collection.mutable.Buffer[VertexProperty]() - graphResultSet.forEach { n => Try(columnValues.append(n.get(name).asVertexProperty())) } - columnValues - } + def getVertexProperties: String => Seq[VertexProperty[_]] = buildFilterAndMapFn(_.isVertexProperty, _.asVertexProperty) def getDseAttributes: DseGraphAttributes = dseAttributes } class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes[_]) extends DseResponse with LazyLogging { - private lazy val allCqlRows: Seq[Row] = collection.JavaConverters.asScalaBuffer(cqlResultSet.all()) + private lazy val allCqlRows: Seq[Row] = iterableAsScalaIterable(cqlResultSet.all()).toSeq override def executionInfo(): ExecutionInfo = cqlResultSet.getExecutionInfo() override def applied(): Boolean = cqlResultSet.wasApplied() - override def exhausted(): Boolean = cqlResultSet.isFullyFetched && (cqlResultSet.getAvailableWithoutFetching == 0) + override def exhausted(): Option[Boolean] = + Option(cqlResultSet.isFullyFetched && (cqlResultSet.getAvailableWithoutFetching == 0)) /** * Get the number of all rows returned by the query. @@ -125,31 +95,18 @@ class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes[_]) e * * @return */ - def getCqlResultSet: ResultSet = { - cqlResultSet - } - + def getCqlResultSet: ResultSet = cqlResultSet /** * Get all the rows in a Seq[Row] format * * @return */ - def getAllRows: Seq[Row] = allCqlRows + def getAllRowsSeq: Seq[Row] = allCqlRows + def getOneRow: Row = cqlResultSet.one() - def getOneRow: Row = { - cqlResultSet.one() - } - - - def getCqlResultColumnValues(column: String): Seq[Any] = { - if (allCqlRows.isEmpty || !allCqlRows.head.getColumnDefinitions.contains(column)) { - return Seq.empty - } - - allCqlRows.map(row => row.getObject(column)) - } + def getColumnValSeq(column: String): Seq[Any] = allCqlRows.map(_.getObject(column)) def getDseAttributes: DseCqlAttributes[_] = dseAttributes } From 01b87b43d41b3c7a47380e633385e79072f0b6df Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 27 Nov 2019 13:41:19 -0600 Subject: [PATCH 12/62] Most of the core graph refactoring --- .../com/datastax/gatling/plugin/Predef.scala | 2 +- .../model/DseCqlStatementBuilders.scala | 8 +- .../plugin/model/DseCqlStatements.scala | 2 +- .../plugin/model/DseGraphAttributes.scala | 4 +- .../model/DseGraphAttributesBuilder.scala | 67 +++++++++------- .../model/DseGraphStatementBuilders.scala | 78 ++++++++++++------- .../plugin/model/DseGraphStatements.scala | 63 +++++++-------- .../plugin/request/GraphRequestAction.scala | 2 +- .../request/GraphRequestActionBuilder.scala | 2 +- 9 files changed, 126 insertions(+), 102 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/Predef.scala b/src/main/scala/com/datastax/gatling/plugin/Predef.scala index 228a254..28cd12c 100644 --- a/src/main/scala/com/datastax/gatling/plugin/Predef.scala +++ b/src/main/scala/com/datastax/gatling/plugin/Predef.scala @@ -38,7 +38,7 @@ trait DsePredefBase extends DseCheckSupport { implicit def cqlRequestAttributes2ActionBuilder(builder: DseCqlAttributesBuilder[_]): ActionBuilder = builder.build() - implicit def graphRequestAttributes2ActionBuilder(builder: DseGraphAttributesBuilder): ActionBuilder = builder.build() + implicit def graphRequestAttributes2ActionBuilder(builder: DseGraphAttributesBuilder[_]): ActionBuilder = builder.build() } /** diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index 1a86203..2a70018 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.oss.driver.api.core.cql.{BoundStatement, PreparedStatement, SimpleStatement, SimpleStatementBuilder} +import com.datastax.oss.driver.api.core.cql.{BatchStatement, BoundStatement, PreparedStatement, SimpleStatement, SimpleStatementBuilder} import com.datastax.gatling.plugin._ import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.core.session.Expression @@ -78,7 +78,7 @@ case class DseCqlStatementBuilder(tag: String) { * @param preparedStatement CQL Prepared Statement w/ anon ?'s * @return */ - def executeStatement(preparedStatement: PreparedStatement) = + def executeStatement(preparedStatement: PreparedStatement): DsePreparedCqlStatementBuilder = DsePreparedCqlStatementBuilder(tag, preparedStatement) /** @@ -98,7 +98,7 @@ case class DseCqlStatementBuilder(tag: String) { * * @param preparedStatements Array of prepared statements */ - def executePreparedBatch(preparedStatements: Array[PreparedStatement]) = + def executePreparedBatch(preparedStatements: Array[PreparedStatement]): DseCqlAttributesBuilder[BatchStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -168,7 +168,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * @param sessionKeys Gatling Session Keys * @return */ - def withParams(sessionKeys: List[String]) = + def withParams(sessionKeys: List[String]): DseCqlAttributesBuilder[BoundStatement] = DseCqlAttributesBuilder( DseCqlAttributes( tag, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index d2716da..3eb09f1 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -18,7 +18,7 @@ import scala.collection.JavaConverters._ import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseCqlStatement[T] extends DseStatement[T] { +trait DseCqlStatement[T <: Statement[_]] extends DseStatement[T] { def buildFromSession(session: Session): Validation[T] } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index 944809f..b902b5e 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -34,8 +34,8 @@ import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} * @param graphInternalOptions Query-specific options not available in the driver public API * @param graphTransformResults Function to use in order to transform a row into a Graph node */ -case class DseGraphAttributes(tag: String, - statement: DseStatement[GraphStatement], +case class DseGraphAttributes[T <: GraphStatement[_]](tag: String, + statement: DseStatement[T], cl: Option[ConsistencyLevel] = None, graphChecks: List[DseGraphCheck] = List.empty, genericChecks: List[GenericCheck] = List.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index 9176d9b..c9e2ee5 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -8,18 +8,19 @@ package com.datastax.gatling.plugin.model import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Row -import com.datastax.dse.driver.api.core.graph.GraphNode +import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} import com.datastax.gatling.plugin.request.GraphRequestActionBuilder import io.gatling.core.action.builder.ActionBuilder +import com.datastax.oss.driver.shaded.guava.common.base.Function /** * Request Builder for Graph Requests * * @param attr Addition Attributes */ -case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { +case class DseGraphAttributesBuilder[T <: GraphStatement[_]](attr: DseGraphAttributes[T]) { /** * Builds to final action to run * @@ -33,20 +34,22 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param level ConsistencyLevel * @return */ - def withConsistencyLevel(level: ConsistencyLevel) = DseGraphAttributesBuilder(attr.copy(cl = Some(level))) + def withConsistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(cl = Some(level))) /** * Execute a query as another user or another role, provided the current logged in user has PROXY.EXECUTE permission. * * This permission MUST be granted to the currently logged in user using the CQL statement: `GRANT PROXY.EXECUTE ON * ROLE someRole TO alice`. The user MUST be logged in with - * [[com.datastax.dse.driver.api.core.auth.DsePlainTextAuthProvider]] or - * [[com.datastax.dse.driver.api.core.auth.DseGSSAPIAuthProvider]] + * [[com.datastax.dse.driver.api.core.auth.DsePlainTextAuthProviderBase]] or + * [[com.datastax.dse.driver.api.core.auth.DseGssApiAuthProviderBase]] * * @param userOrRole String * @return */ - def withUserOrRole(userOrRole: String) = DseGraphAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) + def withUserOrRole(userOrRole: String):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) /** * Override the current system time for write time of query @@ -54,16 +57,16 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param epochTsInMs timestamp to use * @return */ - def withDefaultTimestamp(epochTsInMs: Long) = DseGraphAttributesBuilder(attr.copy(defaultTimestamp = Some(epochTsInMs))) - + def withDefaultTimestamp(epochTsInMs: Long):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(defaultTimestamp = Some(epochTsInMs))) /** * Set query to be idempotent i.e. run only once * * @return */ - def withIdempotency() = DseGraphAttributesBuilder(attr.copy(idempotent = Some(true))) - + def withIdempotency():DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(idempotent = Some(true))) /** * Set Read timeout of the query @@ -71,8 +74,8 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param readTimeoutInMs time in milliseconds * @return */ - def withReadTimeout(readTimeoutInMs: Int) = DseGraphAttributesBuilder(attr.copy(readTimeout = Some(readTimeoutInMs))) - + def withReadTimeout(readTimeoutInMs: Int):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(readTimeout = Some(readTimeoutInMs))) /** * Sets the graph language @@ -80,7 +83,8 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param language graph language to use * @return */ - def withLanguage(language: String) = DseGraphAttributesBuilder(attr.copy(graphLanguage = Some(language))) + def withLanguage(language: String):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(graphLanguage = Some(language))) /** * Sets the graph name to use @@ -88,8 +92,8 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param name Graph name * @return */ - def withName(name: String) = DseGraphAttributesBuilder(attr.copy(graphName = Some(name))) - + def withName(name: String):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(graphName = Some(name))) /** * Set the source of the graph @@ -97,14 +101,16 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param source graph source * @return */ - def withSource(source: String) = DseGraphAttributesBuilder(attr.copy(graphSource = Some(source))) + def withSource(source: String):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(graphSource = Some(source))) /** * Set the query to be system level * * @return */ - def withSystemQuery() = DseGraphAttributesBuilder(attr.copy(isSystemQuery = Some(true))) + def withSystemQuery():DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(isSystemQuery = Some(true))) /** * Set Options on graph @@ -112,8 +118,8 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param options options in key/value par to set against the query * @return */ - def withOptions(options: (String, String)*) = DseGraphAttributesBuilder(attr.copy(graphInternalOptions = Some(options))) - + def withOptions(options: (String, String)*):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(graphInternalOptions = Some(options))) /** * Set Option on graph @@ -121,8 +127,7 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param option options in key/value par to set against the query * @return */ - def withOption(option: (String, String)) = withOptions(option) - + def withOption(option: (String, String)):DseGraphAttributesBuilder[T] = withOptions(option) /** * Transform results function @@ -130,7 +135,7 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param transform Transform Function * @return */ - def withTransformResults(transform: com.datastax.oss.driver.shaded.guava.common.base.Function[Row, GraphNode]) = { + def withTransformResults(transform: Function[Row, GraphNode]):DseGraphAttributesBuilder[T] = { DseGraphAttributesBuilder(attr.copy(graphTransformResults = Some(transform))) } @@ -140,7 +145,8 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param readCL Consistency Level to use * @return */ - def withReadConsistency(readCL: ConsistencyLevel) = DseGraphAttributesBuilder(attr.copy(readCL = Some(readCL))) + def withReadConsistency(readCL: ConsistencyLevel):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(readCL = Some(readCL))) /** * Define [[ConsistencyLevel]] to be used for write queries @@ -148,8 +154,8 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @param writeCL Consistency Level to use * @return */ - def withWriteConsistency(writeCL: ConsistencyLevel) = DseGraphAttributesBuilder(attr.copy(writeCL = Some(writeCL))) - + def withWriteConsistency(writeCL: ConsistencyLevel):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(writeCL = Some(writeCL))) /** * Backwards compatibility to set consistencyLevel @@ -159,8 +165,7 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @return */ @deprecated("use withConsistencyLevel() instead, will be removed in future version") - def consistencyLevel(level: ConsistencyLevel) = withConsistencyLevel(level) - + def consistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T] = withConsistencyLevel(level) /** * For Backwards compatibility @@ -170,8 +175,10 @@ case class DseGraphAttributesBuilder(attr: DseGraphAttributes) { * @return */ @deprecated("use withUserOrRole() instead, will be removed in future version") - def executeAs(userOrRole: String) = withUserOrRole(userOrRole: String) + def executeAs(userOrRole: String):DseGraphAttributesBuilder[T] = withUserOrRole(userOrRole: String) - def check(check: DseGraphCheck) = DseGraphAttributesBuilder(attr.copy(graphChecks = check :: attr.graphChecks)) - def check(check: GenericCheck) = DseGraphAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) + def check(check: DseGraphCheck):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(graphChecks = check :: attr.graphChecks)) + def check(check: GenericCheck):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala index eca66ce..9b38d3e 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{GraphStatement, SimpleGraphStatement} +import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, ScriptGraphStatement, ScriptGraphStatementBuilder} import io.gatling.core.session.{Expression, Session} /** @@ -22,8 +22,11 @@ case class DseGraphStatementBuilder(tag: String) { * @param strStatement Graph Query String * @return */ - def executeGraph(strStatement: Expression[String]) = { - DseGraphAttributesBuilder(DseGraphAttributes(tag, GraphStringStatement(strStatement))) + def executeGraph(strStatement: Expression[String]): DseGraphAttributesBuilder[ScriptGraphStatement] = { + DseGraphAttributesBuilder( + DseGraphAttributes( + tag, + GraphStringStatement(strStatement))) } /** @@ -33,8 +36,8 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Simple Graph Statement * @return */ - @deprecated("Replaced by executeGraph(SimpleGraphStatement)") - def executeGraphStatement(gStatement: SimpleGraphStatement) = + @deprecated("Replaced by executeGraph(ScriptGraphStatement)") + def executeGraphStatement(gStatement: ScriptGraphStatement): DseGraphParametrizedStatementBuilder = executeGraph(gStatement) /** @@ -44,8 +47,8 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Simple Graph Statement * @return */ - def executeGraph(gStatement: SimpleGraphStatement) = { - DseGraphParametrizedStatementBuilder(tag, gStatement) + def executeGraph(gStatement: ScriptGraphStatement):DseGraphParametrizedStatementBuilder = { + DseGraphParametrizedStatementBuilder(tag, new ScriptGraphStatementBuilder(gStatement)) } /** @@ -54,8 +57,11 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Graph Statement from a Fluent API builder * @return */ - def executeGraphFluent(gStatement: GraphStatement) = { - DseGraphAttributesBuilder(DseGraphAttributes(tag, GraphFluentStatement(gStatement))) + def executeGraphFluent(gStatement: FluentGraphStatement): DseGraphAttributesBuilder[FluentGraphStatement] = { + DseGraphAttributesBuilder( + DseGraphAttributes( + tag, + GraphFluentStatement(gStatement))) } /** @@ -71,8 +77,11 @@ case class DseGraphStatementBuilder(tag: String) { * @param gLambda The lambda * @return */ - def executeGraphFluent(gLambda: Session => GraphStatement) = { - DseGraphAttributesBuilder(DseGraphAttributes(tag, GraphFluentStatementFromScalaLambda(gLambda))) + def executeGraphFluent(gLambda: Session => FluentGraphStatement): DseGraphAttributesBuilder[FluentGraphStatement] = { + DseGraphAttributesBuilder( + DseGraphAttributes( + tag, + GraphFluentStatementFromScalaLambda(gLambda))) } /** @@ -82,8 +91,11 @@ case class DseGraphStatementBuilder(tag: String) { * @return */ @deprecated("Replaced by executeGraphFluent{session => session(feederKey)}") - def executeGraphFeederTraversal(feederKey: String): DseGraphAttributesBuilder = { - DseGraphAttributesBuilder(DseGraphAttributes(tag, GraphFluentSessionKey(feederKey))) + def executeGraphFeederTraversal(feederKey: String): DseGraphAttributesBuilder[FluentGraphStatement] = { + DseGraphAttributesBuilder( + DseGraphAttributes( + tag, + GraphFluentSessionKey(feederKey))) } } @@ -91,9 +103,9 @@ case class DseGraphStatementBuilder(tag: String) { * Builder for Graph queries that do not have bound parameters yet. * * @param tag Query tag - * @param gStatement Simple Graph Staetment + * @param builder Simple Graph Staetment */ -case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleGraphStatement) { +case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGraphStatementBuilder) { /** * Included for compatibility @@ -102,7 +114,8 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @return */ @deprecated("Replaced by withParams") - def withSetParams(paramNames: Array[String]): DseGraphAttributesBuilder = withParams(paramNames.toList) + def withSetParams(paramNames: Array[String]): DseGraphAttributesBuilder[ScriptGraphStatement] = + withParams(paramNames.toList) /** * Params to set from strings @@ -110,7 +123,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @param paramNames List of strings to use * @return */ - def withParams(paramNames: String*): DseGraphAttributesBuilder = + def withParams(paramNames: String*): DseGraphAttributesBuilder[ScriptGraphStatement] = withParams(paramNames.toList) /** @@ -119,8 +132,13 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @param paramNames List of strings to use * @return */ - def withParams(paramNames: List[String]): DseGraphAttributesBuilder = DseGraphAttributesBuilder( - DseGraphAttributes(tag, GraphBoundStatement(gStatement, paramNames.map(key => key -> key).toMap)) + def withParams(paramNames: List[String]): DseGraphAttributesBuilder[ScriptGraphStatement] = + DseGraphAttributesBuilder( + DseGraphAttributes( + tag, + GraphBoundStatement( + builder, + paramNames.map(key => key -> key).toMap)) ) /** @@ -130,7 +148,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @return */ @deprecated("Replaced with withParams") - def withSetParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder = + def withSetParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = withParams(paramNamesAndOverrides) @@ -142,7 +160,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @return */ @deprecated("Replaced with withParams") - def withParamOverrides(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder = + def withParamOverrides(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = withParams(paramNamesAndOverrides) /** @@ -152,8 +170,11 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @param paramNamesAndOverrides a Map of Session parameter names to their GraphStatement parameter names * @return */ - def withParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder = { - DseGraphAttributesBuilder(DseGraphAttributes(tag, GraphBoundStatement(gStatement, paramNamesAndOverrides))) + def withParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = { + DseGraphAttributesBuilder( + DseGraphAttributes( + tag, + GraphBoundStatement(builder, paramNamesAndOverrides))) } /** @@ -165,9 +186,8 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @return */ @deprecated("Replaced by withRepeatedParams") - def withRepeatedSetParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder = { + def withRepeatedSetParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = withRepeatedParams(batchSize, paramNamesAndOverrides) - } /** * Repeat the parameters given by suffixing their names and overridden names by a number picked from 1 to batchSize. @@ -177,7 +197,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG * @param paramNamesAndOverrides a Map of Session parameter names to their GraphStatement parameter names * @return */ - def withRepeatedParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder = { + def withRepeatedParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = { def repeatParameters(params: Map[String, String]): Map[String, String] = batchSize match { // Gatling has a weird behavior when feeding multiple values // Feeding 1 value gives non-suffixed variables whereas feeding more gives suffixed variables starting by the @@ -190,7 +210,11 @@ case class DseGraphParametrizedStatementBuilder(tag: String, gStatement: SimpleG } DseGraphAttributesBuilder( - DseGraphAttributes(tag, GraphBoundStatement(gStatement, repeatParameters(paramNamesAndOverrides))) + DseGraphAttributes( + tag, + GraphBoundStatement( + builder, + repeatParameters(paramNamesAndOverrides))) ) } } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index 9c56eec..52f9c00 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{DseGraph, GraphStatement, SimpleGraphStatement} +import com.datastax.dse.driver.api.core.graph.{DseGraph, FluentGraphStatement, GraphStatement, ScriptGraphStatement, ScriptGraphStatementBuilder} import com.datastax.gatling.plugin.exceptions.DseGraphStatementException import io.gatling.commons.validation._ import io.gatling.core.session.{Expression, Session} @@ -15,8 +15,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseGraphStatement extends DseStatement[GraphStatement] { - def buildFromSession(session: Session): Validation[GraphStatement] +trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[T] { + def buildFromSession(session: Session): Validation[T] } /** @@ -24,9 +24,9 @@ trait DseGraphStatement extends DseStatement[GraphStatement] { * * @param statement the Gremlin String to execute */ -case class GraphStringStatement(statement: Expression[String]) extends DseGraphStatement { - def buildFromSession(gatlingSession: Session): Validation[GraphStatement] = { - statement(gatlingSession).flatMap(stmt => new SimpleGraphStatement(stmt).success) +case class GraphStringStatement(statement: Expression[String]) extends DseGraphStatement[ScriptGraphStatement] { + def buildFromSession(gatlingSession: Session): Validation[ScriptGraphStatement] = { + statement(gatlingSession).flatMap(stmt => ScriptGraphStatement.builder(stmt).build().success) } } @@ -35,8 +35,9 @@ case class GraphStringStatement(statement: Expression[String]) extends DseGraphS * * @param statement the Fluent Statement */ -case class GraphFluentStatement(statement: GraphStatement) extends DseGraphStatement { - def buildFromSession(gatlingSession: Session): Validation[GraphStatement] = { +case class GraphFluentStatement(statement: FluentGraphStatement) + extends DseGraphStatement[FluentGraphStatement] { + def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatement] = { statement.success } } @@ -48,8 +49,9 @@ case class GraphFluentStatement(statement: GraphStatement) extends DseGraphState * @param lambda Scala lambda that takes a Gatling User Session (from which it can retrieve parameters) * and returns a fluent Graph Statement */ -case class GraphFluentStatementFromScalaLambda(lambda: Session => GraphStatement) extends DseGraphStatement { - def buildFromSession(gatlingSession: Session): Validation[GraphStatement] = { +case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphStatement) + extends DseGraphStatement[FluentGraphStatement] { + def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatement] = { lambda(gatlingSession).success } } @@ -60,31 +62,31 @@ case class GraphFluentStatementFromScalaLambda(lambda: Session => GraphStatement * * @param sessionKey Place a GraphTraversal in your session with this key name */ -case class GraphFluentSessionKey(sessionKey: String) extends DseGraphStatement { - - def buildFromSession(gatlingSession: Session): Validation[GraphStatement] = { +case class GraphFluentSessionKey(sessionKey: String) + extends DseGraphStatement[FluentGraphStatement] { + def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatement] = { if (!gatlingSession.contains(sessionKey)) { throw new DseGraphStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } Try { - DseGraph.statementFromTraversal(gatlingSession(sessionKey).as[GraphTraversal[_, _]]) + FluentGraphStatement.builder(gatlingSession(sessionKey).as[GraphTraversal[_, _]]).build() } match { case TrySuccess(stmt) => stmt.success case TryFailure(error) => error.getMessage.failure } } - } /** * Set/Bind Gatling Session key/vals to GraphStatement * - * @param statement SimpleGraphStatement + * @param builder SimpleGraphStatementBuilder * @param sessionKeys Gatling session param keys mapped to their bind name, to allow name override */ -case class GraphBoundStatement(statement: SimpleGraphStatement, sessionKeys: Map[String, String]) extends DseGraphStatement { +case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys: Map[String, String]) + extends DseGraphStatement[ScriptGraphStatement] { /** * Apply the Gatling session params passed to the GraphStatement @@ -92,28 +94,19 @@ case class GraphBoundStatement(statement: SimpleGraphStatement, sessionKeys: Map * @param gatlingSession Gatling Session * @return */ - def buildFromSession(gatlingSession: Session): Validation[GraphStatement] = { + + def buildFromSession(gatlingSession: Session): Validation[ScriptGraphStatement] = { Try { - sessionKeys.foreach((tuple: (String, String)) => setParam(gatlingSession, tuple._1, tuple._2)).success - statement + sessionKeys foreach { + _ match { + case (k, v) => builder.setQueryParam(v, gatlingSession(k).as[Object]) + case _ => throw new RuntimeException() + } + } + builder.build() } match { case TrySuccess(stmt) => stmt.success case TryFailure(error) => error.getMessage.failure } } - - /** - * Set a parameter to the current gStatement. - * - * The value of this parameter is retrieved by looking up paramName from the gatlingSession. - * It is then bound to overriddenParamName in gStatement. - * - * @param gatlingSession Gatling session - * @param paramName Parameter name as accessible in Gatling session - * @param overriddenParamName Parameter name used to bind the statement - * @return gStatement - */ - private def setParam(gatlingSession: Session, paramName: String, overriddenParamName: String): GraphStatement = { - statement.set(overriddenParamName, gatlingSession(paramName).as[Object]) - } } \ No newline at end of file diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index e4abe66..a3d3196 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -47,7 +47,7 @@ class GraphRequestAction(val name: String, val system: ActorSystem, val statsEngine: StatsEngine, val protocol: DseProtocol, - val dseAttributes: DseGraphAttributes, + val dseAttributes: DseGraphAttributes[_], val metricsLogger: MetricsLogger, val dseExecutorService: ExecutorService, val gatlingTimingSource: GatlingTimingSource) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala index eb2d367..047a853 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala @@ -13,7 +13,7 @@ import io.gatling.core.action.builder.ActionBuilder import io.gatling.core.structure.ScenarioContext import io.gatling.core.util.NameGen -class GraphRequestActionBuilder(dseAttributes: DseGraphAttributes) extends ActionBuilder with +class GraphRequestActionBuilder(dseAttributes: DseGraphAttributes[_]) extends ActionBuilder with NameGen { def build(ctx: ScenarioContext, next: Action): Action = { From 7521b1e011d43626af3efd07d9477222ccc8a968 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 27 Nov 2019 15:27:45 -0600 Subject: [PATCH 13/62] Fixes to DseResponseHandler... and a few other miscellaneous fixes --- .../plugin/request/DseRequestActor.scala | 4 +- .../gatling/plugin/response/DseResponse.scala | 32 +++++++------ .../plugin/response/DseResponseHandler.scala | 47 +++++++++---------- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala index 2736861..c42b784 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala @@ -10,7 +10,7 @@ package com.datastax.gatling.plugin.request import akka.actor.Actor import com.datastax.oss.driver.api.core.cql.ResultSet import com.datastax.dse.driver.api.core.graph.GraphResultSet -import com.datastax.gatling.plugin.response.SimpleCallback +import com.datastax.gatling.plugin.response.DseResponseCallback import com.typesafe.scalalogging.StrictLogging import io.gatling.core.session.Session @@ -20,7 +20,7 @@ import scala.util.{Failure, Success, Try} case class SendCqlQuery(dseRequestAction: CqlRequestAction, session: Session) case class SendGraphQuery(dseRequestAction: GraphRequestAction, session: Session) -case class RecordResult[T](t: Try[T], callback: SimpleCallback[T]) +case class RecordResult[T](t: Try[T], callback: DseResponseCallback[T]) class DseRequestActor extends Actor with StrictLogging { override def receive: Actor.Receive = { diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index a6a556b..7e3e21b 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -23,18 +23,18 @@ abstract class DseResponse { def rowCount(): Int def applied(): Boolean def exhausted(): Option[Boolean] - def coordinator(): Node = executionInfo().getCoordinator - def speculativeExecutions(): Int = executionInfo().getSpeculativeExecutionCount - def pagingState(): ByteBuffer = executionInfo().getPagingState - def warnings(): List[String] = executionInfo().getWarnings.asScala.toList - def successFullExecutionIndex(): Int = executionInfo().getSuccessfulExecutionIndex - def schemaInAgreement(): Boolean = executionInfo().isSchemaInAgreement + def coordinator(): Node = executionInfo.getCoordinator + def speculativeExecutions(): Int = executionInfo.getSpeculativeExecutionCount + def pagingState(): ByteBuffer = executionInfo.getPagingState + def warnings(): List[String] = executionInfo.getWarnings.asScala.toList + def successFullExecutionIndex(): Int = executionInfo.getSuccessfulExecutionIndex + def schemaInAgreement(): Boolean = executionInfo.isSchemaInAgreement } -class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttributes) extends DseResponse with LazyLogging { +class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttributes[_]) extends DseResponse with LazyLogging { private lazy val allGraphNodes: Seq[GraphNode] = iterableAsScalaIterable(graphResultSet.all()).toSeq - override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo().asInstanceOf[ExecutionInfo] + override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo.asInstanceOf[ExecutionInfo] override def applied(): Boolean = false // graph doesn't support LWTs so always return false override def exhausted(): Option[Boolean] = Option.empty @@ -69,18 +69,20 @@ class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttri def getPaths: String => Seq[Path] = buildFilterAndMapFn(_.isPath, _.asPath) - def getProperties: String => Seq[Property[_]] = buildFilterAndMapFn(_.isProperty, _.asProperty) + def getProperties: String => Seq[Property[_]] = + buildFilterAndMapFn(_.isProperty, _.asProperty.asInstanceOf[Property[_]]) - def getVertexProperties: String => Seq[VertexProperty[_]] = buildFilterAndMapFn(_.isVertexProperty, _.asVertexProperty) + def getVertexProperties: String => Seq[VertexProperty[_]] = + buildFilterAndMapFn(_.isVertexProperty, _.asVertexProperty.asInstanceOf[VertexProperty[_]]) - def getDseAttributes: DseGraphAttributes = dseAttributes + def getDseAttributes: DseGraphAttributes[_] = dseAttributes } class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes[_]) extends DseResponse with LazyLogging { private lazy val allCqlRows: Seq[Row] = iterableAsScalaIterable(cqlResultSet.all()).toSeq - override def executionInfo(): ExecutionInfo = cqlResultSet.getExecutionInfo() - override def applied(): Boolean = cqlResultSet.wasApplied() + override def executionInfo(): ExecutionInfo = cqlResultSet.getExecutionInfo + override def applied(): Boolean = cqlResultSet.wasApplied override def exhausted(): Option[Boolean] = Option(cqlResultSet.isFullyFetched && (cqlResultSet.getAvailableWithoutFetching == 0)) @@ -88,7 +90,7 @@ class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes[_]) e * Get the number of all rows returned by the query. * Note: Calling this function fetches all rows from the result set! */ - def rowCount: Int = allCqlRows.size + def rowCount(): Int = allCqlRows.size /** * Get CQL ResultSet @@ -104,7 +106,7 @@ class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes[_]) e */ def getAllRowsSeq: Seq[Row] = allCqlRows - def getOneRow: Row = cqlResultSet.one() + def getOneRow: Row = cqlResultSet.one def getColumnValSeq(column: String): Seq[Any] = allCqlRows.map(_.getObject(column)) diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 5c0fb69..18d4f81 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -11,10 +11,11 @@ import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem import com.datastax.oss.driver.api.core.cql._ -import com.datastax.dse.driver.api.core.graph.{GraphProtocol, GraphResultSet, GraphStatement} +import com.datastax.dse.driver.api.core.graph.{GraphResultSet, GraphStatement} import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.datastax.gatling.plugin.utils.{ResponseTime, ResponseTimeBuilder} +import com.datastax.oss.driver.api.core.metadata.Node import com.typesafe.scalalogging.StrictLogging import io.gatling.commons.stats._ import io.gatling.commons.validation.Failure @@ -34,26 +35,26 @@ object DseResponseHandler { .mkString(",") } -trait SimpleCallback[RS] { +trait DseResponseCallback[RS] { def onFailure(t: Throwable): Unit def onSuccess(result: RS): Unit } -abstract class DseResponseHandler[RS, Response <: DseResponse] extends StrictLogging with SimpleCallback[RS] { +abstract class DseResponseHandler[S, RS, R <: DseResponse] extends StrictLogging with DseResponseCallback[RS] { protected def responseTimeBuilder: ResponseTimeBuilder protected def system: ActorSystem protected def statsEngine: StatsEngine protected def metricsLogger: MetricsLogger protected def next: Action protected def session: Session - protected def stmt: Any + protected def stmt: S protected def tag: String protected def queries: Seq[String] - protected def specificChecks: List[Check[Response]] + protected def specificChecks: List[Check[R]] protected def genericChecks: List[Check[DseResponse]] - protected def newResponse(rs: RS): Response - protected def queriedHost(rs: RS): String + protected def newResponse(rs: RS): R + protected def coordinator(rs: RS): Node private def writeGatlingLog(status: Status, respTimings: ResponseTimings, message: Option[String], extraInfo: List[Any]): Unit = statsEngine.logResponse(session, tag, respTimings, status, None, message, extraInfo) @@ -75,8 +76,8 @@ abstract class DseResponseHandler[RS, Response <: DseResponse] extends StrictLog List(responseTime.latencyIn(MICROSECONDS), "CHK", logUuid) ) - logger.warn("[{}] {} - Check: {}, Query: {}, Host: {}", - logUuid, tagString, checkRes._2.get.message, DseResponseHandler.sanitizeAndJoin(queries), queriedHost(resultSet) + logger.warn("[{}] {} - Check: {}, Query: {}, Coordinator: {}", + logUuid, tagString, checkRes._2.get.message, DseResponseHandler.sanitizeAndJoin(queries), coordinator(resultSet).toString ) } @@ -93,13 +94,9 @@ abstract class DseResponseHandler[RS, Response <: DseResponse] extends StrictLog ) stmt match { - case Some(gs: GraphStatement) => - val unwrap = Try( - DseResponseHandler.sanitize(gs.unwrap(GraphProtocol.GRAPHSON_2_0).toString) - ).getOrElse(DseResponseHandler.sanitize(gs.unwrap(GraphProtocol.GRAPHSON_1_0).toString)) - + case Some(gs: GraphStatement[_]) => logger.warn("[{}] {} - Execute: {} - Attrs: {}", - logUuid, tagString, unwrap, session.attributes.mkString(","), t + logUuid, tagString, gs, session.attributes.mkString(","), t ) case _ => logger.warn("[{}] {} - Execute: {}, Query: {}", @@ -141,36 +138,36 @@ abstract class DseResponseHandler[RS, Response <: DseResponse] extends StrictLog } } -class GraphResponseHandler(val next: Action, +class GraphResponseHandler[T <: GraphStatement[_]](val next: Action, val session: Session, val system: ActorSystem, val statsEngine: StatsEngine, val responseTimeBuilder: ResponseTimeBuilder, - val stmt: GraphStatement, - val dseAttributes: DseGraphAttributes, + val stmt: T, + val dseAttributes: DseGraphAttributes[T], val metricsLogger: MetricsLogger) - extends DseResponseHandler[GraphResultSet, GraphResponse] { + extends DseResponseHandler[T, GraphResultSet, GraphResponse] { override protected def tag: String = dseAttributes.tag override protected def queries: Seq[String] = Seq.empty override protected def specificChecks: List[Check[GraphResponse]] = dseAttributes.graphChecks override protected def genericChecks: List[Check[DseResponse]] = dseAttributes.genericChecks override protected def newResponse(rs: GraphResultSet): GraphResponse = new GraphResponse(rs, dseAttributes) - override protected def queriedHost(rs: GraphResultSet): String = rs.getExecutionInfo.getQueriedHost.toString + override protected def coordinator(rs: GraphResultSet): Node = rs.getExecutionInfo.getCoordinator } -class CqlResponseHandler(val next: Action, +class CqlResponseHandler[T <: Statement[_]](val next: Action, val session: Session, val system: ActorSystem, val statsEngine: StatsEngine, val responseTimeBuilder: ResponseTimeBuilder, - val stmt: Statement, - val dseAttributes: DseCqlAttributes, + val stmt: T, + val dseAttributes: DseCqlAttributes[T], val metricsLogger: MetricsLogger) - extends DseResponseHandler[ResultSet, CqlResponse] { + extends DseResponseHandler[T, ResultSet, CqlResponse] { override protected def tag: String = dseAttributes.tag override protected def queries: Seq[String] = Seq.empty override protected def specificChecks: List[Check[CqlResponse]] = dseAttributes.cqlChecks override protected def genericChecks: List[Check[DseResponse]] = dseAttributes.genericChecks override protected def newResponse(rs: ResultSet): CqlResponse = new CqlResponse(rs, dseAttributes) - override protected def queriedHost(rs: ResultSet): String = rs.getExecutionInfo.getQueriedHost.toString + override protected def coordinator(rs: ResultSet): Node = rs.getExecutionInfo.getCoordinator } From bf859857430611c8104c9dbf024b7b12cda11ca5 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 2 Dec 2019 10:58:09 -0600 Subject: [PATCH 14/62] Updates to Cql/GraphRequestAction to match other work done elsewhere in these changes. Still need to update the bits around the explicit interaction with the driver. --- .../model/DseCqlAttributesBuilder.scala | 2 +- .../model/DseGraphAttributesBuilder.scala | 2 +- .../plugin/model/DseGraphStatements.scala | 2 +- .../plugin/request/CqlRequestAction.scala | 10 +++-- .../request/CqlRequestActionBuilder.scala | 4 +- .../plugin/request/DseRequestActor.scala | 4 +- .../plugin/request/GraphRequestAction.scala | 18 +++++---- .../request/GraphRequestActionBuilder.scala | 4 +- .../gatling/plugin/utils/FutureUtils.scala | 39 ------------------- 9 files changed, 26 insertions(+), 59 deletions(-) delete mode 100644 src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 8967a18..587dc20 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -26,7 +26,7 @@ case class DseCqlAttributesBuilder[T <: Statement[_]](attr: DseCqlAttributes[T]) * * @return */ - def build(): CqlRequestActionBuilder = new CqlRequestActionBuilder(attr) + def build(): CqlRequestActionBuilder[T] = new CqlRequestActionBuilder(attr) /** * Set Consistency Level diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index c9e2ee5..44cfa98 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -26,7 +26,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[_]](attr: DseGraphAttri * * @return */ - def build(): ActionBuilder = new GraphRequestActionBuilder(attr) + def build(): GraphRequestActionBuilder[T] = new GraphRequestActionBuilder(attr) /** * Set Consistency Level diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index 52f9c00..b5e66a7 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{DseGraph, FluentGraphStatement, GraphStatement, ScriptGraphStatement, ScriptGraphStatementBuilder} +import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, GraphStatement, ScriptGraphStatement, ScriptGraphStatementBuilder} import com.datastax.gatling.plugin.exceptions.DseGraphStatementException import io.gatling.commons.validation._ import io.gatling.core.session.{Expression, Session} diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index 0a046d6..66c0b0a 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -17,6 +17,7 @@ import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.DseCqlAttributes import com.datastax.gatling.plugin.response.CqlResponseHandler import com.datastax.gatling.plugin.utils._ +import com.datastax.oss.driver.api.core.cql.Statement import io.gatling.commons.stats.KO import io.gatling.commons.validation.safely import io.gatling.core.action.{Action, ExitableAction} @@ -24,6 +25,7 @@ import io.gatling.core.session.Session import io.gatling.core.stats.StatsEngine import scala.collection.JavaConverters._ +import scala.compat.java8.FutureConverters import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} /** @@ -44,12 +46,12 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to * other Gatling data writers, like the console reporter. */ -class CqlRequestAction(val name: String, +class CqlRequestAction[T <: Statement[_]](val name: String, val next: Action, val system: ActorSystem, val statsEngine: StatsEngine, val protocol: DseProtocol, - val dseAttributes: DseCqlAttributes[_], + val dseAttributes: DseCqlAttributes[T], val metricsLogger: MetricsLogger, val dseExecutorService: ExecutorService, val gatlingTimingSource: GatlingTimingSource) @@ -96,8 +98,8 @@ class CqlRequestAction(val name: String, val responseHandler = new CqlResponseHandler(next, session, system, statsEngine, responseTimeBuilder, stmt, dseAttributes, metricsLogger) implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) - FutureUtils - .toScalaFuture(protocol.session.executeAsync(stmt)) + FutureConverters + .toScala(protocol.session.executeAsync(stmt)) .onComplete(t => DseRequestActor.recordResult(RecordResult(t, responseHandler))) }) } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala index af0a9a6..5964fcb 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala @@ -13,12 +13,12 @@ import io.gatling.core.action.builder.ActionBuilder import io.gatling.core.structure.ScenarioContext import io.gatling.core.util.NameGen -class CqlRequestActionBuilder(val dseAttributes: DseCqlAttributes[_]) extends ActionBuilder with +class CqlRequestActionBuilder[T](val dseAttributes: DseCqlAttributes[T]) extends ActionBuilder with NameGen { def build(ctx: ScenarioContext, next: Action): Action = { val dseComponents = ctx.protocolComponentsRegistry.components(DseProtocol.DseProtocolKey) - new CqlRequestAction( + new CqlRequestAction[T]( dseAttributes.tag, next, ctx.system, diff --git a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala index c42b784..06368c4 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala @@ -17,8 +17,8 @@ import io.gatling.core.session.Session import scala.concurrent.ExecutionException import scala.util.{Failure, Success, Try} -case class SendCqlQuery(dseRequestAction: CqlRequestAction, session: Session) -case class SendGraphQuery(dseRequestAction: GraphRequestAction, session: Session) +case class SendCqlQuery(dseRequestAction: CqlRequestAction[_], session: Session) +case class SendGraphQuery(dseRequestAction: GraphRequestAction[_], session: Session) case class RecordResult[T](t: Try[T], callback: DseResponseCallback[T]) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index a3d3196..3709725 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -12,6 +12,7 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem +import com.datastax.dse.driver.api.core.graph.GraphStatement import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.DseGraphAttributes @@ -22,6 +23,7 @@ import io.gatling.core.action.{Action, ExitableAction} import io.gatling.core.session.Session import io.gatling.core.stats.StatsEngine +import scala.compat.java8.FutureConverters import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} /** @@ -42,12 +44,12 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to * other Gatling data writers, like the console reporter. */ -class GraphRequestAction(val name: String, +class GraphRequestAction[T <: GraphStatement[_]](val name: String, val next: Action, val system: ActorSystem, val statsEngine: StatsEngine, val protocol: DseProtocol, - val dseAttributes: DseGraphAttributes[_], + val dseAttributes: DseGraphAttributes[T], val metricsLogger: MetricsLogger, val dseExecutorService: ExecutorService, val gatlingTimingSource: GatlingTimingSource) @@ -92,8 +94,8 @@ class GraphRequestAction(val name: String, dseAttributes.idempotent.map(gStmt.setIdempotent) // Graph only Options - dseAttributes.readCL.map(gStmt.setGraphReadConsistencyLevel) - dseAttributes.writeCL.map(gStmt.setGraphWriteConsistencyLevel) + dseAttributes.readCL.map(gStmt.setReadConsistencyLevel) + dseAttributes.writeCL.map(gStmt.setWriteConsistencyLevel) dseAttributes.graphLanguage.map(gStmt.setGraphLanguage) dseAttributes.graphName.map(gStmt.setGraphName) dseAttributes.graphSource.map(gStmt.setGraphSource) @@ -109,10 +111,12 @@ class GraphRequestAction(val name: String, gStmt.setSystemQuery() } - val responseHandler = new GraphResponseHandler(next, session, system, statsEngine, responseTimeBuilder, gStmt, dseAttributes, metricsLogger) + val responseHandler = + new GraphResponseHandler( + next, session, system, statsEngine, responseTimeBuilder, gStmt, dseAttributes, metricsLogger) implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) - FutureUtils - .toScalaFuture(protocol.session.executeGraphAsync(gStmt)) + FutureConverters + .toScala(protocol.session.executeAsync(gStmt)) .onComplete(t => DseRequestActor.recordResult(RecordResult(t, responseHandler))) }) } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala index 047a853..3d239a9 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala @@ -13,12 +13,12 @@ import io.gatling.core.action.builder.ActionBuilder import io.gatling.core.structure.ScenarioContext import io.gatling.core.util.NameGen -class GraphRequestActionBuilder(dseAttributes: DseGraphAttributes[_]) extends ActionBuilder with +class GraphRequestActionBuilder[T](dseAttributes: DseGraphAttributes[T]) extends ActionBuilder with NameGen { def build(ctx: ScenarioContext, next: Action): Action = { val dseComponents = ctx.protocolComponentsRegistry.components(DseProtocol.DseProtocolKey) - new GraphRequestAction( + new GraphRequestAction[T]( dseAttributes.tag, next, ctx.system, diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala b/src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala deleted file mode 100644 index 74a2227..0000000 --- a/src/main/scala/com/datastax/gatling/plugin/utils/FutureUtils.scala +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018 Datastax Inc. - * - * This software can be used solely with DataStax products. Please consult the file LICENSE.md. - */ - -package com.datastax.gatling.plugin.utils - -import com.datastax.oss.driver.shaded.guava.common.util.concurrent.{FutureCallback, Futures, ListenableFuture} - -import scala.concurrent.{Future, Promise} - -object FutureUtils { - /** - * Converts a Guava future into a Scala future containing the exact same - * result. - * - * The conversion is operated by the same thread that will eventually - * complete the guava future. It is not an expensive operation, though it - * may involve CAS operations under the hood. - * - * @param guavaFuture the Guava future to convert - * @tparam T the type of object returned by the Guava future - * @return a Scala [[Future]] that will be completed when the Guava future - * completes - */ - def toScalaFuture[T](guavaFuture: ListenableFuture[T]): Future[T] = { - val scalaPromise = Promise[T]() - Futures.addCallback( - guavaFuture, - new FutureCallback[T] { - def onSuccess(result: T): Unit = scalaPromise.success(result) - - def onFailure(exception: Throwable): Unit = scalaPromise.failure(exception) - } - ) - scalaPromise.future - } -} From c488c5ae3938351372ab33c86271b8733bc64079 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 3 Dec 2019 16:04:58 -0600 Subject: [PATCH 15/62] A bit of refactring to remove some of the larger fn definitions in the action impls --- .../plugin/request/CqlRequestAction.scala | 85 ++++++++------- .../plugin/request/GraphRequestAction.scala | 101 ++++++++++-------- 2 files changed, 102 insertions(+), 84 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index 66c0b0a..d6bae6b 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -63,48 +63,45 @@ class CqlRequestAction[T <: Statement[_]](val name: String, }) } - def sendQuery(session: Session): Unit = { - val enableCO = Boolean.getBoolean("gatling.dse.plugin.measure_service_time") - val responseTimeBuilder: ResponseTimeBuilder = if (enableCO) { - // The throughput checker is useless in CO affected scenarios since throughput is not known in advance - COAffectedResponseTime.startingNow(gatlingTimingSource) - } else { - ThroughputVerifier.checkForGatlingOverloading(session, gatlingTimingSource) - GatlingResponseTime.startedByGatling(session, gatlingTimingSource) - } - val stmt = safely()(dseAttributes.statement.buildFromSession(session)) + private def updateStatement(stmt:T):T = { + // global options + dseAttributes.cl.map(stmt.setConsistencyLevel) + dseAttributes.userOrRole.map(stmt.executingAs) + dseAttributes.readTimeout.map(stmt.setReadTimeoutMillis) + dseAttributes.idempotent.map(stmt.setIdempotent) + dseAttributes.defaultTimestamp.map(stmt.setDefaultTimestamp) - stmt.onFailure(err => { - handleFailure(session, responseTimeBuilder, err) - }) - - stmt.onSuccess({ stmt => - // global options - dseAttributes.cl.map(stmt.setConsistencyLevel) - dseAttributes.userOrRole.map(stmt.executingAs) - dseAttributes.readTimeout.map(stmt.setReadTimeoutMillis) - dseAttributes.idempotent.map(stmt.setIdempotent) - dseAttributes.defaultTimestamp.map(stmt.setDefaultTimestamp) + // CQL Only Options + dseAttributes.outGoingPayload.map(x => stmt.setOutgoingPayload(x.asJava)) + dseAttributes.serialCl.map(stmt.setSerialConsistencyLevel) + dseAttributes.retryPolicy.map(stmt.setRetryPolicy) + dseAttributes.fetchSize.map(stmt.setFetchSize) + dseAttributes.pagingState.map(stmt.setPagingState) + if (dseAttributes.enableTrace.isDefined && dseAttributes.enableTrace.get) { + stmt.enableTracing + } + stmt + } - // CQL Only Options - dseAttributes.outGoingPayload.map(x => stmt.setOutgoingPayload(x.asJava)) - dseAttributes.serialCl.map(stmt.setSerialConsistencyLevel) - dseAttributes.retryPolicy.map(stmt.setRetryPolicy) - dseAttributes.fetchSize.map(stmt.setFetchSize) - dseAttributes.pagingState.map(stmt.setPagingState) - if (dseAttributes.enableTrace.isDefined && dseAttributes.enableTrace.get) { - stmt.enableTracing - } + private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(stmt:T): Unit = { - val responseHandler = new CqlResponseHandler(next, session, system, statsEngine, responseTimeBuilder, stmt, dseAttributes, metricsLogger) - implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) - FutureConverters - .toScala(protocol.session.executeAsync(stmt)) - .onComplete(t => DseRequestActor.recordResult(RecordResult(t, responseHandler))) - }) + val responseHandler = + new CqlResponseHandler( + next, + session, + system, + statsEngine, + responseTimeBuilder, + updateStatement(stmt), + dseAttributes, + metricsLogger) + implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) + FutureConverters + .toScala(protocol.session.executeAsync(stmt)) + .onComplete(t => DseRequestActor.recordResult(RecordResult(t, responseHandler))) } - private def handleFailure(session: Session, responseTimeBuilder: ResponseTimeBuilder, err: String) = { + private def handleFailure(session: Session, responseTimeBuilder: ResponseTimeBuilder)(err: String) = { val responseTime: ResponseTime = responseTimeBuilder.build() val logUuid = UUID.randomUUID.toString val tagString = if (session.groupHierarchy.nonEmpty) session.groupHierarchy.mkString("/") + "/" + dseAttributes.tag else dseAttributes.tag @@ -115,4 +112,18 @@ class CqlRequestAction[T <: Statement[_]](val name: String, logger.error("[{}] {} - Err: {} - Attrs: {}", logUuid, tagString, err, session.attributes.mkString(",")) next ! session.markAsFailed } + + def sendQuery(session: Session): Unit = { + val enableCO = Boolean.getBoolean("gatling.dse.plugin.measure_service_time") + val responseTimeBuilder: ResponseTimeBuilder = if (enableCO) { + // The throughput checker is useless in CO affected scenarios since throughput is not known in advance + COAffectedResponseTime.startingNow(gatlingTimingSource) + } else { + ThroughputVerifier.checkForGatlingOverloading(session, gatlingTimingSource) + GatlingResponseTime.startedByGatling(session, gatlingTimingSource) + } + val stmt = safely()(dseAttributes.statement.buildFromSession(session)) + stmt.onFailure(handleFailure(session,responseTimeBuilder)) + stmt.onSuccess(handleSuccess(session,responseTimeBuilder)) + } } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index 3709725..e2bb6b7 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -61,6 +61,58 @@ class GraphRequestAction[T <: GraphStatement[_]](val name: String, }) } + private def updateStatement(stmt:T):T = { + + // global options + dseAttributes.cl.map(gStmt.setConsistencyLevel) + dseAttributes.defaultTimestamp.map(gStmt.setDefaultTimestamp) + dseAttributes.userOrRole.map(gStmt.executingAs) + dseAttributes.readTimeout.map(gStmt.setReadTimeoutMillis) + dseAttributes.idempotent.map(gStmt.setIdempotent) + + // Graph only Options + dseAttributes.readCL.map(gStmt.setReadConsistencyLevel) + dseAttributes.writeCL.map(gStmt.setWriteConsistencyLevel) + dseAttributes.graphLanguage.map(gStmt.setGraphLanguage) + dseAttributes.graphName.map(gStmt.setGraphName) + dseAttributes.graphSource.map(gStmt.setGraphSource) + dseAttributes.graphTransformResults.map(gStmt.setTransformResultFunction) + + if (dseAttributes.graphInternalOptions.isDefined) { + dseAttributes.graphInternalOptions.get.foreach { t => + gStmt.setGraphInternalOption(t._1, t._2) + } + } + + if (dseAttributes.isSystemQuery.isDefined && dseAttributes.isSystemQuery.get) { + gStmt.setSystemQuery() + } + stmt + } + + private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(stmt:T): Unit = { + + val responseHandler = + new GraphResponseHandler( + next, session, system, statsEngine, responseTimeBuilder, updateStatement(stmt), dseAttributes, metricsLogger) + implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) + FutureConverters + .toScala(protocol.session.executeAsync(stmt)) + .onComplete(t => DseRequestActor.recordResult(RecordResult(t, responseHandler))) + } + + private def handleFailure(session: Session, responseTimeBuilder: ResponseTimeBuilder)(err: String) = { + + val responseTime = responseTimeBuilder.build() + val logUuid = UUID.randomUUID.toString + val tagString = if (session.groupHierarchy.nonEmpty) session.groupHierarchy.mkString("/") + "/" + dseAttributes.tag else dseAttributes.tag + + statsEngine.logResponse(session, name, responseTime.toGatlingResponseTimings, KO, None, + Some(s"$tagString - Preparing: ${err.take(50)}"), List(responseTime.latencyIn(MICROSECONDS), "PRE", logUuid)) + + logger.error("[{}] {} - Preparing: {} - Attrs: {}", logUuid, tagString, err, session.attributes.mkString(",")) + next ! session.markAsFailed + } def sendQuery(session: Session): Unit = { val enableCO = Boolean.getBoolean("gatling.dse.plugin.measure_service_time") @@ -72,52 +124,7 @@ class GraphRequestAction[T <: GraphStatement[_]](val name: String, GatlingResponseTime.startedByGatling(session, gatlingTimingSource) } val stmt = dseAttributes.statement.buildFromSession(session) - - stmt.onFailure(err => { - val responseTime = responseTimeBuilder.build() - val logUuid = UUID.randomUUID.toString - val tagString = if (session.groupHierarchy.nonEmpty) session.groupHierarchy.mkString("/") + "/" + dseAttributes.tag else dseAttributes.tag - - statsEngine.logResponse(session, name, responseTime.toGatlingResponseTimings, KO, None, - Some(s"$tagString - Preparing: ${err.take(50)}"), List(responseTime.latencyIn(MICROSECONDS), "PRE", logUuid)) - - logger.error("[{}] {} - Preparing: {} - Attrs: {}", logUuid, tagString, err, session.attributes.mkString(",")) - next ! session.markAsFailed - }) - - stmt.onSuccess({ gStmt => - // global options - dseAttributes.cl.map(gStmt.setConsistencyLevel) - dseAttributes.defaultTimestamp.map(gStmt.setDefaultTimestamp) - dseAttributes.userOrRole.map(gStmt.executingAs) - dseAttributes.readTimeout.map(gStmt.setReadTimeoutMillis) - dseAttributes.idempotent.map(gStmt.setIdempotent) - - // Graph only Options - dseAttributes.readCL.map(gStmt.setReadConsistencyLevel) - dseAttributes.writeCL.map(gStmt.setWriteConsistencyLevel) - dseAttributes.graphLanguage.map(gStmt.setGraphLanguage) - dseAttributes.graphName.map(gStmt.setGraphName) - dseAttributes.graphSource.map(gStmt.setGraphSource) - dseAttributes.graphTransformResults.map(gStmt.setTransformResultFunction) - - if (dseAttributes.graphInternalOptions.isDefined) { - dseAttributes.graphInternalOptions.get.foreach { t => - gStmt.setGraphInternalOption(t._1, t._2) - } - } - - if (dseAttributes.isSystemQuery.isDefined && dseAttributes.isSystemQuery.get) { - gStmt.setSystemQuery() - } - - val responseHandler = - new GraphResponseHandler( - next, session, system, statsEngine, responseTimeBuilder, gStmt, dseAttributes, metricsLogger) - implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) - FutureConverters - .toScala(protocol.session.executeAsync(gStmt)) - .onComplete(t => DseRequestActor.recordResult(RecordResult(t, responseHandler))) - }) + stmt.onFailure(handleFailure(session, responseTimeBuilder)) + stmt.onSuccess(handleSuccess(session, responseTimeBuilder)) } } From 632eea8d4fdd6835f70a5e73362f421ef262581e Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 3 Dec 2019 16:08:46 -0600 Subject: [PATCH 16/62] Fixing some weird import ordering issues --- .../com/datastax/gatling/plugin/model/DseCqlAttributes.scala | 2 +- .../gatling/plugin/model/DseCqlAttributesBuilder.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index 96321a0..ae032b9 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -8,9 +8,9 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer -import com.datastax.oss.driver.api.core.retry.RetryPolicy import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Statement +import com.datastax.oss.driver.api.core.retry.RetryPolicy import com.datastax.gatling.plugin.response.{CqlResponse, DseResponse} import io.gatling.core.check.Check diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 587dc20..dc85847 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -8,11 +8,11 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer -import com.datastax.oss.driver.api.core.retry.RetryPolicy import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.cql.Statement +import com.datastax.oss.driver.api.core.retry.RetryPolicy import com.datastax.gatling.plugin.checks.{DseCqlCheck, GenericCheck} import com.datastax.gatling.plugin.request.CqlRequestActionBuilder -import com.datastax.oss.driver.api.core.cql.Statement /** From b55391fdfcd530d7ebf75733dbf83c16f6243d82 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 4 Dec 2019 13:37:27 -0600 Subject: [PATCH 17/62] Conversion to use a builder rather than a (template) statement in CqlRequestAction... should make supporting the setting of various options from DseCqlAttributes considerably easier. --- .../plugin/model/DseCqlAttributes.scala | 4 +- .../plugin/model/DseCqlStatements.scala | 53 +++++++++++-------- .../plugin/request/CqlRequestAction.scala | 38 ++++++------- .../plugin/request/GraphRequestAction.scala | 9 +++- 4 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index ae032b9..ed36d29 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -9,7 +9,7 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer import com.datastax.oss.driver.api.core.ConsistencyLevel -import com.datastax.oss.driver.api.core.cql.Statement +import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} import com.datastax.oss.driver.api.core.retry.RetryPolicy import com.datastax.gatling.plugin.response.{CqlResponse, DseResponse} import io.gatling.core.check.Check @@ -38,7 +38,7 @@ import io.gatling.core.check.Check * */ case class DseCqlAttributes[T <: Statement[_]](tag: String, - statement: DseStatement[T], + statement: DseStatement[StatementBuilder[_,T]], cl: Option[ConsistencyLevel] = None, cqlChecks: List[Check[CqlResponse]] = List.empty, genericChecks: List[Check[DseResponse]] = List.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 3eb09f1..2a58e0a 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -18,7 +18,7 @@ import scala.collection.JavaConverters._ import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseCqlStatement[T <: Statement[_]] extends DseStatement[T] { +trait DseCqlStatement[T <: Statement[T]] extends DseStatement[T] { def buildFromSession(session: Session): Validation[T] } @@ -27,9 +27,11 @@ trait DseCqlStatement[T <: Statement[_]] extends DseStatement[T] { * * @param statement the statement to execute */ -case class DseCqlSimpleStatement(statement: SimpleStatement) extends DseCqlStatement[SimpleStatement] { - def buildFromSession(gatlingSession: Session): Validation[SimpleStatement] = { - statement.success +case class DseCqlSimpleStatement(statement: SimpleStatement) + extends DseCqlStatement[StatementBuilder[_,SimpleStatement]] { + + def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,SimpleStatement]] = { + SimpleStatement.builder(statement).success } } @@ -39,13 +41,15 @@ case class DseCqlSimpleStatement(statement: SimpleStatement) extends DseCqlState * @param preparedStatement the prepared statement on which to bind parameters */ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement) - extends DseCqlStatement[BoundStatement] { + extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { - def buildFromSession(gatlingSession: Session): Validation[BoundStatement] = - bindParams( + def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { + val template:BoundStatement = bindParams( gatlingSession, preparedStatement.bind(), - cqlTypes.getParamsMap(preparedStatement)).success + cqlTypes.getParamsMap(preparedStatement)) + new BoundStatementBuilder(template).success + } /** * Bind Gatling Session Params to CQL Statement by Name and Type @@ -73,9 +77,10 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare */ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - params: Expression[AnyRef]*) extends DseCqlStatement[BoundStatement] { + params: Expression[AnyRef]*) + extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { - def buildFromSession(gatlingSession: Session): Validation[BoundStatement] = { + def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { val parsedParams: Seq[Validation[AnyRef]] = params.map(param => param(gatlingSession)) if (parsedParams.exists(_.isInstanceOf[Failure])) { val firstError = StringBuilder.newBuilder @@ -85,7 +90,8 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt .onFailure(msg => firstError.append(msg)) firstError.toString().failure } else { - preparedStatement.bind(parsedParams.map(_.get): _*).success + val template:BoundStatement = preparedStatement.bind(parsedParams.map(_.get): _*) + new BoundStatementBuilder(template).success } } } @@ -97,7 +103,8 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt */ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - sessionKeys: Seq[String]) extends DseCqlStatement[BoundStatement] { + sessionKeys: Seq[String]) + extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { /** * Apply the Gatling session params to the Prepared statement @@ -105,8 +112,9 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param gatlingSession DseSession * @return */ - def buildFromSession(gatlingSession: Session): Validation[BoundStatement] = { - bindParams(gatlingSession, preparedStatement.bind(), sessionKeys).success + def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { + val template:BoundStatement = bindParams(gatlingSession, preparedStatement.bind(), sessionKeys) + new BoundStatementBuilder(template).success } /** @@ -140,16 +148,16 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param statements CQL Prepared Statements */ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, statements: Seq[PreparedStatement]) - extends DseCqlStatement[BatchStatement] { + extends DseCqlStatement[StatementBuilder[_,BatchStatement]] { - def buildFromSession(gatlingSession: Session): Validation[BatchStatement] = { + def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BatchStatement]] = { val batch = BatchStatement.builder(DefaultBatchType.LOGGED) statements.foreach(s => batch.addStatement(bindParams(gatlingSession, s, cqlTypes.getParamsMap(s)))) - batch.build().success + batch.success } @@ -184,9 +192,9 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * @param payloadRef session variable for custom payload */ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: String) - extends DseCqlStatement[SimpleStatement] { + extends DseCqlStatement[StatementBuilder[_,SimpleStatement]] { - def buildFromSession(gatlingSession: Session): Validation[SimpleStatement] = { + def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,SimpleStatement]] = { if (!gatlingSession.contains(payloadRef)) { throw new DseCqlStatementException(s"Passed sessionKey: {$payloadRef} does not exist in Session.") @@ -196,11 +204,10 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: val payload = gatlingSession(payloadRef).as[Map[String, ByteBuffer]].asJava statement.setCustomPayload(payload) } match { - case TrySuccess(stmt) => stmt.success + case TrySuccess(stmt) => SimpleStatement.builder(stmt).success case TryFailure(error) => error.getMessage.failure } } - } /** @@ -210,9 +217,9 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: * @param sessionKey the session key which is associated to a PreparedStatement */ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, sessionKey: String) - extends DseCqlStatement[BoundStatement] { + extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { - def buildFromSession(gatlingSession: Session): Validation[BoundStatement] = { + def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { if (!gatlingSession.contains(sessionKey)) { throw new DseCqlStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index d6bae6b..fc21f13 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -17,7 +17,7 @@ import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.DseCqlAttributes import com.datastax.gatling.plugin.response.CqlResponseHandler import com.datastax.gatling.plugin.utils._ -import com.datastax.oss.driver.api.core.cql.Statement +import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} import io.gatling.commons.stats.KO import io.gatling.commons.validation.safely import io.gatling.core.action.{Action, ExitableAction} @@ -46,7 +46,7 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to * other Gatling data writers, like the console reporter. */ -class CqlRequestAction[T <: Statement[_]](val name: String, +class CqlRequestAction[T <: Statement[T]](val name: String, val next: Action, val system: ActorSystem, val statsEngine: StatsEngine, @@ -63,36 +63,38 @@ class CqlRequestAction[T <: Statement[_]](val name: String, }) } - private def updateStatement(stmt:T):T = { + private def buildStatement(builder:StatementBuilder[_,T]):T = { + // global options - dseAttributes.cl.map(stmt.setConsistencyLevel) - dseAttributes.userOrRole.map(stmt.executingAs) - dseAttributes.readTimeout.map(stmt.setReadTimeoutMillis) - dseAttributes.idempotent.map(stmt.setIdempotent) - dseAttributes.defaultTimestamp.map(stmt.setDefaultTimestamp) + dseAttributes.cl.map(builder.setConsistencyLevel) + dseAttributes.userOrRole.map(builder.executingAs) + dseAttributes.readTimeout.map(builder.setReadTimeoutMillis) + dseAttributes.idempotent.map(builder.setIdempotent) + dseAttributes.defaultTimestamp.map(builder.setDefaultTimestamp) // CQL Only Options - dseAttributes.outGoingPayload.map(x => stmt.setOutgoingPayload(x.asJava)) - dseAttributes.serialCl.map(stmt.setSerialConsistencyLevel) - dseAttributes.retryPolicy.map(stmt.setRetryPolicy) - dseAttributes.fetchSize.map(stmt.setFetchSize) - dseAttributes.pagingState.map(stmt.setPagingState) + dseAttributes.outGoingPayload.map(x => builder.setOutgoingPayload(x.asJava)) + dseAttributes.serialCl.map(builder.setSerialConsistencyLevel) + dseAttributes.retryPolicy.map(builder.setRetryPolicy) + dseAttributes.fetchSize.map(builder.setFetchSize) + dseAttributes.pagingState.map(builder.setPagingState) if (dseAttributes.enableTrace.isDefined && dseAttributes.enableTrace.get) { - stmt.enableTracing + builder.enableTracing } - stmt + builder.build() } - private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(stmt:T): Unit = { + private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:StatementBuilder[_,T]): Unit = { + val stmt:T = buildStatement(builder) val responseHandler = - new CqlResponseHandler( + new CqlResponseHandler[T]( next, session, system, statsEngine, responseTimeBuilder, - updateStatement(stmt), + stmt, dseAttributes, metricsLogger) implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index e2bb6b7..c319190 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -94,7 +94,14 @@ class GraphRequestAction[T <: GraphStatement[_]](val name: String, val responseHandler = new GraphResponseHandler( - next, session, system, statsEngine, responseTimeBuilder, updateStatement(stmt), dseAttributes, metricsLogger) + next, + session, + system, + statsEngine, + responseTimeBuilder, + updateStatement(stmt), + dseAttributes, + metricsLogger) implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) FutureConverters .toScala(protocol.session.executeAsync(stmt)) From b45d2de3343a2957fc724751a05c0cc07f830987 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 4 Dec 2019 14:14:36 -0600 Subject: [PATCH 18/62] Convert graph infrastructure to use builders coming off of DseSession rather than Statement directly --- .../plugin/model/DseCqlAttributes.scala | 2 +- .../model/DseCqlAttributesBuilder.scala | 2 +- .../plugin/model/DseCqlStatements.scala | 1 - .../plugin/model/DseGraphAttributes.scala | 6 +-- .../model/DseGraphAttributesBuilder.scala | 3 +- .../plugin/model/DseGraphStatements.scala | 42 ++++++++++--------- .../plugin/request/CqlRequestAction.scala | 2 +- .../plugin/request/GraphRequestAction.scala | 39 ++++++++--------- 8 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index ed36d29..5574ce1 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -37,7 +37,7 @@ import io.gatling.core.check.Check * @param cqlStatements String version of the CQL statement that is sent * */ -case class DseCqlAttributes[T <: Statement[_]](tag: String, +case class DseCqlAttributes[T <: Statement[T]](tag: String, statement: DseStatement[StatementBuilder[_,T]], cl: Option[ConsistencyLevel] = None, cqlChecks: List[Check[CqlResponse]] = List.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index dc85847..dedd274 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -20,7 +20,7 @@ import com.datastax.gatling.plugin.request.CqlRequestActionBuilder * * @param attr Addition Attributes */ -case class DseCqlAttributesBuilder[T <: Statement[_]](attr: DseCqlAttributes[T]) { +case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) { /** * Builds to final action to run * diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 2a58e0a..9250d10 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -17,7 +17,6 @@ import io.gatling.core.session._ import scala.collection.JavaConverters._ import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} - trait DseCqlStatement[T <: Statement[T]] extends DseStatement[T] { def buildFromSession(session: Session): Validation[T] } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index b902b5e..089e9c4 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -8,7 +8,7 @@ package com.datastax.gatling.plugin.model import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Row -import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement} +import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} /** @@ -34,8 +34,8 @@ import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} * @param graphInternalOptions Query-specific options not available in the driver public API * @param graphTransformResults Function to use in order to transform a row into a Graph node */ -case class DseGraphAttributes[T <: GraphStatement[_]](tag: String, - statement: DseStatement[T], +case class DseGraphAttributes[T <: GraphStatement[T]](tag: String, + statement: DseStatement[GraphStatementBuilderBase[_,T]], cl: Option[ConsistencyLevel] = None, graphChecks: List[DseGraphCheck] = List.empty, genericChecks: List[GenericCheck] = List.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index 44cfa98..5fac5f5 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -11,7 +11,6 @@ import com.datastax.oss.driver.api.core.cql.Row import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} import com.datastax.gatling.plugin.request.GraphRequestActionBuilder -import io.gatling.core.action.builder.ActionBuilder import com.datastax.oss.driver.shaded.guava.common.base.Function @@ -20,7 +19,7 @@ import com.datastax.oss.driver.shaded.guava.common.base.Function * * @param attr Addition Attributes */ -case class DseGraphAttributesBuilder[T <: GraphStatement[_]](attr: DseGraphAttributes[T]) { +case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttributes[T]) { /** * Builds to final action to run * diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index b5e66a7..fb88155 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, GraphStatement, ScriptGraphStatement, ScriptGraphStatementBuilder} +import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, GraphStatement, GraphStatementBuilderBase, ScriptGraphStatement, ScriptGraphStatementBuilder} import com.datastax.gatling.plugin.exceptions.DseGraphStatementException import io.gatling.commons.validation._ import io.gatling.core.session.{Expression, Session} @@ -14,7 +14,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} - trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[T] { def buildFromSession(session: Session): Validation[T] } @@ -24,9 +23,11 @@ trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[T] { * * @param statement the Gremlin String to execute */ -case class GraphStringStatement(statement: Expression[String]) extends DseGraphStatement[ScriptGraphStatement] { - def buildFromSession(gatlingSession: Session): Validation[ScriptGraphStatement] = { - statement(gatlingSession).flatMap(stmt => ScriptGraphStatement.builder(stmt).build().success) +case class GraphStringStatement(statement: Expression[String]) + extends DseGraphStatement[GraphStatementBuilderBase[_,ScriptGraphStatement]] { + + def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,ScriptGraphStatement]] = { + statement(gatlingSession).flatMap(stmt => ScriptGraphStatement.builder(stmt).success) } } @@ -36,9 +37,10 @@ case class GraphStringStatement(statement: Expression[String]) extends DseGraphS * @param statement the Fluent Statement */ case class GraphFluentStatement(statement: FluentGraphStatement) - extends DseGraphStatement[FluentGraphStatement] { - def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatement] = { - statement.success + extends DseGraphStatement[GraphStatementBuilderBase[_,FluentGraphStatement]] { + + def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { + FluentGraphStatement.builder(statement).success } } @@ -50,9 +52,10 @@ case class GraphFluentStatement(statement: FluentGraphStatement) * and returns a fluent Graph Statement */ case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphStatement) - extends DseGraphStatement[FluentGraphStatement] { - def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatement] = { - lambda(gatlingSession).success + extends DseGraphStatement[GraphStatementBuilderBase[_,FluentGraphStatement]] { + + def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { + FluentGraphStatement.builder(lambda(gatlingSession)).success } } @@ -63,17 +66,18 @@ case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphSta * @param sessionKey Place a GraphTraversal in your session with this key name */ case class GraphFluentSessionKey(sessionKey: String) - extends DseGraphStatement[FluentGraphStatement] { - def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatement] = { + extends DseGraphStatement[GraphStatementBuilderBase[_,FluentGraphStatement]] { + + def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { if (!gatlingSession.contains(sessionKey)) { throw new DseGraphStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } Try { - FluentGraphStatement.builder(gatlingSession(sessionKey).as[GraphTraversal[_, _]]).build() + FluentGraphStatement.builder(gatlingSession(sessionKey).as[GraphTraversal[_, _]]) } match { - case TrySuccess(stmt) => stmt.success + case TrySuccess(builder) => builder.success case TryFailure(error) => error.getMessage.failure } } @@ -86,7 +90,7 @@ case class GraphFluentSessionKey(sessionKey: String) * @param sessionKeys Gatling session param keys mapped to their bind name, to allow name override */ case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys: Map[String, String]) - extends DseGraphStatement[ScriptGraphStatement] { + extends DseGraphStatement[GraphStatementBuilderBase[_,ScriptGraphStatement]] { /** * Apply the Gatling session params passed to the GraphStatement @@ -95,7 +99,7 @@ case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys * @return */ - def buildFromSession(gatlingSession: Session): Validation[ScriptGraphStatement] = { + def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,ScriptGraphStatement]] = { Try { sessionKeys foreach { _ match { @@ -103,9 +107,9 @@ case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys case _ => throw new RuntimeException() } } - builder.build() + builder } match { - case TrySuccess(stmt) => stmt.success + case TrySuccess(builder) => builder.success case TryFailure(error) => error.getMessage.failure } } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index fc21f13..0adaa94 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -81,7 +81,7 @@ class CqlRequestAction[T <: Statement[T]](val name: String, if (dseAttributes.enableTrace.isDefined && dseAttributes.enableTrace.get) { builder.enableTracing } - builder.build() + builder.build } private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:StatementBuilder[_,T]): Unit = { diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index c319190..0abb988 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -12,7 +12,7 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem -import com.datastax.dse.driver.api.core.graph.GraphStatement +import com.datastax.dse.driver.api.core.graph.{GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.DseGraphAttributes @@ -44,7 +44,7 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to * other Gatling data writers, like the console reporter. */ -class GraphRequestAction[T <: GraphStatement[_]](val name: String, +class GraphRequestAction[T <: GraphStatement[T]](val name: String, val next: Action, val system: ActorSystem, val statsEngine: StatsEngine, @@ -61,37 +61,38 @@ class GraphRequestAction[T <: GraphStatement[_]](val name: String, }) } - private def updateStatement(stmt:T):T = { + private def buildStatement(builder:GraphStatementBuilderBase[_,T]):T = { // global options - dseAttributes.cl.map(gStmt.setConsistencyLevel) - dseAttributes.defaultTimestamp.map(gStmt.setDefaultTimestamp) - dseAttributes.userOrRole.map(gStmt.executingAs) - dseAttributes.readTimeout.map(gStmt.setReadTimeoutMillis) - dseAttributes.idempotent.map(gStmt.setIdempotent) + dseAttributes.cl.map(builder.setConsistencyLevel) + dseAttributes.defaultTimestamp.map(builder.setDefaultTimestamp) + dseAttributes.userOrRole.map(builder.executingAs) + dseAttributes.readTimeout.map(builder.setReadTimeoutMillis) + dseAttributes.idempotent.map(builder.setIdempotent) // Graph only Options - dseAttributes.readCL.map(gStmt.setReadConsistencyLevel) - dseAttributes.writeCL.map(gStmt.setWriteConsistencyLevel) - dseAttributes.graphLanguage.map(gStmt.setGraphLanguage) - dseAttributes.graphName.map(gStmt.setGraphName) - dseAttributes.graphSource.map(gStmt.setGraphSource) - dseAttributes.graphTransformResults.map(gStmt.setTransformResultFunction) + dseAttributes.readCL.map(builder.setReadConsistencyLevel) + dseAttributes.writeCL.map(builder.setWriteConsistencyLevel) + dseAttributes.graphLanguage.map(builder.setGraphLanguage) + dseAttributes.graphName.map(builder.setGraphName) + dseAttributes.graphSource.map(builder.setGraphSource) + dseAttributes.graphTransformResults.map(builder.setTransformResultFunction) if (dseAttributes.graphInternalOptions.isDefined) { dseAttributes.graphInternalOptions.get.foreach { t => - gStmt.setGraphInternalOption(t._1, t._2) + builder.setGraphInternalOption(t._1, t._2) } } if (dseAttributes.isSystemQuery.isDefined && dseAttributes.isSystemQuery.get) { - gStmt.setSystemQuery() + builder.setSystemQuery() } - stmt + builder.build } - private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(stmt:T): Unit = { + private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:GraphStatementBuilderBase[_,T]): Unit = { + val stmt:T = buildStatement(builder) val responseHandler = new GraphResponseHandler( next, @@ -99,7 +100,7 @@ class GraphRequestAction[T <: GraphStatement[_]](val name: String, system, statsEngine, responseTimeBuilder, - updateStatement(stmt), + stmt, dseAttributes, metricsLogger) implicit val sameThreadExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutorService(dseExecutorService) From 0a9d372dd29823453e340911fc22822b330f4785 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 5 Dec 2019 14:23:09 -0600 Subject: [PATCH 19/62] Convert CqlPreparedStatementUtil to work with Bindable instances rather than statements specifically. Facilitates conversion to builders generally. Also converted CQL statements to use builders in order to address immutable statement classes --- .../plugin/model/DseCqlStatements.scala | 75 ++++---- .../utils/CqlPreparedStatementUtil.scala | 160 +++++++++--------- 2 files changed, 117 insertions(+), 118 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 9250d10..5790d61 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -54,17 +54,21 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare * Bind Gatling Session Params to CQL Statement by Name and Type * * @param gatlingSession Gatling Session - * @param boundStatement CQL Prepared Statement + * @param template CQL Prepared Statement * @param queryParams CQL Query Named Params and Types * @return */ - protected def bindParams(gatlingSession: Session, boundStatement: BoundStatement, + protected def bindParams(gatlingSession: Session, template: BoundStatement, queryParams: Map[String, Int]): BoundStatement = { - queryParams.foreach { - case (gatlingSessionKey, valType) => - cqlTypes.bindParamByName(gatlingSession, boundStatement, valType, gatlingSessionKey) - } - boundStatement + val completedBuilder = + queryParams.foldLeft(new BoundStatementBuilder(template)) { + (builder, kv) => + kv match { + case (gatlingSessionKey, valType) => + cqlTypes.bindParamByName(gatlingSession, builder, valType, gatlingSessionKey) + } + } + completedBuilder.build() } } @@ -120,24 +124,25 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * Bind the Gatling session params to the CQL Prepared Statement * * @param gatlingSession Gatling Session - * @param boundStatement CQL Prepared Statement + * @param template CQL Prepared Statement * @param sessionKeys List of session params to apply, put in order of query ?'s * @return */ - protected def bindParams(gatlingSession: Session, boundStatement: BoundStatement, + protected def bindParams(gatlingSession: Session, template: BoundStatement, sessionKeys: Seq[String]): BoundStatement = { - val params = cqlTypes.getParamsList(preparedStatement) - var cnt = 0 - - sessionKeys.foreach { gatlingSessionKey => - cqlTypes.bindParamByOrder(gatlingSession, boundStatement, params(cnt), gatlingSessionKey, cnt) - cnt += 1 + val completedBuilder = + sessionKeys.foldLeft((0,new BoundStatementBuilder(template))) { + (acc, gatlingSessionKey) => + acc match { + case (cnt, builder) => + (cnt + 1, cqlTypes.bindParamByOrder(gatlingSession, builder, params(cnt), gatlingSessionKey, cnt)) + } + } + completedBuilder match { + case (_, builder) => builder.build() } - - boundStatement } - } @@ -150,13 +155,9 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme extends DseCqlStatement[StatementBuilder[_,BatchStatement]] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BatchStatement]] = { - - val batch = BatchStatement.builder(DefaultBatchType.LOGGED) - - statements.foreach(s => - batch.addStatement(bindParams(gatlingSession, s, cqlTypes.getParamsMap(s)))) - - batch.success + val builder:BatchStatementBuilder = BatchStatement.builder(DefaultBatchType.LOGGED) + val batchables = statements.map(bindParams(gatlingSession)) + builder.addStatements(batchables:_*).success } @@ -165,21 +166,20 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * * @param gatlingSession Gatling Session * @param statement CQL Prepared Statement - * @param queryParams CQL Query Named Params and Types * @return */ - protected def bindParams(gatlingSession: Session, statement: PreparedStatement, - queryParams: Map[String, Int]): BoundStatement = { - - val boundStatement = statement.bind() - - if (queryParams.nonEmpty) { - queryParams.foreach { - case (gatlingSessionKey, valType) => - cqlTypes.bindParamByName(gatlingSession, boundStatement, valType, gatlingSessionKey) + protected def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundStatement = { + val queryParams: Map[String, Int] = cqlTypes.getParamsMap(statement) + val completedBuilder = + queryParams.foldLeft(new BoundStatementBuilder(statement.bind())) { + + (builder, kv) => + kv match { + case (gatlingSessionKey, valType) => + cqlTypes.bindParamByName(gatlingSession, builder, valType, gatlingSessionKey) + } } - } - boundStatement + completedBuilder.build() } } @@ -194,7 +194,6 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: extends DseCqlStatement[StatementBuilder[_,SimpleStatement]] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,SimpleStatement]] = { - if (!gatlingSession.contains(payloadRef)) { throw new DseCqlStatementException(s"Passed sessionKey: {$payloadRef} does not exist in Session.") } diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index b3aeba5..a89fe0f 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -28,12 +28,16 @@ trait CqlPreparedStatementUtil { protected val hourMinSecRegEx: Regex = """(\d+):(\d+):(\d+)""".r protected val hourMinSecNanoRegEx: Regex = """(\d+):(\d+):(\d+).(\d+{1,9})""".r - def bindParamByOrder(gatlingSession: Session, - boundStatement: BoundStatement, paramType: Int, - paramName: String, key: Int): BoundStatement + def bindParamByOrder[T <: Bindable[T]](gatlingSession: Session, + bindable: T, + paramType: Int, + paramName: String, + key: Int): T - def bindParamByName(gatlingSession: Session, boundStatement: BoundStatement, paramType: Int, - paramName: String): BoundStatement + def bindParamByName[T <: Bindable[T]](gatlingSession: Session, + bindable: T, + paramType: Int, + paramName: String): T def getParamsMap(preparedStatement: PreparedStatement): Map[String, Int] @@ -50,86 +54,83 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * Bind CQL Prepared statement params by key order * * @param gatlingSession Gatling Session - * @param boundStatement CQL BoundStatement + * @param bindable CQL Bindable impl * @param paramType Type of param ie String, int, boolean * @param paramName Gatling Session Attribute Name * @param key Key/Order of param */ - def bindParamByOrder(gatlingSession: Session, boundStatement: BoundStatement, paramType: Int, - paramName: String, key: Int): BoundStatement = { + def bindParamByOrder[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: Int, + paramName: String, key: Int): T = { if (!gatlingSession.attributes.contains(paramName)) { - if (boundStatement.isSet(paramName)) { - boundStatement.unset(paramName) - } - return boundStatement + return if (bindable.isSet(paramName)) { + bindable.unset(paramName) + } else { bindable } } val stringClz = classOf[String] gatlingSession.attributes.get(paramName) match { case Some(null) => - boundStatement.setToNull(paramName) - boundStatement + bindable.setToNull(paramName) case Some(None) => - if (boundStatement.isSet(paramName)) { - boundStatement.unset(paramName) - } - boundStatement + if (bindable.isSet(paramName)) { + bindable.unset(paramName) + } else { bindable } case _ => paramType match { case (VARCHAR | ASCII) => - boundStatement.setString(key, asString(gatlingSession, paramName)) + bindable.setString(key, asString(gatlingSession, paramName)) case INT => - boundStatement.setInt(key, asInteger(gatlingSession, paramName)) + bindable.setInt(key, asInteger(gatlingSession, paramName)) case BOOLEAN => - boundStatement.setBoolean(key, asBoolean(gatlingSession, paramName)) + bindable.setBoolean(key, asBoolean(gatlingSession, paramName)) case (UUID | TIMEUUID) => - boundStatement.setUuid(key, asUuid(gatlingSession, paramName)) + bindable.setUuid(key, asUuid(gatlingSession, paramName)) case FLOAT => - boundStatement.setFloat(key, asFloat(gatlingSession, paramName)) + bindable.setFloat(key, asFloat(gatlingSession, paramName)) case DOUBLE => - boundStatement.setDouble(key, asDouble(gatlingSession, paramName)) + bindable.setDouble(key, asDouble(gatlingSession, paramName)) case DECIMAL => - boundStatement.setBigDecimal(key, asDecimal(gatlingSession, paramName)) + bindable.setBigDecimal(key, asDecimal(gatlingSession, paramName)) case INET => - boundStatement.setInetAddress(key, asInet(gatlingSession, paramName)) + bindable.setInetAddress(key, asInet(gatlingSession, paramName)) case TIMESTAMP => - boundStatement.setInstant(key, asInstant(gatlingSession, paramName)) + bindable.setInstant(key, asInstant(gatlingSession, paramName)) case COUNTER => - boundStatement.setLong(key, asCounter(gatlingSession, paramName)) + bindable.setLong(key, asCounter(gatlingSession, paramName)) case BIGINT => - boundStatement.setLong(key, asBigInt(gatlingSession, paramName)) + bindable.setLong(key, asBigInt(gatlingSession, paramName)) case BLOB => - boundStatement.setByteBuffer(key, asByte(gatlingSession, paramName)) + bindable.setByteBuffer(key, asByte(gatlingSession, paramName)) case VARINT => - boundStatement.setBigInteger(key, asVarInt(gatlingSession, paramName)) + bindable.setBigInteger(key, asVarInt(gatlingSession, paramName)) case LIST => - boundStatement.setList(key, asList(gatlingSession, paramName, stringClz), stringClz) + bindable.setList(key, asList(gatlingSession, paramName, stringClz), stringClz) case SET => - boundStatement.setSet(key, asSet(gatlingSession, paramName, stringClz), stringClz) + bindable.setSet(key, asSet(gatlingSession, paramName, stringClz), stringClz) case MAP => - boundStatement.setMap(key, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) + bindable.setMap(key, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) case UDT => - boundStatement.setUdtValue(key, asUdt(gatlingSession, paramName)) + bindable.setUdtValue(key, asUdt(gatlingSession, paramName)) case TUPLE => - boundStatement.setTupleValue(key, asTuple(gatlingSession, paramName)) + bindable.setTupleValue(key, asTuple(gatlingSession, paramName)) case DATE => - boundStatement.setLocalDate(key, asLocalDate(gatlingSession, paramName)) + bindable.setLocalDate(key, asLocalDate(gatlingSession, paramName)) case SMALLINT => - boundStatement.setShort(key, asSmallInt(gatlingSession, paramName)) + bindable.setShort(key, asSmallInt(gatlingSession, paramName)) case TINYINT => - boundStatement.setByte(key, asTinyInt(gatlingSession, paramName)) + bindable.setByte(key, asTinyInt(gatlingSession, paramName)) case TIME => - boundStatement.setLocalTime(key, asTime(gatlingSession, paramName)) + bindable.setLocalTime(key, asTime(gatlingSession, paramName)) case CUSTOM => gatlingSession.attributes.get(paramName) match { case Some(p: Point) => - boundStatement.set(key, asPoint(gatlingSession, paramName), classOf[Point]) + bindable.set(key, asPoint(gatlingSession, paramName), classOf[Point]) case Some(p: LineString) => - boundStatement.set(key, asLineString(gatlingSession, paramName), classOf[LineString]) + bindable.set(key, asLineString(gatlingSession, paramName), classOf[LineString]) case Some(p: Polygon) => - boundStatement.set(key, asPolygon(gatlingSession, paramName), classOf[Polygon]) + bindable.set(key, asPolygon(gatlingSession, paramName), classOf[Polygon]) case _ => throw new UnsupportedOperationException(s"$paramName on unknown CUSTOM type") } @@ -143,85 +144,84 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * Bind CQL Prepared statement params by anem * * @param gatlingSession Gatling Session - * @param boundStatement CQL BoundStatement + * @param bindable CQL Bindable impl * @param paramType Type of param ie String, int, boolean * @param paramName Gatling Session Attribute Value */ - def bindParamByName(gatlingSession: Session, boundStatement: BoundStatement, paramType: Int, - paramName: String): BoundStatement = { + def bindParamByName[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: Int, + paramName: String): T = { if (!gatlingSession.attributes.contains(paramName)) { - if (boundStatement.isSet(paramName)) { - boundStatement.unset(paramName) - } - return boundStatement + return if (bindable.isSet(paramName)) { + bindable.unset(paramName) + } else { bindable } } val stringClz = classOf[String] gatlingSession.attributes.get(paramName) match { case Some(null) => - boundStatement.setToNull(paramName) - boundStatement + bindable.setToNull(paramName) + bindable case Some(None) => - if (boundStatement.isSet(paramName)) { - boundStatement.unset(paramName) + if (bindable.isSet(paramName)) { + bindable.unset(paramName) } - boundStatement + bindable case _ => paramType match { case (VARCHAR | ASCII) => - boundStatement.setString(paramName, asString(gatlingSession, paramName)) + bindable.setString(paramName, asString(gatlingSession, paramName)) case INT => - boundStatement.setInt(paramName, asInteger(gatlingSession, paramName)) + bindable.setInt(paramName, asInteger(gatlingSession, paramName)) case BOOLEAN => - boundStatement.setBoolean(paramName, asBoolean(gatlingSession, paramName)) + bindable.setBoolean(paramName, asBoolean(gatlingSession, paramName)) case (UUID | TIMEUUID) => - boundStatement.setUuid(paramName, asUuid(gatlingSession, paramName)) + bindable.setUuid(paramName, asUuid(gatlingSession, paramName)) case FLOAT => - boundStatement.setFloat(paramName, asFloat(gatlingSession, paramName)) + bindable.setFloat(paramName, asFloat(gatlingSession, paramName)) case DOUBLE => - boundStatement.setDouble(paramName, asDouble(gatlingSession, paramName)) + bindable.setDouble(paramName, asDouble(gatlingSession, paramName)) case DECIMAL => - boundStatement.setBigDecimal(paramName, asDecimal(gatlingSession, paramName)) + bindable.setBigDecimal(paramName, asDecimal(gatlingSession, paramName)) case INET => - boundStatement.setInetAddress(paramName, asInet(gatlingSession, paramName)) + bindable.setInetAddress(paramName, asInet(gatlingSession, paramName)) case TIMESTAMP => - boundStatement.setInstant(paramName, asInstant(gatlingSession, paramName)) + bindable.setInstant(paramName, asInstant(gatlingSession, paramName)) case BIGINT => - boundStatement.setLong(paramName, asBigInt(gatlingSession, paramName)) + bindable.setLong(paramName, asBigInt(gatlingSession, paramName)) case COUNTER => - boundStatement.setLong(paramName, asCounter(gatlingSession, paramName)) + bindable.setLong(paramName, asCounter(gatlingSession, paramName)) case BLOB => - boundStatement.setByteBuffer(paramName, asByte(gatlingSession, paramName)) + bindable.setByteBuffer(paramName, asByte(gatlingSession, paramName)) case VARINT => - boundStatement.setBigInteger(paramName, asVarInt(gatlingSession, paramName)) + bindable.setBigInteger(paramName, asVarInt(gatlingSession, paramName)) case LIST => - boundStatement.setList(paramName, asList(gatlingSession, paramName, stringClz), stringClz) + bindable.setList(paramName, asList(gatlingSession, paramName, stringClz), stringClz) case SET => - boundStatement.setSet(paramName, asSet(gatlingSession, paramName, stringClz), stringClz) + bindable.setSet(paramName, asSet(gatlingSession, paramName, stringClz), stringClz) case MAP => - boundStatement.setMap(paramName, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) + bindable.setMap(paramName, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) case UDT => - boundStatement.setUdtValue(paramName, asUdt(gatlingSession, paramName)) + bindable.setUdtValue(paramName, asUdt(gatlingSession, paramName)) case TUPLE => - boundStatement.setTupleValue(paramName, asTuple(gatlingSession, paramName)) + bindable.setTupleValue(paramName, asTuple(gatlingSession, paramName)) case DATE => - boundStatement.setLocalDate(paramName, asLocalDate(gatlingSession, paramName)) + bindable.setLocalDate(paramName, asLocalDate(gatlingSession, paramName)) case SMALLINT => - boundStatement.setShort(paramName, asSmallInt(gatlingSession, paramName)) + bindable.setShort(paramName, asSmallInt(gatlingSession, paramName)) case TINYINT => - boundStatement.setByte(paramName, asTinyInt(gatlingSession, paramName)) + bindable.setByte(paramName, asTinyInt(gatlingSession, paramName)) case TIME => - boundStatement.setLocalTime(paramName, asTime(gatlingSession, paramName)) + bindable.setLocalTime(paramName, asTime(gatlingSession, paramName)) case CUSTOM => gatlingSession.attributes.get(paramName) match { case Some(p: Point) => - boundStatement.set(paramName, asPoint(gatlingSession, paramName), classOf[Point]) + bindable.set(paramName, asPoint(gatlingSession, paramName), classOf[Point]) case Some(p: LineString) => - boundStatement.set(paramName, asLineString(gatlingSession, paramName), classOf[LineString]) + bindable.set(paramName, asLineString(gatlingSession, paramName), classOf[LineString]) case Some(p: Polygon) => - boundStatement.set(paramName, asPolygon(gatlingSession, paramName), classOf[Polygon]) + bindable.set(paramName, asPolygon(gatlingSession, paramName), classOf[Polygon]) case _ => throw new UnsupportedOperationException(s"$paramName on unknown CUSTOM type") } From ef25ca6c4747850384e4ca8ddc5324a87c03ea6a Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 5 Dec 2019 14:47:10 -0600 Subject: [PATCH 20/62] Cleaning up some type stuff --- .../plugin/model/DseCqlAttributes.scala | 2 +- .../plugin/model/DseCqlStatements.scala | 18 ++++++++---------- .../plugin/model/DseGraphAttributes.scala | 2 +- .../plugin/model/DseGraphStatements.scala | 16 +++++++--------- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index 5574ce1..b7c3cd2 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -38,7 +38,7 @@ import io.gatling.core.check.Check * */ case class DseCqlAttributes[T <: Statement[T]](tag: String, - statement: DseStatement[StatementBuilder[_,T]], + statement: DseCqlStatement[T], cl: Option[ConsistencyLevel] = None, cqlChecks: List[Check[CqlResponse]] = List.empty, genericChecks: List[Check[DseResponse]] = List.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 5790d61..7b18fb8 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -17,9 +17,7 @@ import io.gatling.core.session._ import scala.collection.JavaConverters._ import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseCqlStatement[T <: Statement[T]] extends DseStatement[T] { - def buildFromSession(session: Session): Validation[T] -} +trait DseCqlStatement[T <: Statement[T]] extends DseStatement[StatementBuilder[_,T]] /** * Simple CQL Statement from the java driver @@ -27,7 +25,7 @@ trait DseCqlStatement[T <: Statement[T]] extends DseStatement[T] { * @param statement the statement to execute */ case class DseCqlSimpleStatement(statement: SimpleStatement) - extends DseCqlStatement[StatementBuilder[_,SimpleStatement]] { + extends DseCqlStatement[SimpleStatement] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,SimpleStatement]] = { SimpleStatement.builder(statement).success @@ -40,7 +38,7 @@ case class DseCqlSimpleStatement(statement: SimpleStatement) * @param preparedStatement the prepared statement on which to bind parameters */ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement) - extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { + extends DseCqlStatement[BoundStatement] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { val template:BoundStatement = bindParams( @@ -81,7 +79,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, params: Expression[AnyRef]*) - extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { + extends DseCqlStatement[BoundStatement] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { val parsedParams: Seq[Validation[AnyRef]] = params.map(param => param(gatlingSession)) @@ -107,7 +105,7 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, sessionKeys: Seq[String]) - extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { + extends DseCqlStatement[BoundStatement] { /** * Apply the Gatling session params to the Prepared statement @@ -152,7 +150,7 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param statements CQL Prepared Statements */ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, statements: Seq[PreparedStatement]) - extends DseCqlStatement[StatementBuilder[_,BatchStatement]] { + extends DseCqlStatement[BatchStatement] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BatchStatement]] = { val builder:BatchStatementBuilder = BatchStatement.builder(DefaultBatchType.LOGGED) @@ -191,7 +189,7 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * @param payloadRef session variable for custom payload */ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: String) - extends DseCqlStatement[StatementBuilder[_,SimpleStatement]] { + extends DseCqlStatement[SimpleStatement] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,SimpleStatement]] = { if (!gatlingSession.contains(payloadRef)) { @@ -215,7 +213,7 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: * @param sessionKey the session key which is associated to a PreparedStatement */ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, sessionKey: String) - extends DseCqlStatement[StatementBuilder[_,BoundStatement]] { + extends DseCqlStatement[BoundStatement] { def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { if (!gatlingSession.contains(sessionKey)) { diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index 089e9c4..4b216df 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -35,7 +35,7 @@ import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} * @param graphTransformResults Function to use in order to transform a row into a Graph node */ case class DseGraphAttributes[T <: GraphStatement[T]](tag: String, - statement: DseStatement[GraphStatementBuilderBase[_,T]], + statement: DseGraphStatement[T], cl: Option[ConsistencyLevel] = None, graphChecks: List[DseGraphCheck] = List.empty, genericChecks: List[GenericCheck] = List.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index fb88155..db46588 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -6,7 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, GraphStatement, GraphStatementBuilderBase, ScriptGraphStatement, ScriptGraphStatementBuilder} +import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.exceptions.DseGraphStatementException import io.gatling.commons.validation._ import io.gatling.core.session.{Expression, Session} @@ -14,9 +14,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[T] { - def buildFromSession(session: Session): Validation[T] -} +trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[GraphStatementBuilderBase[_,T]] /** * Simple DSE Graph Statement from a String @@ -24,7 +22,7 @@ trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[T] { * @param statement the Gremlin String to execute */ case class GraphStringStatement(statement: Expression[String]) - extends DseGraphStatement[GraphStatementBuilderBase[_,ScriptGraphStatement]] { + extends DseGraphStatement[ScriptGraphStatement] { def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,ScriptGraphStatement]] = { statement(gatlingSession).flatMap(stmt => ScriptGraphStatement.builder(stmt).success) @@ -37,7 +35,7 @@ case class GraphStringStatement(statement: Expression[String]) * @param statement the Fluent Statement */ case class GraphFluentStatement(statement: FluentGraphStatement) - extends DseGraphStatement[GraphStatementBuilderBase[_,FluentGraphStatement]] { + extends DseGraphStatement[FluentGraphStatement] { def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { FluentGraphStatement.builder(statement).success @@ -52,7 +50,7 @@ case class GraphFluentStatement(statement: FluentGraphStatement) * and returns a fluent Graph Statement */ case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphStatement) - extends DseGraphStatement[GraphStatementBuilderBase[_,FluentGraphStatement]] { + extends DseGraphStatement[FluentGraphStatement] { def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { FluentGraphStatement.builder(lambda(gatlingSession)).success @@ -66,7 +64,7 @@ case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphSta * @param sessionKey Place a GraphTraversal in your session with this key name */ case class GraphFluentSessionKey(sessionKey: String) - extends DseGraphStatement[GraphStatementBuilderBase[_,FluentGraphStatement]] { + extends DseGraphStatement[FluentGraphStatement] { def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { @@ -90,7 +88,7 @@ case class GraphFluentSessionKey(sessionKey: String) * @param sessionKeys Gatling session param keys mapped to their bind name, to allow name override */ case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys: Map[String, String]) - extends DseGraphStatement[GraphStatementBuilderBase[_,ScriptGraphStatement]] { + extends DseGraphStatement[ScriptGraphStatement] { /** * Apply the Gatling session params passed to the GraphStatement From 06aab9520d9d6d9651aa43c24329766858cd74b7 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 6 Dec 2019 16:52:17 -0600 Subject: [PATCH 21/62] Converted CQL props to use only what's actually supported on the driver now. Still need to do the same for graph. Some things have moved into driver configuration, most notably the retry policy. Also simplified the DseResponse API. Primary accessor here is for the (Graph|Async)ResultSet... these vals can then be converted to Seqs using ResultSetUtils and managed via Scala's collection API. Preserved as many of the existing checks as possible mainly for backward compatibility; going forward many users would migrate to a Seq-based impl. The DseResponse API changes were (largely) a result of the distinction between ResultSet and AsyncResultSet in the 4.x driver. --- .../gatling/plugin/checks/CqlChecks.scala | 39 +----- .../plugin/checks/DseCheckSupport.scala | 11 -- .../gatling/plugin/checks/GenericChecks.scala | 20 +--- .../gatling/plugin/checks/GraphChecks.scala | 25 ++-- .../plugin/model/DseCqlAttributes.scala | 57 +++++---- .../model/DseCqlAttributesBuilder.scala | 112 +++++++++--------- .../plugin/request/CqlRequestAction.scala | 31 +++-- .../gatling/plugin/response/DseResponse.scala | 71 +---------- .../plugin/response/DseResponseHandler.scala | 6 +- .../gatling/plugin/utils/ResultSetUtils.scala | 41 +++++++ 10 files changed, 169 insertions(+), 244 deletions(-) create mode 100644 src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala index b2dd67f..875d5e5 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala @@ -6,11 +6,12 @@ package com.datastax.gatling.plugin.checks -import com.datastax.oss.driver.api.core.cql.{ResultSet, Row} +import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, Row} import com.datastax.gatling.plugin.response.CqlResponse +import com.datastax.gatling.plugin.utils.ResultSetUtils import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check._ -import io.gatling.core.check.extractor.{CountArity, CriterionExtractor, Extractor, FindAllArity, FindArity, SingleArity, _} +import io.gatling.core.check.extractor.{Extractor, SingleArity} import io.gatling.core.session.{Expression, ExpressionSuccessWrapper, Session} import scala.collection.mutable @@ -51,28 +52,9 @@ private class CqlResponseExtractor[X](val name: String, } } -private abstract class ColumnValueExtractor[X] extends CriterionExtractor[CqlResponse, Any, X] { - val criterionName = "columnValue" -} - -private class SingleColumnValueExtractor(val criterion: String, val occurrence: Int) extends ColumnValueExtractor[Any] with FindArity { - def extract(response: CqlResponse): Validation[Option[Any]] = - response.getColumnValSeq(criterion).lift(occurrence).success -} - -private class MultipleColumnValueExtractor(val criterion: String) extends ColumnValueExtractor[Seq[Any]] with FindAllArity { - def extract(response: CqlResponse): Validation[Option[Seq[Any]]] = - response.getColumnValSeq(criterion).liftSeqOption.success -} - -private class CountColumnValueExtractor(val criterion: String) extends ColumnValueExtractor[Int] with CountArity { - def extract(response: CqlResponse): Validation[Option[Int]] = - response.getColumnValSeq(criterion).liftSeqOption.map(_.size).success -} - object CqlChecks { val resultSet = - new CqlResponseExtractor[ResultSet]( + new CqlResponseExtractor[AsyncResultSet]( "resultSet", r => r.getCqlResultSet) .toCheckBuilder @@ -80,21 +62,12 @@ object CqlChecks { val allRows = new CqlResponseExtractor[Seq[Row]]( "allRows", - r => r.getAllRowsSeq) + r => ResultSetUtils.asyncResultSetToSeq(r.getCqlResultSet)) .toCheckBuilder val oneRow = new CqlResponseExtractor[Row]( "oneRow", - r => r.getOneRow) + r => ResultSetUtils.asyncResultSetToSeq(r.getCqlResultSet).head) .toCheckBuilder - - def columnValue(columnName: Expression[String]) = { - val cqlResponseExtender: Extender[DseCqlCheck, CqlResponse] = wrapped => DseCqlCheck(wrapped) - new DefaultMultipleFindCheckBuilder[DseCqlCheck, CqlResponse, CqlResponse, Any](cqlResponseExtender, x => x.success) { - def findExtractor(occurrence: Int) = columnName.map(new SingleColumnValueExtractor(_, occurrence)) - def findAllExtractor = columnName.map(new MultipleColumnValueExtractor(_)) - def countExtractor = columnName.map(new CountColumnValueExtractor(_)) - } - } } diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala index 453e70f..cad2d8d 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala @@ -10,11 +10,6 @@ import io.gatling.core.session.ExpressionSuccessWrapper trait DseCheckSupport { - // start global checks - lazy val exhausted = GenericChecks.exhausted - lazy val applied = GenericChecks.applied - lazy val rowCount = GenericChecks.rowCount - // execution info and subsets lazy val executionInfo = GenericChecks.executionInfo lazy val pagingState = GenericChecks.pagingState @@ -42,11 +37,5 @@ trait DseCheckSupport { def properties(columnName: String) = GraphChecks.paths(columnName) def vertexProperties(columnName: String) = GraphChecks.vertexProperties(columnName) - - /** - * Get a column by name returned by the CQL statement. - * Note that this statement implicitly fetches all rows from the result set! - */ - def columnValue(columnName: String) = CqlChecks.columnValue(columnName.expressionSuccess) } diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala index 690d902..e3e1c95 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala @@ -94,27 +94,9 @@ object GenericChecks { r => r.schemaInAgreement()) .toCheckBuilder - val rowCount = - new GenericResponseExtractor[Int]( - "rowCount", - r => r.rowCount()) - .toCheckBuilder - - val applied = - new GenericResponseExtractor[Boolean]( - "applied", - r => r.applied()) - .toCheckBuilder - - val exhausted = - new GenericResponseExtractor[Option[Boolean]]( - "exhausted", - r => r.exhausted()) - .toCheckBuilder - val coordinator = new GenericResponseExtractor[Node]( - "queriedHost", + "coordinator", r => r.coordinator()) .toCheckBuilder } diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala index 14d9cba..5614ee4 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala @@ -8,6 +8,7 @@ package com.datastax.gatling.plugin.checks import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.response.GraphResponse +import com.datastax.gatling.plugin.utils.ResultSetUtils import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} import io.gatling.core.check._ @@ -63,42 +64,42 @@ object GraphChecks { val allNodes = new GraphResponseExtractor[Seq[GraphNode]]( "allNodes", - r => r.getAllNodes) + r => ResultSetUtils.graphResultSetToSeq(r.getGraphResultSet)) .toCheckBuilder val oneNode = new GraphResponseExtractor[GraphNode]( "oneNode", - r => r.getOneNode) + r => ResultSetUtils.graphResultSetToSeq(r.getGraphResultSet).head) .toCheckBuilder - def edges(column: String) = + def edges(column: String):GraphCheckBuilder[Seq[Edge]] = new GraphResponseExtractor[Seq[Edge]]( "edges", - r => r.getEdges(column)) + r => ResultSetUtils.getEdges(r.getGraphResultSet,column)) .toCheckBuilder - def vertexes(column: String) = + def vertexes(column: String):GraphCheckBuilder[Seq[Vertex]] = new GraphResponseExtractor[Seq[Vertex]]( "vertices", - r => r.getVertexes(column)) + r => ResultSetUtils.getVertexes(r.getGraphResultSet, column)) .toCheckBuilder - def paths(column: String) = + def paths(column: String):GraphCheckBuilder[Seq[Path]] = new GraphResponseExtractor[Seq[Path]]( "paths", - r => r.getPaths(column)) + r => ResultSetUtils.getPaths(r.getGraphResultSet, column)) .toCheckBuilder - def properties(column: String) = + def properties(column: String):GraphCheckBuilder[Seq[Property[_]]] = new GraphResponseExtractor[Seq[Property[_]]]( "properties", - r => r.getProperties(column)) + r => ResultSetUtils.getProperties(r.getGraphResultSet, column)) .toCheckBuilder - def vertexProperties(column: String) = + def vertexProperties(column: String):GraphCheckBuilder[Seq[VertexProperty[_]]] = new GraphResponseExtractor[Seq[VertexProperty[_]]]( "vertexProperties", - r => r.getVertexProperties(column)) + r => ResultSetUtils.getVertexProperties(r.getGraphResultSet, column)) .toCheckBuilder } \ No newline at end of file diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index b7c3cd2..ebb4dd9 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -7,11 +7,13 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer +import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel -import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} -import com.datastax.oss.driver.api.core.retry.RetryPolicy +import com.datastax.oss.driver.api.core.cql.Statement import com.datastax.gatling.plugin.response.{CqlResponse, DseResponse} +import com.datastax.oss.driver.api.core.metadata.Node +import com.datastax.oss.driver.api.core.metadata.token.Token import io.gatling.core.check.Check /** @@ -24,32 +26,37 @@ import io.gatling.core.check.Check * @param cl Consistency Level to be used * @param cqlChecks Data-level checks to be run after response is returned * @param genericChecks Low-level checks to be run after response is returned - * @param userOrRole User or role to be used when proxy auth is enabled - * @param readTimeout Read timeout to be used * @param idempotent Set request to be idempotent i.e. whether it can be applied multiple times - * @param defaultTimestamp Set default timestamp on request, overriding current system time + * @param node Set the node that should handle this query + * @param customPayload Custom payload for this request * @param enableTrace Whether tracing should be enabled - * @param outGoingPayload Set ByteBuffer custom outgoing Payload - * @param serialCl Serial Consistency Level to be used - * @param fetchSize Set fetchSize of request i.e. paging size - * @param retryPolicy Retry Policy to be used + * @param pageSize Set pageSize (formerly known as fetchSize) * @param pagingState Set paging State wanted + * @param routingKey Sets the key for token-aware routing + * @param routingKeyspace Sets the keyspace for token-aware routing + * @param routingToken Sets the token to use for token-aware routing + * @param serialCl Serial Consistency Level to be used + * @param timeout How long to wait for this request to complete * @param cqlStatements String version of the CQL statement that is sent * */ -case class DseCqlAttributes[T <: Statement[T]](tag: String, - statement: DseCqlStatement[T], - cl: Option[ConsistencyLevel] = None, - cqlChecks: List[Check[CqlResponse]] = List.empty, - genericChecks: List[Check[DseResponse]] = List.empty, - userOrRole: Option[String] = None, - readTimeout: Option[Int] = None, - idempotent: Option[Boolean] = None, - defaultTimestamp: Option[Long] = None, - enableTrace: Option[Boolean] = None, - outGoingPayload: Option[Map[String, ByteBuffer]] = None, - serialCl: Option[ConsistencyLevel] = None, - fetchSize: Option[Int] = None, - retryPolicy: Option[RetryPolicy] = None, - pagingState: Option[ByteBuffer] = None, - cqlStatements: Seq[String] = Seq.empty) +case class DseCqlAttributes[T <: Statement[T]] + (tag: String, + statement: DseCqlStatement[T], + cqlChecks: List[Check[CqlResponse]] = List.empty, + genericChecks: List[Check[DseResponse]] = List.empty, + cqlStatements: Seq[String] = Seq.empty, + cl: Option[ConsistencyLevel] = None, + idempotent: Option[Boolean] = None, + node: Option[Node] = None, + customPayload: Option[Map[String, ByteBuffer]] = None, + enableTrace: Option[Boolean] = None, + pageSize: Option[Int] = None, + pagingState: Option[ByteBuffer] = None, + queryTimestamp: Option[Long] = None, + routingKey: Option[ByteBuffer] = None, + routingKeyspace: Option[String] = None, + routingToken: Option[Token] = None, + serialCl: Option[ConsistencyLevel] = None, + timeout: Option[Duration] = None) + diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index dedd274..db95ba9 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -7,12 +7,14 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer +import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Statement -import com.datastax.oss.driver.api.core.retry.RetryPolicy import com.datastax.gatling.plugin.checks.{DseCqlCheck, GenericCheck} import com.datastax.gatling.plugin.request.CqlRequestActionBuilder +import com.datastax.oss.driver.api.core.metadata.Node +import com.datastax.oss.driver.api.core.metadata.token.Token /** @@ -38,95 +40,100 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) DseCqlAttributesBuilder(attr.copy(cl = Some(level))) /** - * Execute a query as another user or another role, provided the current logged in user has PROXY.EXECUTE permission. - * - * This permission MUST be granted to the currently logged in user using the CQL statement: `GRANT PROXY.EXECUTE ON - * ROLE someRole TO alice`. The user MUST be logged in with - * [[com.datastax.dse.driver.api.core.auth.DsePlainTextAuthProviderBase]] or - * [[com.datastax.dse.driver.api.core.auth.DseGssApiAuthProviderBase]] + * Set query to be idempotent i.e. run only once * - * @param userOrRole String * @return */ - def withUserOrRole(userOrRole: String):DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) + def withIdempotency():DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(idempotent = Some(true))) /** - * Override the current system time for write time of query - * - * @param epochTsInMs timestamp to use + * Set the node that should handle this query + * @param node Node * @return */ - def withDefaultTimestamp(epochTsInMs: Long):DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(defaultTimestamp = Some(epochTsInMs))) - + def withNode(node: Node):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(node = Some(node))) /** - * Set query to be idempotent i.e. run only once + * Enable CQL Tracing on the query * * @return */ - def withIdempotency():DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(idempotent = Some(true))) - + def withTracingEnabled():DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(enableTrace = Some(true))) /** - * Set Read timeout of the query + * Set the page size * - * @param readTimeoutInMs time in milliseconds + * @param pageSize CQL page size * @return */ - def withReadTimeout(readTimeoutInMs: Int):DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(readTimeout = Some(readTimeoutInMs))) - + def withPageSize(pageSize: Int):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(pageSize = Some(pageSize))) /** - * Set Serial Consistency + * Set the paging state * - * @param level ConsistencyLevel + * @param pagingState CQL Paging state * @return */ - def withSerialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(serialCl = Some(level))) - + def withPagingState(pagingState: ByteBuffer):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(pagingState = Some(pagingState))) /** - * Define the [[com.datastax.oss.driver.api.core.retry.RetryPolicy]] to be used for query + * Set the query timestamp * - * @param retryPolicy DataStax drivers retry policy + * @param queryTimestamp CQL query timestamp * @return */ - def withRetryPolicy(retryPolicy: RetryPolicy):DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(retryPolicy = Some(retryPolicy))) + def withQueryTimestamp(queryTimestamp: Long):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(queryTimestamp = Some(queryTimestamp))) /** - * Set fetchSize of query for paging + * Set the routing key * - * @param rowCnt number of rows to fetch at one time + * @param routingKey the routing key to use * @return */ - def withFetchSize(rowCnt: Int):DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(fetchSize = Some(rowCnt))) - + def withRoutingKey(routingKey: ByteBuffer):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(routingKey = Some(routingKey))) /** - * Enable CQL Tracing on the query + * Set the routing keyspace * + * @param routingKeyspace the routing keyspace to set * @return */ - def withTracingEnabled():DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(enableTrace = Some(true))) + def withRoutingKeyspace(routingKeyspace: String):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(routingKeyspace = Some(routingKeyspace))) + /** + * Set the routing token + * + * @param routingToken the routing token to set + * @return + */ + def withRoutingToken(routingToken: Token):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(routingToken = Some(routingToken))) /** - * Set the paging state + * Set Serial Consistency * - * @param pagingState CQL Paging state + * @param level ConsistencyLevel * @return */ - def withPagingState(pagingState: ByteBuffer):DseCqlAttributesBuilder[T] = - DseCqlAttributesBuilder(attr.copy(pagingState = Some(pagingState))) + def withSerialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(serialCl = Some(level))) + /** + * Set timeout + * + * @param timeout the timeout to set + * @return + */ + def withTimeout(timeout: Duration):DseCqlAttributesBuilder[T] = + DseCqlAttributesBuilder(attr.copy(timeout = Some(timeout))) /** * For backwards compatibility @@ -138,7 +145,6 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) def serialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = withSerialConsistencyLevel(level) - /** * Backwards compatibility to set consistencyLevel * @@ -150,18 +156,6 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) def consistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = withConsistencyLevel(level) - - /** - * For Backwards compatibility - * - * @see [[DseCqlAttributesBuilder.executeAs]] - * @param userOrRole User or role to use - * @return - */ - @deprecated("Replaced by withUserOrRole") - def executeAs(userOrRole: String):DseCqlAttributesBuilder[T] = - withUserOrRole(userOrRole: String) - def check(check: DseCqlCheck):DseCqlAttributesBuilder[T] = DseCqlAttributesBuilder(attr.copy(cqlChecks = check :: attr.cqlChecks)) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index 0adaa94..c51ea93 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -24,7 +24,6 @@ import io.gatling.core.action.{Action, ExitableAction} import io.gatling.core.session.Session import io.gatling.core.stats.StatsEngine -import scala.collection.JavaConverters._ import scala.compat.java8.FutureConverters import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} @@ -66,21 +65,27 @@ class CqlRequestAction[T <: Statement[T]](val name: String, private def buildStatement(builder:StatementBuilder[_,T]):T = { // global options - dseAttributes.cl.map(builder.setConsistencyLevel) - dseAttributes.userOrRole.map(builder.executingAs) - dseAttributes.readTimeout.map(builder.setReadTimeoutMillis) - dseAttributes.idempotent.map(builder.setIdempotent) - dseAttributes.defaultTimestamp.map(builder.setDefaultTimestamp) + dseAttributes.cl.foreach(builder.setConsistencyLevel) + dseAttributes.idempotent.foreach((v) => builder.setIdempotence(v)) + dseAttributes.node.foreach(builder.setNode) // CQL Only Options - dseAttributes.outGoingPayload.map(x => builder.setOutgoingPayload(x.asJava)) - dseAttributes.serialCl.map(builder.setSerialConsistencyLevel) - dseAttributes.retryPolicy.map(builder.setRetryPolicy) - dseAttributes.fetchSize.map(builder.setFetchSize) - dseAttributes.pagingState.map(builder.setPagingState) - if (dseAttributes.enableTrace.isDefined && dseAttributes.enableTrace.get) { - builder.enableTracing + dseAttributes.customPayload.foreach { + _.foreach { + _ match { + case (k, v) => builder.addCustomPayload(k, v) + } + } } + dseAttributes.enableTrace.foreach(builder.setTracing) + dseAttributes.pageSize.foreach(builder.setPageSize) + dseAttributes.pagingState.foreach(builder.setPagingState) + dseAttributes.queryTimestamp.foreach(builder.setQueryTimestamp) + dseAttributes.routingKey.foreach(builder.setRoutingKey) + dseAttributes.routingKeyspace.foreach(builder.setRoutingKeyspace) + dseAttributes.routingToken.foreach(builder.setRoutingToken) + dseAttributes.serialCl.foreach(builder.setSerialConsistencyLevel) + dseAttributes.timeout.foreach(builder.setTimeout) builder.build } diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 7e3e21b..0e781d5 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -20,9 +20,6 @@ import scala.collection.JavaConverters._ abstract class DseResponse { def executionInfo(): ExecutionInfo - def rowCount(): Int - def applied(): Boolean - def exhausted(): Option[Boolean] def coordinator(): Node = executionInfo.getCoordinator def speculativeExecutions(): Int = executionInfo.getSpeculativeExecutionCount def pagingState(): ByteBuffer = executionInfo.getPagingState @@ -32,83 +29,19 @@ abstract class DseResponse { } class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttributes[_]) extends DseResponse with LazyLogging { - private lazy val allGraphNodes: Seq[GraphNode] = iterableAsScalaIterable(graphResultSet.all()).toSeq override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo.asInstanceOf[ExecutionInfo] - override def applied(): Boolean = false // graph doesn't support LWTs so always return false - override def exhausted(): Option[Boolean] = Option.empty - - /** - * Get the number of all rows returned by the query. - * Note: Calling this function fetches all rows from the result set! - */ - override def rowCount(): Int = allGraphNodes.size - def getGraphResultSet: GraphResultSet = graphResultSet - def getAllNodes: Seq[GraphNode] = allGraphNodes - - def getOneNode: GraphNode = graphResultSet.one() - - def getGraphResultColumnValues(column: String): Iterable[GraphNode] = - allGraphNodes.map(node => node.getByKey(column)) - .filter(_ != null) - - def buildFilterAndMapFn[T](filterFn: GraphNode => Boolean, mapFn: GraphNode => T): String => Seq[T] = - { arg => - iterableAsScalaIterable[GraphNode](graphResultSet).toSeq - .map(graphNode => graphNode.getByKey(arg)) - .filter(filterFn) - .map(mapFn) - } - - def getEdges: String => Seq[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) - - def getVertexes: String => Seq[Vertex] = buildFilterAndMapFn(_.isVertex, _.asVertex) - - def getPaths: String => Seq[Path] = buildFilterAndMapFn(_.isPath, _.asPath) - - def getProperties: String => Seq[Property[_]] = - buildFilterAndMapFn(_.isProperty, _.asProperty.asInstanceOf[Property[_]]) - - def getVertexProperties: String => Seq[VertexProperty[_]] = - buildFilterAndMapFn(_.isVertexProperty, _.asVertexProperty.asInstanceOf[VertexProperty[_]]) - def getDseAttributes: DseGraphAttributes[_] = dseAttributes } -class CqlResponse(cqlResultSet: ResultSet, dseAttributes: DseCqlAttributes[_]) extends DseResponse with LazyLogging { - private lazy val allCqlRows: Seq[Row] = iterableAsScalaIterable(cqlResultSet.all()).toSeq +class CqlResponse(cqlResultSet: AsyncResultSet, dseAttributes: DseCqlAttributes[_]) extends DseResponse with LazyLogging { override def executionInfo(): ExecutionInfo = cqlResultSet.getExecutionInfo - override def applied(): Boolean = cqlResultSet.wasApplied - override def exhausted(): Option[Boolean] = - Option(cqlResultSet.isFullyFetched && (cqlResultSet.getAvailableWithoutFetching == 0)) - - /** - * Get the number of all rows returned by the query. - * Note: Calling this function fetches all rows from the result set! - */ - def rowCount(): Int = allCqlRows.size - - /** - * Get CQL ResultSet - * - * @return - */ - def getCqlResultSet: ResultSet = cqlResultSet - - /** - * Get all the rows in a Seq[Row] format - * - * @return - */ - def getAllRowsSeq: Seq[Row] = allCqlRows - - def getOneRow: Row = cqlResultSet.one - def getColumnValSeq(column: String): Seq[Any] = allCqlRows.map(_.getObject(column)) + def getCqlResultSet: AsyncResultSet = cqlResultSet def getDseAttributes: DseCqlAttributes[_] = dseAttributes } diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 18d4f81..fbad929 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -163,11 +163,11 @@ class CqlResponseHandler[T <: Statement[_]](val next: Action, val stmt: T, val dseAttributes: DseCqlAttributes[T], val metricsLogger: MetricsLogger) - extends DseResponseHandler[T, ResultSet, CqlResponse] { + extends DseResponseHandler[T, AsyncResultSet, CqlResponse] { override protected def tag: String = dseAttributes.tag override protected def queries: Seq[String] = Seq.empty override protected def specificChecks: List[Check[CqlResponse]] = dseAttributes.cqlChecks override protected def genericChecks: List[Check[DseResponse]] = dseAttributes.genericChecks - override protected def newResponse(rs: ResultSet): CqlResponse = new CqlResponse(rs, dseAttributes) - override protected def coordinator(rs: ResultSet): Node = rs.getExecutionInfo.getCoordinator + override protected def newResponse(rs: AsyncResultSet): CqlResponse = new CqlResponse(rs, dseAttributes) + override protected def coordinator(rs: AsyncResultSet): Node = rs.getExecutionInfo.getCoordinator } diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala new file mode 100644 index 0000000..a94033c --- /dev/null +++ b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala @@ -0,0 +1,41 @@ +package com.datastax.gatling.plugin.utils + +import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphResultSet} +import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, ResultSet, Row} +import org.apache.tinkerpop.gremlin.process.traversal.Path +import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} + +import scala.collection.JavaConverters._ + +object ResultSetUtils { + + def resultSetToSeq(resultSet:ResultSet): Seq[Row] = { + iterableAsScalaIterable(resultSet).toSeq + } + + def asyncResultSetToSeq(resultSet:AsyncResultSet): Seq[Row] = { + } + + def graphResultSetToSeq(resultSet:GraphResultSet): Seq[GraphNode] = { + iterableAsScalaIterable(resultSet).toSeq + } + + private def buildFilterAndMapFn[T](filterFn: GraphNode => Boolean, mapFn: GraphNode => T)(resultSet: GraphResultSet, key:String):Seq[T] = { + graphResultSetToSeq(resultSet ) + .map(graphNode => graphNode.getByKey(key)) + .filter(filterFn) + .map(mapFn) + } + + def getEdges: (GraphResultSet, String) => Seq[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) + + def getVertexes: (GraphResultSet, String) => Seq[Vertex] = buildFilterAndMapFn(_.isVertex, _.asVertex) + + def getPaths: (GraphResultSet, String) => Seq[Path] = buildFilterAndMapFn(_.isPath, _.asPath) + + def getProperties: (GraphResultSet, String) => Seq[Property[_]] = + buildFilterAndMapFn(_.isProperty, _.asProperty.asInstanceOf[Property[_]]) + + def getVertexProperties: (GraphResultSet, String) => Seq[VertexProperty[_]] = + buildFilterAndMapFn(_.isVertexProperty, _.asVertexProperty.asInstanceOf[VertexProperty[_]]) +} From b56f341c7821cb7463e85c000c9c77effbc14094 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 9 Dec 2019 15:03:01 -0600 Subject: [PATCH 22/62] Converted graph props to include only what's supported on the driver now. --- .../plugin/model/DseCqlAttributes.scala | 3 +- .../plugin/model/DseGraphAttributes.scala | 37 ++++--- .../model/DseGraphAttributesBuilder.scala | 103 +++++------------- .../plugin/request/CqlRequestAction.scala | 2 +- .../plugin/request/GraphRequestAction.scala | 30 ++--- .../gatling/plugin/response/DseResponse.scala | 2 - .../plugin/response/DseResponseHandler.scala | 2 +- 7 files changed, 61 insertions(+), 118 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index ebb4dd9..bc5d52e 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -46,9 +46,11 @@ case class DseCqlAttributes[T <: Statement[T]] cqlChecks: List[Check[CqlResponse]] = List.empty, genericChecks: List[Check[DseResponse]] = List.empty, cqlStatements: Seq[String] = Seq.empty, + /* General attributes */ cl: Option[ConsistencyLevel] = None, idempotent: Option[Boolean] = None, node: Option[Node] = None, + /* CQL-specific attributes */ customPayload: Option[Map[String, ByteBuffer]] = None, enableTrace: Option[Boolean] = None, pageSize: Option[Int] = None, @@ -59,4 +61,3 @@ case class DseCqlAttributes[T <: Statement[T]] routingToken: Option[Token] = None, serialCl: Option[ConsistencyLevel] = None, timeout: Option[Duration] = None) - diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index 4b216df..25545fb 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -6,10 +6,13 @@ package com.datastax.gatling.plugin.model +import java.time.Duration + import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Row import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} +import com.datastax.oss.driver.api.core.metadata.Node /** * Graph Query Attributes to be applied to the current query @@ -34,20 +37,20 @@ import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} * @param graphInternalOptions Query-specific options not available in the driver public API * @param graphTransformResults Function to use in order to transform a row into a Graph node */ -case class DseGraphAttributes[T <: GraphStatement[T]](tag: String, - statement: DseGraphStatement[T], - cl: Option[ConsistencyLevel] = None, - graphChecks: List[DseGraphCheck] = List.empty, - genericChecks: List[GenericCheck] = List.empty, - userOrRole: Option[String] = None, - readTimeout: Option[Int] = None, - idempotent: Option[Boolean] = None, - defaultTimestamp: Option[Long] = None, - readCL: Option[ConsistencyLevel] = None, - writeCL: Option[ConsistencyLevel] = None, - graphName: Option[String] = None, - graphLanguage: Option[String] = None, - graphSource: Option[String] = None, - isSystemQuery: Option[Boolean] = None, - graphInternalOptions: Option[Seq[(String, String)]] = None, - graphTransformResults: Option[com.datastax.oss.driver.shaded.guava.common.base.Function[Row, GraphNode]] = None) +case class DseGraphAttributes[T <: GraphStatement[T]] + (tag: String, + statement: DseGraphStatement[T], + graphChecks: List[DseGraphCheck] = List.empty, + genericChecks: List[GenericCheck] = List.empty, + /* General attributes */ + cl: Option[ConsistencyLevel] = None, + idempotent: Option[Boolean] = None, + node: Option[Node] = None, + /* Graph-specific attributes */ + graphName: Option[String] = None, + readCL: Option[ConsistencyLevel] = None, + subProtocol: Option[String] = None, + timeout: Option[Duration] = None, + timestamp: Option[Long] = None, + traversalSource: Option[String] = None, + writeCL: Option[ConsistencyLevel] = None) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index 5fac5f5..b84ab4c 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -6,12 +6,14 @@ package com.datastax.gatling.plugin.model +import java.time.Duration + import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Row import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} import com.datastax.gatling.plugin.request.GraphRequestActionBuilder - +import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.shaded.guava.common.base.Function /** @@ -36,29 +38,6 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri def withConsistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T] = DseGraphAttributesBuilder(attr.copy(cl = Some(level))) - /** - * Execute a query as another user or another role, provided the current logged in user has PROXY.EXECUTE permission. - * - * This permission MUST be granted to the currently logged in user using the CQL statement: `GRANT PROXY.EXECUTE ON - * ROLE someRole TO alice`. The user MUST be logged in with - * [[com.datastax.dse.driver.api.core.auth.DsePlainTextAuthProviderBase]] or - * [[com.datastax.dse.driver.api.core.auth.DseGssApiAuthProviderBase]] - * - * @param userOrRole String - * @return - */ - def withUserOrRole(userOrRole: String):DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) - - /** - * Override the current system time for write time of query - * - * @param epochTsInMs timestamp to use - * @return - */ - def withDefaultTimestamp(epochTsInMs: Long):DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(defaultTimestamp = Some(epochTsInMs))) - /** * Set query to be idempotent i.e. run only once * @@ -67,24 +46,6 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri def withIdempotency():DseGraphAttributesBuilder[T] = DseGraphAttributesBuilder(attr.copy(idempotent = Some(true))) - /** - * Set Read timeout of the query - * - * @param readTimeoutInMs time in milliseconds - * @return - */ - def withReadTimeout(readTimeoutInMs: Int):DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(readTimeout = Some(readTimeoutInMs))) - - /** - * Sets the graph language - * - * @param language graph language to use - * @return - */ - def withLanguage(language: String):DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(graphLanguage = Some(language))) - /** * Sets the graph name to use * @@ -95,57 +56,57 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri DseGraphAttributesBuilder(attr.copy(graphName = Some(name))) /** - * Set the source of the graph - * - * @param source graph source + * Set the node that should handle this query + * @param node Node * @return */ - def withSource(source: String):DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(graphSource = Some(source))) + def withNode(node: Node):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(node = Some(node))) /** - * Set the query to be system level + * Define [[ConsistencyLevel]] to be used for read queries * + * @param readCL Consistency Level to use * @return */ - def withSystemQuery():DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(isSystemQuery = Some(true))) + def withReadConsistency(readCL: ConsistencyLevel):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(readCL = Some(readCL))) /** - * Set Options on graph + * Set the sub-protocol * - * @param options options in key/value par to set against the query + * @param subProtocol the sub-protocol to use * @return */ - def withOptions(options: (String, String)*):DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(graphInternalOptions = Some(options))) + def withSubProtocol(subProtocol: String):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(subProtocol = Some(subProtocol))) /** - * Set Option on graph + * Set the timeout * - * @param option options in key/value par to set against the query + * @param timeout the timeout to use * @return */ - def withOption(option: (String, String)):DseGraphAttributesBuilder[T] = withOptions(option) + def withTimeout(timeout: Duration):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(timeout = Some(timeout))) /** - * Transform results function + * Set the timestamp * - * @param transform Transform Function + * @param timestamp the timestamp to use * @return */ - def withTransformResults(transform: Function[Row, GraphNode]):DseGraphAttributesBuilder[T] = { - DseGraphAttributesBuilder(attr.copy(graphTransformResults = Some(transform))) - } + def withTimestamp(timestamp: Long):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(timestamp = Some(timestamp))) /** - * Define [[ConsistencyLevel]] to be used for read queries + * Set the sub-protocol * - * @param readCL Consistency Level to use + * @param traversalSource the traversal source to use * @return */ - def withReadConsistency(readCL: ConsistencyLevel):DseGraphAttributesBuilder[T] = - DseGraphAttributesBuilder(attr.copy(readCL = Some(readCL))) + def withTraversalSource(traversalSource: String):DseGraphAttributesBuilder[T] = + DseGraphAttributesBuilder(attr.copy(traversalSource = Some(traversalSource))) /** * Define [[ConsistencyLevel]] to be used for write queries @@ -166,16 +127,6 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri @deprecated("use withConsistencyLevel() instead, will be removed in future version") def consistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T] = withConsistencyLevel(level) - /** - * For Backwards compatibility - * - * @see [[DseGraphAttributesBuilder.executeAs]] - * @param userOrRole User or role to use - * @return - */ - @deprecated("use withUserOrRole() instead, will be removed in future version") - def executeAs(userOrRole: String):DseGraphAttributesBuilder[T] = withUserOrRole(userOrRole: String) - def check(check: DseGraphCheck):DseGraphAttributesBuilder[T] = DseGraphAttributesBuilder(attr.copy(graphChecks = check :: attr.graphChecks)) def check(check: GenericCheck):DseGraphAttributesBuilder[T] = diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index c51ea93..8601da6 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -66,7 +66,7 @@ class CqlRequestAction[T <: Statement[T]](val name: String, // global options dseAttributes.cl.foreach(builder.setConsistencyLevel) - dseAttributes.idempotent.foreach((v) => builder.setIdempotence(v)) + dseAttributes.idempotent.foreach(builder.setIdempotence(_)) dseAttributes.node.foreach(builder.setNode) // CQL Only Options diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index 0abb988..6d69667 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -65,28 +65,18 @@ class GraphRequestAction[T <: GraphStatement[T]](val name: String, // global options dseAttributes.cl.map(builder.setConsistencyLevel) - dseAttributes.defaultTimestamp.map(builder.setDefaultTimestamp) - dseAttributes.userOrRole.map(builder.executingAs) - dseAttributes.readTimeout.map(builder.setReadTimeoutMillis) - dseAttributes.idempotent.map(builder.setIdempotent) + dseAttributes.idempotent.foreach(builder.setIdempotence(_)) + dseAttributes.node.foreach(builder.setNode) // Graph only Options - dseAttributes.readCL.map(builder.setReadConsistencyLevel) - dseAttributes.writeCL.map(builder.setWriteConsistencyLevel) - dseAttributes.graphLanguage.map(builder.setGraphLanguage) - dseAttributes.graphName.map(builder.setGraphName) - dseAttributes.graphSource.map(builder.setGraphSource) - dseAttributes.graphTransformResults.map(builder.setTransformResultFunction) - - if (dseAttributes.graphInternalOptions.isDefined) { - dseAttributes.graphInternalOptions.get.foreach { t => - builder.setGraphInternalOption(t._1, t._2) - } - } + dseAttributes.graphName.foreach(builder.setGraphName) + dseAttributes.readCL.foreach(builder.setReadConsistencyLevel) + dseAttributes.subProtocol.foreach(builder.setSubProtocol) + dseAttributes.timeout.foreach(builder.setTimeout) + dseAttributes.timestamp.foreach(builder.setTimestamp) + dseAttributes.traversalSource.foreach(builder.setTraversalSource) + dseAttributes.writeCL.foreach(builder.setWriteConsistencyLevel) - if (dseAttributes.isSystemQuery.isDefined && dseAttributes.isSystemQuery.get) { - builder.setSystemQuery() - } builder.build } @@ -94,7 +84,7 @@ class GraphRequestAction[T <: GraphStatement[T]](val name: String, val stmt:T = buildStatement(builder) val responseHandler = - new GraphResponseHandler( + new GraphResponseHandler[T]( next, session, system, diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 0e781d5..7d60ee7 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -13,8 +13,6 @@ import com.datastax.oss.driver.api.core.cql._ import com.datastax.dse.driver.api.core.graph._ import com.datastax.oss.driver.api.core.metadata.Node import com.typesafe.scalalogging.LazyLogging -import org.apache.tinkerpop.gremlin.process.traversal.Path -import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} import scala.collection.JavaConverters._ diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index fbad929..3c54010 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -146,7 +146,7 @@ class GraphResponseHandler[T <: GraphStatement[_]](val next: Action, val stmt: T, val dseAttributes: DseGraphAttributes[T], val metricsLogger: MetricsLogger) - extends DseResponseHandler[T, GraphResultSet, GraphResponse] { + extends DseResponseHandler[T, GraphResultSet, GraphResponse] { override protected def tag: String = dseAttributes.tag override protected def queries: Seq[String] = Seq.empty override protected def specificChecks: List[Check[GraphResponse]] = dseAttributes.graphChecks From fca261f355b36f8890ce6a4d1b039df49529ce50 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 9 Dec 2019 15:48:59 -0600 Subject: [PATCH 23/62] Converting from GraphResultSet to AsyncGraphResultSet --- .../gatling/plugin/checks/GraphChecks.scala | 18 ++++++------- .../plugin/request/GraphRequestAction.scala | 2 +- .../gatling/plugin/response/DseResponse.scala | 4 +-- .../plugin/response/DseResponseHandler.scala | 8 +++--- .../gatling/plugin/utils/ResultSetUtils.scala | 25 +++++++++++-------- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala index 5614ee4..3eddc3e 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala @@ -8,7 +8,7 @@ package com.datastax.gatling.plugin.checks import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.response.GraphResponse -import com.datastax.gatling.plugin.utils.ResultSetUtils +import com.datastax.gatling.plugin.utils.{GraphResultSetUtils, ResultSetUtils} import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} import io.gatling.core.check._ @@ -56,7 +56,7 @@ private class GraphResponseExtractor[X](val name: String, object GraphChecks { val graphResultSet = - new GraphResponseExtractor[GraphResultSet]( + new GraphResponseExtractor[AsyncGraphResultSet]( "graphResultSet", r => r.getGraphResultSet) .toCheckBuilder @@ -64,42 +64,42 @@ object GraphChecks { val allNodes = new GraphResponseExtractor[Seq[GraphNode]]( "allNodes", - r => ResultSetUtils.graphResultSetToSeq(r.getGraphResultSet)) + r => ResultSetUtils.asyncGraphResultSetToSeq(r.getGraphResultSet)) .toCheckBuilder val oneNode = new GraphResponseExtractor[GraphNode]( "oneNode", - r => ResultSetUtils.graphResultSetToSeq(r.getGraphResultSet).head) + r => ResultSetUtils.asyncGraphResultSetToSeq(r.getGraphResultSet).head) .toCheckBuilder def edges(column: String):GraphCheckBuilder[Seq[Edge]] = new GraphResponseExtractor[Seq[Edge]]( "edges", - r => ResultSetUtils.getEdges(r.getGraphResultSet,column)) + r => GraphResultSetUtils.edges(r.getGraphResultSet,column)) .toCheckBuilder def vertexes(column: String):GraphCheckBuilder[Seq[Vertex]] = new GraphResponseExtractor[Seq[Vertex]]( "vertices", - r => ResultSetUtils.getVertexes(r.getGraphResultSet, column)) + r => GraphResultSetUtils.vertexes(r.getGraphResultSet, column)) .toCheckBuilder def paths(column: String):GraphCheckBuilder[Seq[Path]] = new GraphResponseExtractor[Seq[Path]]( "paths", - r => ResultSetUtils.getPaths(r.getGraphResultSet, column)) + r => GraphResultSetUtils.paths(r.getGraphResultSet, column)) .toCheckBuilder def properties(column: String):GraphCheckBuilder[Seq[Property[_]]] = new GraphResponseExtractor[Seq[Property[_]]]( "properties", - r => ResultSetUtils.getProperties(r.getGraphResultSet, column)) + r => GraphResultSetUtils.properties(r.getGraphResultSet, column)) .toCheckBuilder def vertexProperties(column: String):GraphCheckBuilder[Seq[VertexProperty[_]]] = new GraphResponseExtractor[Seq[VertexProperty[_]]]( "vertexProperties", - r => ResultSetUtils.getVertexProperties(r.getGraphResultSet, column)) + r => GraphResultSetUtils.vertexProperties(r.getGraphResultSet, column)) .toCheckBuilder } \ No newline at end of file diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index 6d69667..c5efc05 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -64,7 +64,7 @@ class GraphRequestAction[T <: GraphStatement[T]](val name: String, private def buildStatement(builder:GraphStatementBuilderBase[_,T]):T = { // global options - dseAttributes.cl.map(builder.setConsistencyLevel) + dseAttributes.cl.foreach(builder.setConsistencyLevel) dseAttributes.idempotent.foreach(builder.setIdempotence(_)) dseAttributes.node.foreach(builder.setNode) diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 7d60ee7..81818e0 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -26,11 +26,11 @@ abstract class DseResponse { def schemaInAgreement(): Boolean = executionInfo.isSchemaInAgreement } -class GraphResponse(graphResultSet: GraphResultSet, dseAttributes: DseGraphAttributes[_]) extends DseResponse with LazyLogging { +class GraphResponse(graphResultSet: AsyncGraphResultSet, dseAttributes: DseGraphAttributes[_]) extends DseResponse with LazyLogging { override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo.asInstanceOf[ExecutionInfo] - def getGraphResultSet: GraphResultSet = graphResultSet + def getGraphResultSet: AsyncGraphResultSet = graphResultSet def getDseAttributes: DseGraphAttributes[_] = dseAttributes } diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 3c54010..6cb034d 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem import com.datastax.oss.driver.api.core.cql._ -import com.datastax.dse.driver.api.core.graph.{GraphResultSet, GraphStatement} +import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphResultSet, GraphStatement} import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.datastax.gatling.plugin.utils.{ResponseTime, ResponseTimeBuilder} @@ -146,13 +146,13 @@ class GraphResponseHandler[T <: GraphStatement[_]](val next: Action, val stmt: T, val dseAttributes: DseGraphAttributes[T], val metricsLogger: MetricsLogger) - extends DseResponseHandler[T, GraphResultSet, GraphResponse] { + extends DseResponseHandler[T, AsyncGraphResultSet, GraphResponse] { override protected def tag: String = dseAttributes.tag override protected def queries: Seq[String] = Seq.empty override protected def specificChecks: List[Check[GraphResponse]] = dseAttributes.graphChecks override protected def genericChecks: List[Check[DseResponse]] = dseAttributes.genericChecks - override protected def newResponse(rs: GraphResultSet): GraphResponse = new GraphResponse(rs, dseAttributes) - override protected def coordinator(rs: GraphResultSet): Node = rs.getExecutionInfo.getCoordinator + override protected def newResponse(rs: AsyncGraphResultSet): GraphResponse = new GraphResponse(rs, dseAttributes) + override protected def coordinator(rs: AsyncGraphResultSet): Node = rs.getExecutionInfo.getCoordinator } class CqlResponseHandler[T <: Statement[_]](val next: Action, diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala index a94033c..9c69445 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala @@ -1,6 +1,6 @@ package com.datastax.gatling.plugin.utils -import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphResultSet} +import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphNode} import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, ResultSet, Row} import org.apache.tinkerpop.gremlin.process.traversal.Path import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} @@ -16,26 +16,29 @@ object ResultSetUtils { def asyncResultSetToSeq(resultSet:AsyncResultSet): Seq[Row] = { } - def graphResultSetToSeq(resultSet:GraphResultSet): Seq[GraphNode] = { - iterableAsScalaIterable(resultSet).toSeq + def asyncGraphResultSetToSeq(resultSet:AsyncGraphResultSet): Seq[GraphNode] = { } - private def buildFilterAndMapFn[T](filterFn: GraphNode => Boolean, mapFn: GraphNode => T)(resultSet: GraphResultSet, key:String):Seq[T] = { - graphResultSetToSeq(resultSet ) +} + +object GraphResultSetUtils { + + private def buildFilterAndMapFn[T](filterFn: GraphNode => Boolean, mapFn: GraphNode => T)(resultSet: AsyncGraphResultSet, key:String):Seq[T] = { + ResultSetUtils.asyncGraphResultSetToSeq(resultSet ) .map(graphNode => graphNode.getByKey(key)) .filter(filterFn) .map(mapFn) } - def getEdges: (GraphResultSet, String) => Seq[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) + def edges: (AsyncGraphResultSet, String) => Seq[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) - def getVertexes: (GraphResultSet, String) => Seq[Vertex] = buildFilterAndMapFn(_.isVertex, _.asVertex) + def vertexes: (AsyncGraphResultSet, String) => Seq[Vertex] = buildFilterAndMapFn(_.isVertex, _.asVertex) - def getPaths: (GraphResultSet, String) => Seq[Path] = buildFilterAndMapFn(_.isPath, _.asPath) + def paths: (AsyncGraphResultSet, String) => Seq[Path] = buildFilterAndMapFn(_.isPath, _.asPath) - def getProperties: (GraphResultSet, String) => Seq[Property[_]] = + def properties: (AsyncGraphResultSet, String) => Seq[Property[_]] = buildFilterAndMapFn(_.isProperty, _.asProperty.asInstanceOf[Property[_]]) - def getVertexProperties: (GraphResultSet, String) => Seq[VertexProperty[_]] = + def vertexProperties: (AsyncGraphResultSet, String) => Seq[VertexProperty[_]] = buildFilterAndMapFn(_.isVertexProperty, _.asVertexProperty.asInstanceOf[VertexProperty[_]]) -} +} \ No newline at end of file From 62d8326431a279a3cbe16635bb9d02b5daf77c22 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 10 Dec 2019 13:52:05 -0600 Subject: [PATCH 24/62] Simple impls of Iterators for async RS impls --- .../gatling/plugin/checks/CqlChecks.scala | 6 +- .../gatling/plugin/checks/GraphChecks.scala | 26 +++---- .../plugin/request/DseRequestActor.scala | 2 - .../gatling/plugin/utils/ResultSetUtils.scala | 69 ++++++++++++++----- 4 files changed, 67 insertions(+), 36 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala index 875d5e5..c1fde95 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala @@ -60,14 +60,14 @@ object CqlChecks { .toCheckBuilder val allRows = - new CqlResponseExtractor[Seq[Row]]( + new CqlResponseExtractor[Iterator[Row]]( "allRows", - r => ResultSetUtils.asyncResultSetToSeq(r.getCqlResultSet)) + r => ResultSetUtils.asyncResultSetToIterator(r.getCqlResultSet)) .toCheckBuilder val oneRow = new CqlResponseExtractor[Row]( "oneRow", - r => ResultSetUtils.asyncResultSetToSeq(r.getCqlResultSet).head) + r => ResultSetUtils.asyncResultSetToIterator(r.getCqlResultSet).next) .toCheckBuilder } diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala index 3eddc3e..0a082f4 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala @@ -62,43 +62,43 @@ object GraphChecks { .toCheckBuilder val allNodes = - new GraphResponseExtractor[Seq[GraphNode]]( + new GraphResponseExtractor[Iterator[GraphNode]]( "allNodes", - r => ResultSetUtils.asyncGraphResultSetToSeq(r.getGraphResultSet)) + r => ResultSetUtils.asyncGraphResultSetToIterator(r.getGraphResultSet)) .toCheckBuilder val oneNode = new GraphResponseExtractor[GraphNode]( "oneNode", - r => ResultSetUtils.asyncGraphResultSetToSeq(r.getGraphResultSet).head) + r => ResultSetUtils.asyncGraphResultSetToIterator(r.getGraphResultSet).next) .toCheckBuilder - def edges(column: String):GraphCheckBuilder[Seq[Edge]] = - new GraphResponseExtractor[Seq[Edge]]( + def edges(column: String):GraphCheckBuilder[Iterator[Edge]] = + new GraphResponseExtractor[Iterator[Edge]]( "edges", r => GraphResultSetUtils.edges(r.getGraphResultSet,column)) .toCheckBuilder - def vertexes(column: String):GraphCheckBuilder[Seq[Vertex]] = - new GraphResponseExtractor[Seq[Vertex]]( + def vertexes(column: String):GraphCheckBuilder[Iterator[Vertex]] = + new GraphResponseExtractor[Iterator[Vertex]]( "vertices", r => GraphResultSetUtils.vertexes(r.getGraphResultSet, column)) .toCheckBuilder - def paths(column: String):GraphCheckBuilder[Seq[Path]] = - new GraphResponseExtractor[Seq[Path]]( + def paths(column: String):GraphCheckBuilder[Iterator[Path]] = + new GraphResponseExtractor[Iterator[Path]]( "paths", r => GraphResultSetUtils.paths(r.getGraphResultSet, column)) .toCheckBuilder - def properties(column: String):GraphCheckBuilder[Seq[Property[_]]] = - new GraphResponseExtractor[Seq[Property[_]]]( + def properties(column: String):GraphCheckBuilder[Iterator[Property[_]]] = + new GraphResponseExtractor[Iterator[Property[_]]]( "properties", r => GraphResultSetUtils.properties(r.getGraphResultSet, column)) .toCheckBuilder - def vertexProperties(column: String):GraphCheckBuilder[Seq[VertexProperty[_]]] = - new GraphResponseExtractor[Seq[VertexProperty[_]]]( + def vertexProperties(column: String):GraphCheckBuilder[Iterator[VertexProperty[_]]] = + new GraphResponseExtractor[Iterator[VertexProperty[_]]]( "vertexProperties", r => GraphResultSetUtils.vertexProperties(r.getGraphResultSet, column)) .toCheckBuilder diff --git a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala index 06368c4..abe4af8 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala @@ -8,8 +8,6 @@ package com.datastax.gatling.plugin.request import akka.actor.Actor -import com.datastax.oss.driver.api.core.cql.ResultSet -import com.datastax.dse.driver.api.core.graph.GraphResultSet import com.datastax.gatling.plugin.response.DseResponseCallback import com.typesafe.scalalogging.StrictLogging import io.gatling.core.session.Session diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala index 9c69445..357dd7f 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala @@ -1,44 +1,77 @@ package com.datastax.gatling.plugin.utils +import java.util.concurrent.CompletionStage + import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphNode} -import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, ResultSet, Row} +import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, Row} import org.apache.tinkerpop.gremlin.process.traversal.Path import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} -import scala.collection.JavaConverters._ +import collection.JavaConverters._ object ResultSetUtils { - def resultSetToSeq(resultSet:ResultSet): Seq[Row] = { - iterableAsScalaIterable(resultSet).toSeq - } - - def asyncResultSetToSeq(resultSet:AsyncResultSet): Seq[Row] = { - } - - def asyncGraphResultSetToSeq(resultSet:AsyncGraphResultSet): Seq[GraphNode] = { - } + def asyncResultSetToIterator(resultSet:AsyncResultSet): Iterator[Row] = + new AsyncResultSetIterator( + new CqlAsyncRS(resultSet)) + def asyncGraphResultSetToIterator(resultSet:AsyncGraphResultSet): Iterator[GraphNode] = + new AsyncResultSetIterator( + new GraphAsyncRS(resultSet)) } object GraphResultSetUtils { - private def buildFilterAndMapFn[T](filterFn: GraphNode => Boolean, mapFn: GraphNode => T)(resultSet: AsyncGraphResultSet, key:String):Seq[T] = { - ResultSetUtils.asyncGraphResultSetToSeq(resultSet ) + private def buildFilterAndMapFn[T] + (filterFn: GraphNode => Boolean, mapFn: GraphNode => T) + (resultSet: AsyncGraphResultSet, key:String):Iterator[T] = { + ResultSetUtils.asyncGraphResultSetToIterator(resultSet ) .map(graphNode => graphNode.getByKey(key)) .filter(filterFn) .map(mapFn) } - def edges: (AsyncGraphResultSet, String) => Seq[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) + def edges: (AsyncGraphResultSet, String) => Iterator[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) - def vertexes: (AsyncGraphResultSet, String) => Seq[Vertex] = buildFilterAndMapFn(_.isVertex, _.asVertex) + def vertexes: (AsyncGraphResultSet, String) => Iterator[Vertex] = buildFilterAndMapFn(_.isVertex, _.asVertex) - def paths: (AsyncGraphResultSet, String) => Seq[Path] = buildFilterAndMapFn(_.isPath, _.asPath) + def paths: (AsyncGraphResultSet, String) => Iterator[Path] = buildFilterAndMapFn(_.isPath, _.asPath) - def properties: (AsyncGraphResultSet, String) => Seq[Property[_]] = + def properties: (AsyncGraphResultSet, String) => Iterator[Property[_]] = buildFilterAndMapFn(_.isProperty, _.asProperty.asInstanceOf[Property[_]]) - def vertexProperties: (AsyncGraphResultSet, String) => Seq[VertexProperty[_]] = + def vertexProperties: (AsyncGraphResultSet, String) => Iterator[VertexProperty[_]] = buildFilterAndMapFn(_.isVertexProperty, _.asVertexProperty.asInstanceOf[VertexProperty[_]]) +} + +trait AsyncRS[T] { + def hasMorePages:Boolean + def currentPage:Iterable[T] + def fetchNextPage:CompletionStage[AsyncRS[T]] +} + +class CqlAsyncRS(rs:AsyncResultSet) extends AsyncRS[Row] { + override def hasMorePages: Boolean = rs.hasMorePages + override def currentPage: Iterable[Row] = rs.currentPage.asScala + override def fetchNextPage: CompletionStage[AsyncRS[Row]] = rs.fetchNextPage.thenApplyAsync(new CqlAsyncRS(_)) +} + +class GraphAsyncRS(rs:AsyncGraphResultSet) extends AsyncRS[GraphNode] { + override def hasMorePages: Boolean = rs.hasMorePages + override def currentPage: Iterable[GraphNode] = rs.currentPage.asScala + override def fetchNextPage: CompletionStage[AsyncRS[GraphNode]] = rs.fetchNextPage.thenApplyAsync(new GraphAsyncRS(_)) +} + +/* Note that this iterator isn't thread-safe */ +class AsyncResultSetIterator[T](rs:AsyncRS[T]) extends Iterator[T] { + var working = rs + var iter = rs.currentPage.iterator + override def hasNext: Boolean = iter.hasNext || working.hasMorePages + override def next: T = { + if (!iter.hasNext && working.hasMorePages) { + working = working.fetchNextPage.toCompletableFuture.get + iter = working.currentPage.iterator + } + iter.next + } } \ No newline at end of file From 3183a44247eb5a9ff7f7609fccea5c9d8d0fc370 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 10 Dec 2019 16:01:38 -0600 Subject: [PATCH 25/62] Fixing up some type things --- .../com/datastax/gatling/plugin/Predef.scala | 4 +- .../plugin/model/DseCqlAttributes.scala | 6 +- .../model/DseCqlAttributesBuilder.scala | 38 ++++----- .../model/DseCqlStatementBuilders.scala | 32 +++++--- .../plugin/model/DseCqlStatements.scala | 78 ++++++++++--------- .../plugin/model/DseGraphAttributes.scala | 26 +++---- .../model/DseGraphAttributesBuilder.scala | 32 ++++---- .../model/DseGraphStatementBuilders.scala | 41 +++++----- .../plugin/model/DseGraphStatements.scala | 43 +++++----- .../plugin/request/CqlRequestAction.scala | 10 +-- .../request/CqlRequestActionBuilder.scala | 9 ++- .../plugin/request/DseRequestActor.scala | 6 +- .../plugin/request/GraphRequestAction.scala | 10 +-- .../request/GraphRequestActionBuilder.scala | 8 +- .../gatling/plugin/response/DseResponse.scala | 8 +- .../plugin/response/DseResponseHandler.scala | 10 +-- 16 files changed, 194 insertions(+), 167 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/Predef.scala b/src/main/scala/com/datastax/gatling/plugin/Predef.scala index 28cd12c..eb1eeea 100644 --- a/src/main/scala/com/datastax/gatling/plugin/Predef.scala +++ b/src/main/scala/com/datastax/gatling/plugin/Predef.scala @@ -36,9 +36,9 @@ trait DsePredefBase extends DseCheckSupport { implicit def protocolBuilder2DseProtocol(builder: DseProtocolBuilder): DseProtocol = builder.build - implicit def cqlRequestAttributes2ActionBuilder(builder: DseCqlAttributesBuilder[_]): ActionBuilder = builder.build() + implicit def cqlRequestAttributes2ActionBuilder(builder: DseCqlAttributesBuilder[_,_]): ActionBuilder = builder.build() - implicit def graphRequestAttributes2ActionBuilder(builder: DseGraphAttributesBuilder[_]): ActionBuilder = builder.build() + implicit def graphRequestAttributes2ActionBuilder(builder: DseGraphAttributesBuilder[_, _]): ActionBuilder = builder.build() } /** diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index bc5d52e..1176c8b 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -10,7 +10,7 @@ import java.nio.ByteBuffer import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel -import com.datastax.oss.driver.api.core.cql.Statement +import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} import com.datastax.gatling.plugin.response.{CqlResponse, DseResponse} import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.api.core.metadata.token.Token @@ -40,9 +40,9 @@ import io.gatling.core.check.Check * @param cqlStatements String version of the CQL statement that is sent * */ -case class DseCqlAttributes[T <: Statement[T]] +case class DseCqlAttributes[T <: Statement[T], B <: StatementBuilder[B,T]] (tag: String, - statement: DseCqlStatement[T], + statement: DseCqlStatement[T, B], cqlChecks: List[Check[CqlResponse]] = List.empty, genericChecks: List[Check[DseResponse]] = List.empty, cqlStatements: Seq[String] = Seq.empty, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index db95ba9..1e7a909 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -10,7 +10,7 @@ import java.nio.ByteBuffer import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel -import com.datastax.oss.driver.api.core.cql.Statement +import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} import com.datastax.gatling.plugin.checks.{DseCqlCheck, GenericCheck} import com.datastax.gatling.plugin.request.CqlRequestActionBuilder import com.datastax.oss.driver.api.core.metadata.Node @@ -22,13 +22,13 @@ import com.datastax.oss.driver.api.core.metadata.token.Token * * @param attr Addition Attributes */ -case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) { +case class DseCqlAttributesBuilder[T <: Statement[T], B <: StatementBuilder[B,T]](attr: DseCqlAttributes[T, B]) { /** * Builds to final action to run * * @return */ - def build(): CqlRequestActionBuilder[T] = new CqlRequestActionBuilder(attr) + def build(): CqlRequestActionBuilder[T, B] = new CqlRequestActionBuilder(attr) /** * Set Consistency Level @@ -36,7 +36,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param level ConsistencyLevel * @return */ - def withConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + def withConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(cl = Some(level))) /** @@ -44,7 +44,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * * @return */ - def withIdempotency():DseCqlAttributesBuilder[T] = + def withIdempotency():DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(idempotent = Some(true))) /** @@ -52,7 +52,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param node Node * @return */ - def withNode(node: Node):DseCqlAttributesBuilder[T] = + def withNode(node: Node):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(node = Some(node))) /** @@ -60,7 +60,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * * @return */ - def withTracingEnabled():DseCqlAttributesBuilder[T] = + def withTracingEnabled():DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(enableTrace = Some(true))) /** @@ -69,7 +69,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param pageSize CQL page size * @return */ - def withPageSize(pageSize: Int):DseCqlAttributesBuilder[T] = + def withPageSize(pageSize: Int):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(pageSize = Some(pageSize))) /** @@ -78,7 +78,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param pagingState CQL Paging state * @return */ - def withPagingState(pagingState: ByteBuffer):DseCqlAttributesBuilder[T] = + def withPagingState(pagingState: ByteBuffer):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(pagingState = Some(pagingState))) /** @@ -87,7 +87,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param queryTimestamp CQL query timestamp * @return */ - def withQueryTimestamp(queryTimestamp: Long):DseCqlAttributesBuilder[T] = + def withQueryTimestamp(queryTimestamp: Long):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(queryTimestamp = Some(queryTimestamp))) /** @@ -96,7 +96,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param routingKey the routing key to use * @return */ - def withRoutingKey(routingKey: ByteBuffer):DseCqlAttributesBuilder[T] = + def withRoutingKey(routingKey: ByteBuffer):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(routingKey = Some(routingKey))) /** @@ -105,7 +105,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param routingKeyspace the routing keyspace to set * @return */ - def withRoutingKeyspace(routingKeyspace: String):DseCqlAttributesBuilder[T] = + def withRoutingKeyspace(routingKeyspace: String):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(routingKeyspace = Some(routingKeyspace))) /** @@ -114,7 +114,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param routingToken the routing token to set * @return */ - def withRoutingToken(routingToken: Token):DseCqlAttributesBuilder[T] = + def withRoutingToken(routingToken: Token):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(routingToken = Some(routingToken))) /** @@ -123,7 +123,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param level ConsistencyLevel * @return */ - def withSerialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + def withSerialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(serialCl = Some(level))) /** @@ -132,7 +132,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @param timeout the timeout to set * @return */ - def withTimeout(timeout: Duration):DseCqlAttributesBuilder[T] = + def withTimeout(timeout: Duration):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(timeout = Some(timeout))) /** @@ -142,7 +142,7 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @return */ @deprecated("Replaced by withSerialConsistencyLevel") - def serialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + def serialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T, B] = withSerialConsistencyLevel(level) /** @@ -153,12 +153,12 @@ case class DseCqlAttributesBuilder[T <: Statement[T]](attr: DseCqlAttributes[T]) * @return */ @deprecated("Replaced by withConsistencyLevel") - def consistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T] = + def consistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T, B] = withConsistencyLevel(level) - def check(check: DseCqlCheck):DseCqlAttributesBuilder[T] = + def check(check: DseCqlCheck):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(cqlChecks = check :: attr.cqlChecks)) - def check(check: GenericCheck):DseCqlAttributesBuilder[T] = + def check(check: GenericCheck):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index 2a70018..eeb16a8 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -6,7 +6,15 @@ package com.datastax.gatling.plugin.model -import com.datastax.oss.driver.api.core.cql.{BatchStatement, BoundStatement, PreparedStatement, SimpleStatement, SimpleStatementBuilder} +import com.datastax.oss.driver.api.core.cql.{ + BatchStatement => BatchS, + BatchStatementBuilder => BatchB, + BoundStatement => BoundS, + BoundStatementBuilder => BoundB, + SimpleStatement => SimpleS, + SimpleStatementBuilder => SimpleB, + _ +} import com.datastax.gatling.plugin._ import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.core.session.Expression @@ -29,7 +37,7 @@ case class DseCqlStatementBuilder(tag: String) { * @return */ @deprecated("Replaced by executeStatement(String)") - def executeCql(query: String): DseCqlAttributesBuilder[SimpleStatement] = + def executeCql(query: String): DseCqlAttributesBuilder[SimpleS, SimpleB] = executeStatement(query) /** @@ -38,8 +46,8 @@ case class DseCqlStatementBuilder(tag: String) { * @param query Simple string query * @return */ - def executeStatement(query: String): DseCqlAttributesBuilder[SimpleStatement] = - executeStatement(new SimpleStatementBuilder(query).build) + def executeStatement(query: String): DseCqlAttributesBuilder[SimpleS, SimpleB] = + executeStatement(new SimpleB(query).build) /** * Execute a Simple Statement @@ -47,7 +55,7 @@ case class DseCqlStatementBuilder(tag: String) { * @param statement SimpleStatement * @return */ - def executeStatement(statement: SimpleStatement): DseCqlAttributesBuilder[SimpleStatement] = + def executeStatement(statement: SimpleS): DseCqlAttributesBuilder[SimpleS, SimpleB] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -90,7 +98,7 @@ case class DseCqlStatementBuilder(tag: String) { * * @param preparedStatement CQL Prepared statement with named parameters */ - def executeNamed(preparedStatement: PreparedStatement): DseCqlAttributesBuilder[BoundStatement] = + def executeNamed(preparedStatement: PreparedStatement): DseCqlAttributesBuilder[BoundS, BoundB] = DsePreparedCqlStatementBuilder(tag, preparedStatement).withSessionParams() /** @@ -98,7 +106,7 @@ case class DseCqlStatementBuilder(tag: String) { * * @param preparedStatements Array of prepared statements */ - def executePreparedBatch(preparedStatements: Array[PreparedStatement]): DseCqlAttributesBuilder[BatchStatement] = + def executePreparedBatch(preparedStatements: Array[PreparedStatement]): DseCqlAttributesBuilder[BatchS, BatchB] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -114,14 +122,14 @@ case class DseCqlStatementBuilder(tag: String) { * @param payloadSessionKey Session key of the payload from session/feed * @return */ - def executeCustomPayload(statement: SimpleStatement, payloadSessionKey: String): DseCqlAttributesBuilder[SimpleStatement] = + def executeCustomPayload(statement: SimpleS, payloadSessionKey: String): DseCqlAttributesBuilder[SimpleS, SimpleB] = DseCqlAttributesBuilder( DseCqlAttributes( tag, DseCqlCustomPayloadStatement(statement, payloadSessionKey), cqlStatements = Seq(statement.getQuery))) - def executePreparedFromSession(key: String): DseCqlAttributesBuilder[BoundStatement] = + def executePreparedFromSession(key: String): DseCqlAttributesBuilder[BoundS, BoundB] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -141,7 +149,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * * @return */ - def withSessionParams(): DseCqlAttributesBuilder[BoundStatement] = + def withSessionParams(): DseCqlAttributesBuilder[BoundS, BoundB] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -154,7 +162,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * @param params Gatling Session variables * @return */ - def withParams(params: Expression[AnyRef]*): DseCqlAttributesBuilder[BoundStatement] = + def withParams(params: Expression[AnyRef]*): DseCqlAttributesBuilder[BoundS, BoundB] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -168,7 +176,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * @param sessionKeys Gatling Session Keys * @return */ - def withParams(sessionKeys: List[String]): DseCqlAttributesBuilder[BoundStatement] = + def withParams(sessionKeys: List[String]): DseCqlAttributesBuilder[BoundS, BoundB] = DseCqlAttributesBuilder( DseCqlAttributes( tag, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 7b18fb8..581bd70 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -8,7 +8,15 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer -import com.datastax.oss.driver.api.core.cql._ +import com.datastax.oss.driver.api.core.cql.{ + BatchStatement => BatchS, + BatchStatementBuilder => BatchB, + BoundStatement => BoundS, + BoundStatementBuilder => BoundB, + SimpleStatement => SimpleS, + SimpleStatementBuilder => SimpleB, + _ +} import com.datastax.gatling.plugin.exceptions.DseCqlStatementException import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.commons.validation._ @@ -17,18 +25,18 @@ import io.gatling.core.session._ import scala.collection.JavaConverters._ import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseCqlStatement[T <: Statement[T]] extends DseStatement[StatementBuilder[_,T]] +trait DseCqlStatement[T <: Statement[T], B <: StatementBuilder[B,T]] extends DseStatement[B] /** * Simple CQL Statement from the java driver * * @param statement the statement to execute */ -case class DseCqlSimpleStatement(statement: SimpleStatement) - extends DseCqlStatement[SimpleStatement] { +case class DseCqlSimpleStatement(statement: SimpleS) + extends DseCqlStatement[SimpleS, SimpleB] { - def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,SimpleStatement]] = { - SimpleStatement.builder(statement).success + def buildFromSession(gatlingSession: Session): Validation[SimpleB] = { + SimpleS.builder(statement).success } } @@ -38,14 +46,14 @@ case class DseCqlSimpleStatement(statement: SimpleStatement) * @param preparedStatement the prepared statement on which to bind parameters */ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement) - extends DseCqlStatement[BoundStatement] { + extends DseCqlStatement[BoundS, BoundB] { - def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { - val template:BoundStatement = bindParams( + def buildFromSession(gatlingSession: Session): Validation[BoundB] = { + val template:BoundS = bindParams( gatlingSession, preparedStatement.bind(), cqlTypes.getParamsMap(preparedStatement)) - new BoundStatementBuilder(template).success + new BoundB(template).success } /** @@ -56,10 +64,10 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare * @param queryParams CQL Query Named Params and Types * @return */ - protected def bindParams(gatlingSession: Session, template: BoundStatement, - queryParams: Map[String, Int]): BoundStatement = { + protected def bindParams(gatlingSession: Session, template: BoundS, + queryParams: Map[String, Int]): BoundS = { val completedBuilder = - queryParams.foldLeft(new BoundStatementBuilder(template)) { + queryParams.foldLeft(new BoundB(template)) { (builder, kv) => kv match { case (gatlingSessionKey, valType) => @@ -79,9 +87,9 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, params: Expression[AnyRef]*) - extends DseCqlStatement[BoundStatement] { + extends DseCqlStatement[BoundS, BoundB] { - def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { + def buildFromSession(gatlingSession: Session): Validation[BoundB] = { val parsedParams: Seq[Validation[AnyRef]] = params.map(param => param(gatlingSession)) if (parsedParams.exists(_.isInstanceOf[Failure])) { val firstError = StringBuilder.newBuilder @@ -91,8 +99,8 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt .onFailure(msg => firstError.append(msg)) firstError.toString().failure } else { - val template:BoundStatement = preparedStatement.bind(parsedParams.map(_.get): _*) - new BoundStatementBuilder(template).success + val template:BoundS = preparedStatement.bind(parsedParams.map(_.get): _*) + new BoundB(template).success } } } @@ -105,7 +113,7 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, sessionKeys: Seq[String]) - extends DseCqlStatement[BoundStatement] { + extends DseCqlStatement[BoundS, BoundB] { /** * Apply the Gatling session params to the Prepared statement @@ -113,9 +121,9 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param gatlingSession DseSession * @return */ - def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { - val template:BoundStatement = bindParams(gatlingSession, preparedStatement.bind(), sessionKeys) - new BoundStatementBuilder(template).success + def buildFromSession(gatlingSession: Session): Validation[BoundB] = { + val template:BoundS = bindParams(gatlingSession, preparedStatement.bind(), sessionKeys) + new BoundB(template).success } /** @@ -126,11 +134,11 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param sessionKeys List of session params to apply, put in order of query ?'s * @return */ - protected def bindParams(gatlingSession: Session, template: BoundStatement, - sessionKeys: Seq[String]): BoundStatement = { + protected def bindParams(gatlingSession: Session, template: BoundS, + sessionKeys: Seq[String]): BoundS = { val params = cqlTypes.getParamsList(preparedStatement) val completedBuilder = - sessionKeys.foldLeft((0,new BoundStatementBuilder(template))) { + sessionKeys.foldLeft((0,new BoundB(template))) { (acc, gatlingSessionKey) => acc match { case (cnt, builder) => @@ -150,10 +158,10 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param statements CQL Prepared Statements */ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, statements: Seq[PreparedStatement]) - extends DseCqlStatement[BatchStatement] { + extends DseCqlStatement[BatchS, BatchB] { - def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BatchStatement]] = { - val builder:BatchStatementBuilder = BatchStatement.builder(DefaultBatchType.LOGGED) + def buildFromSession(gatlingSession: Session): Validation[BatchB] = { + val builder:BatchB = BatchS.builder(DefaultBatchType.LOGGED) val batchables = statements.map(bindParams(gatlingSession)) builder.addStatements(batchables:_*).success } @@ -166,10 +174,10 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * @param statement CQL Prepared Statement * @return */ - protected def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundStatement = { + protected def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundS = { val queryParams: Map[String, Int] = cqlTypes.getParamsMap(statement) val completedBuilder = - queryParams.foldLeft(new BoundStatementBuilder(statement.bind())) { + queryParams.foldLeft(new BoundB(statement.bind())) { (builder, kv) => kv match { @@ -188,10 +196,10 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * @param statement SimpleStaten * @param payloadRef session variable for custom payload */ -case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: String) - extends DseCqlStatement[SimpleStatement] { +case class DseCqlCustomPayloadStatement(statement: SimpleS, payloadRef: String) + extends DseCqlStatement[SimpleS, SimpleB] { - def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,SimpleStatement]] = { + def buildFromSession(gatlingSession: Session): Validation[SimpleB] = { if (!gatlingSession.contains(payloadRef)) { throw new DseCqlStatementException(s"Passed sessionKey: {$payloadRef} does not exist in Session.") } @@ -200,7 +208,7 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: val payload = gatlingSession(payloadRef).as[Map[String, ByteBuffer]].asJava statement.setCustomPayload(payload) } match { - case TrySuccess(stmt) => SimpleStatement.builder(stmt).success + case TrySuccess(stmt) => SimpleS.builder(stmt).success case TryFailure(error) => error.getMessage.failure } } @@ -213,9 +221,9 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: * @param sessionKey the session key which is associated to a PreparedStatement */ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, sessionKey: String) - extends DseCqlStatement[BoundStatement] { + extends DseCqlStatement[BoundS, BoundB] { - def buildFromSession(gatlingSession: Session): Validation[StatementBuilder[_,BoundStatement]] = { + def buildFromSession(gatlingSession: Session): Validation[BoundB] = { if (!gatlingSession.contains(sessionKey)) { throw new DseCqlStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index 25545fb..86e831a 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -9,8 +9,7 @@ package com.datastax.gatling.plugin.model import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel -import com.datastax.oss.driver.api.core.cql.Row -import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement, GraphStatementBuilderBase} +import com.datastax.dse.driver.api.core.graph.{GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} import com.datastax.oss.driver.api.core.metadata.Node @@ -24,22 +23,19 @@ import com.datastax.oss.driver.api.core.metadata.Node * @param cl Consistency Level to be used * @param graphChecks Data-level checks to be run after response is returned * @param genericChecks Low-level checks to be run after response is returned - * @param userOrRole User or role to be used when proxy auth is enabled - * @param readTimeout Read timeout to be used * @param idempotent Set request to be idempotent i.e. whether it can be applied multiple times - * @param defaultTimestamp Set default timestamp on request, overriding current system time - * @param readCL Consistency level to use for the read part of the query - * @param writeCL Consistency level to use for the write part of the query - * @param graphName Name of the graph to use if different from the one used when connecting - * @param graphLanguage Language used in the query - * @param graphSource Graph source to use if different from the one used when connecting - * @param isSystemQuery Whether the query is a system one and should be used without any graph name - * @param graphInternalOptions Query-specific options not available in the driver public API - * @param graphTransformResults Function to use in order to transform a row into a Graph node + * @param node Set the node that should handle this query + * @param graphName Name of the graph to use if different from the one used when connecting + * @param readCL Consistency level to use for the read part of the query + * @param subProtocol Name of the graph protocol to use for encoding/decoding + * @param timeout Timeout to use for this request + * @param timestamp Timestamp to use for this request + * @param traversalSource The traversal source for this request + * @param writeCL Consistency level to use for the write part of the query */ -case class DseGraphAttributes[T <: GraphStatement[T]] +case class DseGraphAttributes[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B,T]] (tag: String, - statement: DseGraphStatement[T], + statement: DseGraphStatement[T, B], graphChecks: List[DseGraphCheck] = List.empty, genericChecks: List[GenericCheck] = List.empty, /* General attributes */ diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index b84ab4c..59d4b74 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -10,7 +10,7 @@ import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.Row -import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement} +import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} import com.datastax.gatling.plugin.request.GraphRequestActionBuilder import com.datastax.oss.driver.api.core.metadata.Node @@ -21,13 +21,13 @@ import com.datastax.oss.driver.shaded.guava.common.base.Function * * @param attr Addition Attributes */ -case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttributes[T]) { +case class DseGraphAttributesBuilder[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B,T]](attr: DseGraphAttributes[T, B]) { /** * Builds to final action to run * * @return */ - def build(): GraphRequestActionBuilder[T] = new GraphRequestActionBuilder(attr) + def build(): GraphRequestActionBuilder[T, B] = new GraphRequestActionBuilder(attr) /** * Set Consistency Level @@ -35,7 +35,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param level ConsistencyLevel * @return */ - def withConsistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T] = + def withConsistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(cl = Some(level))) /** @@ -43,7 +43,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * * @return */ - def withIdempotency():DseGraphAttributesBuilder[T] = + def withIdempotency():DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(idempotent = Some(true))) /** @@ -52,7 +52,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param name Graph name * @return */ - def withName(name: String):DseGraphAttributesBuilder[T] = + def withName(name: String):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(graphName = Some(name))) /** @@ -60,7 +60,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param node Node * @return */ - def withNode(node: Node):DseGraphAttributesBuilder[T] = + def withNode(node: Node):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(node = Some(node))) /** @@ -69,7 +69,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param readCL Consistency Level to use * @return */ - def withReadConsistency(readCL: ConsistencyLevel):DseGraphAttributesBuilder[T] = + def withReadConsistency(readCL: ConsistencyLevel):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(readCL = Some(readCL))) /** @@ -78,7 +78,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param subProtocol the sub-protocol to use * @return */ - def withSubProtocol(subProtocol: String):DseGraphAttributesBuilder[T] = + def withSubProtocol(subProtocol: String):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(subProtocol = Some(subProtocol))) /** @@ -87,7 +87,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param timeout the timeout to use * @return */ - def withTimeout(timeout: Duration):DseGraphAttributesBuilder[T] = + def withTimeout(timeout: Duration):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(timeout = Some(timeout))) /** @@ -96,7 +96,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param timestamp the timestamp to use * @return */ - def withTimestamp(timestamp: Long):DseGraphAttributesBuilder[T] = + def withTimestamp(timestamp: Long):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(timestamp = Some(timestamp))) /** @@ -105,7 +105,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param traversalSource the traversal source to use * @return */ - def withTraversalSource(traversalSource: String):DseGraphAttributesBuilder[T] = + def withTraversalSource(traversalSource: String):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(traversalSource = Some(traversalSource))) /** @@ -114,7 +114,7 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @param writeCL Consistency Level to use * @return */ - def withWriteConsistency(writeCL: ConsistencyLevel):DseGraphAttributesBuilder[T] = + def withWriteConsistency(writeCL: ConsistencyLevel):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(writeCL = Some(writeCL))) /** @@ -125,10 +125,10 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T]](attr: DseGraphAttri * @return */ @deprecated("use withConsistencyLevel() instead, will be removed in future version") - def consistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T] = withConsistencyLevel(level) + def consistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T, B] = withConsistencyLevel(level) - def check(check: DseGraphCheck):DseGraphAttributesBuilder[T] = + def check(check: DseGraphCheck):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(graphChecks = check :: attr.graphChecks)) - def check(check: GenericCheck):DseGraphAttributesBuilder[T] = + def check(check: GenericCheck):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala index 9b38d3e..1959675 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala @@ -6,7 +6,11 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, ScriptGraphStatement, ScriptGraphStatementBuilder} +import com.datastax.dse.driver.api.core.graph.{ + FluentGraphStatement => FluentS, + FluentGraphStatementBuilder => FluentB, + ScriptGraphStatement => ScriptS, + ScriptGraphStatementBuilder => ScriptB} import io.gatling.core.session.{Expression, Session} /** @@ -22,7 +26,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param strStatement Graph Query String * @return */ - def executeGraph(strStatement: Expression[String]): DseGraphAttributesBuilder[ScriptGraphStatement] = { + def executeGraph(strStatement: Expression[String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -36,8 +40,8 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Simple Graph Statement * @return */ - @deprecated("Replaced by executeGraph(ScriptGraphStatement)") - def executeGraphStatement(gStatement: ScriptGraphStatement): DseGraphParametrizedStatementBuilder = + @deprecated("Replaced by executeGraph(ScriptS)") + def executeGraphStatement(gStatement: ScriptS): DseGraphParametrizedStatementBuilder = executeGraph(gStatement) /** @@ -47,8 +51,8 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Simple Graph Statement * @return */ - def executeGraph(gStatement: ScriptGraphStatement):DseGraphParametrizedStatementBuilder = { - DseGraphParametrizedStatementBuilder(tag, new ScriptGraphStatementBuilder(gStatement)) + def executeGraph(gStatement: ScriptS):DseGraphParametrizedStatementBuilder = { + DseGraphParametrizedStatementBuilder(tag, new ScriptB(gStatement)) } /** @@ -57,7 +61,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Graph Statement from a Fluent API builder * @return */ - def executeGraphFluent(gStatement: FluentGraphStatement): DseGraphAttributesBuilder[FluentGraphStatement] = { + def executeGraphFluent(gStatement: FluentS): DseGraphAttributesBuilder[FluentS, FluentB] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -77,7 +81,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param gLambda The lambda * @return */ - def executeGraphFluent(gLambda: Session => FluentGraphStatement): DseGraphAttributesBuilder[FluentGraphStatement] = { + def executeGraphFluent(gLambda: Session => FluentS): DseGraphAttributesBuilder[FluentS, FluentB] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -91,7 +95,7 @@ case class DseGraphStatementBuilder(tag: String) { * @return */ @deprecated("Replaced by executeGraphFluent{session => session(feederKey)}") - def executeGraphFeederTraversal(feederKey: String): DseGraphAttributesBuilder[FluentGraphStatement] = { + def executeGraphFeederTraversal(feederKey: String): DseGraphAttributesBuilder[FluentS, FluentB] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -105,7 +109,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param tag Query tag * @param builder Simple Graph Staetment */ -case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGraphStatementBuilder) { +case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { /** * Included for compatibility @@ -114,7 +118,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @return */ @deprecated("Replaced by withParams") - def withSetParams(paramNames: Array[String]): DseGraphAttributesBuilder[ScriptGraphStatement] = + def withSetParams(paramNames: Array[String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = withParams(paramNames.toList) /** @@ -123,7 +127,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @param paramNames List of strings to use * @return */ - def withParams(paramNames: String*): DseGraphAttributesBuilder[ScriptGraphStatement] = + def withParams(paramNames: String*): DseGraphAttributesBuilder[ScriptS, ScriptB] = withParams(paramNames.toList) /** @@ -132,7 +136,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @param paramNames List of strings to use * @return */ - def withParams(paramNames: List[String]): DseGraphAttributesBuilder[ScriptGraphStatement] = + def withParams(paramNames: List[String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -148,7 +152,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @return */ @deprecated("Replaced with withParams") - def withSetParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = + def withSetParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = withParams(paramNamesAndOverrides) @@ -160,7 +164,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @return */ @deprecated("Replaced with withParams") - def withParamOverrides(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = + def withParamOverrides(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = withParams(paramNamesAndOverrides) /** @@ -170,7 +174,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @param paramNamesAndOverrides a Map of Session parameter names to their GraphStatement parameter names * @return */ - def withParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = { + def withParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -186,7 +190,8 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @return */ @deprecated("Replaced by withRepeatedParams") - def withRepeatedSetParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = + def withRepeatedSetParams(batchSize: Int, + paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = withRepeatedParams(batchSize, paramNamesAndOverrides) /** @@ -197,7 +202,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGrap * @param paramNamesAndOverrides a Map of Session parameter names to their GraphStatement parameter names * @return */ - def withRepeatedParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement] = { + def withRepeatedParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = { def repeatParameters(params: Map[String, String]): Map[String, String] = batchSize match { // Gatling has a weird behavior when feeding multiple values // Feeding 1 value gives non-suffixed variables whereas feeding more gives suffixed variables starting by the diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index db46588..e747ba1 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -6,7 +6,12 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph._ +import com.datastax.dse.driver.api.core.graph.{ + FluentGraphStatement => FluentS, + FluentGraphStatementBuilder => FluentB, + ScriptGraphStatement => ScriptS, + ScriptGraphStatementBuilder => ScriptB, + _} import com.datastax.gatling.plugin.exceptions.DseGraphStatementException import io.gatling.commons.validation._ import io.gatling.core.session.{Expression, Session} @@ -14,7 +19,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal import scala.util.{Try, Failure => TryFailure, Success => TrySuccess} -trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[GraphStatementBuilderBase[_,T]] +trait DseGraphStatement[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B,T]] extends DseStatement[B] /** * Simple DSE Graph Statement from a String @@ -22,10 +27,10 @@ trait DseGraphStatement[T <: GraphStatement[_]] extends DseStatement[GraphStatem * @param statement the Gremlin String to execute */ case class GraphStringStatement(statement: Expression[String]) - extends DseGraphStatement[ScriptGraphStatement] { + extends DseGraphStatement[ScriptS, ScriptB] { - def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,ScriptGraphStatement]] = { - statement(gatlingSession).flatMap(stmt => ScriptGraphStatement.builder(stmt).success) + def buildFromSession(gatlingSession: Session): Validation[ScriptB] = { + statement(gatlingSession).flatMap(stmt => ScriptS.builder(stmt).success) } } @@ -34,11 +39,11 @@ case class GraphStringStatement(statement: Expression[String]) * * @param statement the Fluent Statement */ -case class GraphFluentStatement(statement: FluentGraphStatement) - extends DseGraphStatement[FluentGraphStatement] { +case class GraphFluentStatement(statement: FluentS) + extends DseGraphStatement[FluentS, FluentB] { - def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { - FluentGraphStatement.builder(statement).success + def buildFromSession(gatlingSession: Session): Validation[FluentB] = { + FluentS.builder(statement).success } } @@ -49,11 +54,11 @@ case class GraphFluentStatement(statement: FluentGraphStatement) * @param lambda Scala lambda that takes a Gatling User Session (from which it can retrieve parameters) * and returns a fluent Graph Statement */ -case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphStatement) - extends DseGraphStatement[FluentGraphStatement] { +case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentS) + extends DseGraphStatement[FluentS, FluentB] { - def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { - FluentGraphStatement.builder(lambda(gatlingSession)).success + def buildFromSession(gatlingSession: Session): Validation[FluentB] = { + FluentS.builder(lambda(gatlingSession)).success } } @@ -64,16 +69,16 @@ case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphSta * @param sessionKey Place a GraphTraversal in your session with this key name */ case class GraphFluentSessionKey(sessionKey: String) - extends DseGraphStatement[FluentGraphStatement] { + extends DseGraphStatement[FluentS, FluentB] { - def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,FluentGraphStatement]] = { + def buildFromSession(gatlingSession: Session): Validation[FluentB] = { if (!gatlingSession.contains(sessionKey)) { throw new DseGraphStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } Try { - FluentGraphStatement.builder(gatlingSession(sessionKey).as[GraphTraversal[_, _]]) + FluentS.builder(gatlingSession(sessionKey).as[GraphTraversal[_, _]]) } match { case TrySuccess(builder) => builder.success case TryFailure(error) => error.getMessage.failure @@ -87,8 +92,8 @@ case class GraphFluentSessionKey(sessionKey: String) * @param builder SimpleGraphStatementBuilder * @param sessionKeys Gatling session param keys mapped to their bind name, to allow name override */ -case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys: Map[String, String]) - extends DseGraphStatement[ScriptGraphStatement] { +case class GraphBoundStatement(builder: ScriptB, sessionKeys: Map[String, String]) + extends DseGraphStatement[ScriptS, ScriptB] { /** * Apply the Gatling session params passed to the GraphStatement @@ -97,7 +102,7 @@ case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys * @return */ - def buildFromSession(gatlingSession: Session): Validation[GraphStatementBuilderBase[_,ScriptGraphStatement]] = { + def buildFromSession(gatlingSession: Session): Validation[ScriptB] = { Try { sessionKeys foreach { _ match { diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index 8601da6..582c375 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -45,12 +45,12 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to * other Gatling data writers, like the console reporter. */ -class CqlRequestAction[T <: Statement[T]](val name: String, +class CqlRequestAction[T <: Statement[T], B <: StatementBuilder[B,T]](val name: String, val next: Action, val system: ActorSystem, val statsEngine: StatsEngine, val protocol: DseProtocol, - val dseAttributes: DseCqlAttributes[T], + val dseAttributes: DseCqlAttributes[T, B], val metricsLogger: MetricsLogger, val dseExecutorService: ExecutorService, val gatlingTimingSource: GatlingTimingSource) @@ -62,7 +62,7 @@ class CqlRequestAction[T <: Statement[T]](val name: String, }) } - private def buildStatement(builder:StatementBuilder[_,T]):T = { + private def buildStatement(builder:B):T = { // global options dseAttributes.cl.foreach(builder.setConsistencyLevel) @@ -89,11 +89,11 @@ class CqlRequestAction[T <: Statement[T]](val name: String, builder.build } - private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:StatementBuilder[_,T]): Unit = { + private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:B): Unit = { val stmt:T = buildStatement(builder) val responseHandler = - new CqlResponseHandler[T]( + new CqlResponseHandler[T, B]( next, session, system, diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala index 5964fcb..2816be0 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestActionBuilder.scala @@ -8,17 +8,19 @@ package com.datastax.gatling.plugin.request import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.DseCqlAttributes +import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} import io.gatling.core.action.Action import io.gatling.core.action.builder.ActionBuilder import io.gatling.core.structure.ScenarioContext import io.gatling.core.util.NameGen -class CqlRequestActionBuilder[T](val dseAttributes: DseCqlAttributes[T]) extends ActionBuilder with - NameGen { +class CqlRequestActionBuilder[T <: Statement[T], B <: StatementBuilder[B,T]](val dseAttributes: DseCqlAttributes[T, B]) + extends ActionBuilder + with NameGen { def build(ctx: ScenarioContext, next: Action): Action = { val dseComponents = ctx.protocolComponentsRegistry.components(DseProtocol.DseProtocolKey) - new CqlRequestAction[T]( + new CqlRequestAction[T, B]( dseAttributes.tag, next, ctx.system, @@ -30,4 +32,3 @@ class CqlRequestActionBuilder[T](val dseAttributes: DseCqlAttributes[T]) extends dseComponents.gatlingTimingSource) } } - diff --git a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala index abe4af8..789d3bc 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/DseRequestActor.scala @@ -8,15 +8,17 @@ package com.datastax.gatling.plugin.request import akka.actor.Actor +import com.datastax.dse.driver.api.core.graph.{GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.response.DseResponseCallback +import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} import com.typesafe.scalalogging.StrictLogging import io.gatling.core.session.Session import scala.concurrent.ExecutionException import scala.util.{Failure, Success, Try} -case class SendCqlQuery(dseRequestAction: CqlRequestAction[_], session: Session) -case class SendGraphQuery(dseRequestAction: GraphRequestAction[_], session: Session) +case class SendCqlQuery[T <: Statement[T], B <: StatementBuilder[B,T]](dseRequestAction: CqlRequestAction[T,B], session: Session) +case class SendGraphQuery[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B,T]](dseRequestAction: GraphRequestAction[T,B], session: Session) case class RecordResult[T](t: Try[T], callback: DseResponseCallback[T]) diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index c5efc05..d27f822 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -44,12 +44,12 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to * other Gatling data writers, like the console reporter. */ -class GraphRequestAction[T <: GraphStatement[T]](val name: String, +class GraphRequestAction[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B,T]](val name: String, val next: Action, val system: ActorSystem, val statsEngine: StatsEngine, val protocol: DseProtocol, - val dseAttributes: DseGraphAttributes[T], + val dseAttributes: DseGraphAttributes[T, B], val metricsLogger: MetricsLogger, val dseExecutorService: ExecutorService, val gatlingTimingSource: GatlingTimingSource) @@ -61,7 +61,7 @@ class GraphRequestAction[T <: GraphStatement[T]](val name: String, }) } - private def buildStatement(builder:GraphStatementBuilderBase[_,T]):T = { + private def buildStatement(builder:B):T = { // global options dseAttributes.cl.foreach(builder.setConsistencyLevel) @@ -80,11 +80,11 @@ class GraphRequestAction[T <: GraphStatement[T]](val name: String, builder.build } - private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:GraphStatementBuilderBase[_,T]): Unit = { + private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:B): Unit = { val stmt:T = buildStatement(builder) val responseHandler = - new GraphResponseHandler[T]( + new GraphResponseHandler[T, B]( next, session, system, diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala index 3d239a9..6f6e7f3 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestActionBuilder.scala @@ -6,6 +6,7 @@ package com.datastax.gatling.plugin.request +import com.datastax.dse.driver.api.core.graph.{GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.DseGraphAttributes import io.gatling.core.action.Action @@ -13,12 +14,13 @@ import io.gatling.core.action.builder.ActionBuilder import io.gatling.core.structure.ScenarioContext import io.gatling.core.util.NameGen -class GraphRequestActionBuilder[T](dseAttributes: DseGraphAttributes[T]) extends ActionBuilder with - NameGen { +class GraphRequestActionBuilder[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B,T]](dseAttributes: DseGraphAttributes[T, B]) + extends ActionBuilder + with NameGen { def build(ctx: ScenarioContext, next: Action): Action = { val dseComponents = ctx.protocolComponentsRegistry.components(DseProtocol.DseProtocolKey) - new GraphRequestAction[T]( + new GraphRequestAction[T, B]( dseAttributes.tag, next, ctx.system, diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 81818e0..648a898 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -26,20 +26,20 @@ abstract class DseResponse { def schemaInAgreement(): Boolean = executionInfo.isSchemaInAgreement } -class GraphResponse(graphResultSet: AsyncGraphResultSet, dseAttributes: DseGraphAttributes[_]) extends DseResponse with LazyLogging { +class GraphResponse(graphResultSet: AsyncGraphResultSet, dseAttributes: DseGraphAttributes[_, _]) extends DseResponse with LazyLogging { override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo.asInstanceOf[ExecutionInfo] def getGraphResultSet: AsyncGraphResultSet = graphResultSet - def getDseAttributes: DseGraphAttributes[_] = dseAttributes + def getDseAttributes: DseGraphAttributes[_, _] = dseAttributes } -class CqlResponse(cqlResultSet: AsyncResultSet, dseAttributes: DseCqlAttributes[_]) extends DseResponse with LazyLogging { +class CqlResponse(cqlResultSet: AsyncResultSet, dseAttributes: DseCqlAttributes[_,_]) extends DseResponse with LazyLogging { override def executionInfo(): ExecutionInfo = cqlResultSet.getExecutionInfo def getCqlResultSet: AsyncResultSet = cqlResultSet - def getDseAttributes: DseCqlAttributes[_] = dseAttributes + def getDseAttributes: DseCqlAttributes[_,_] = dseAttributes } diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 6cb034d..208ad09 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem import com.datastax.oss.driver.api.core.cql._ -import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphResultSet, GraphStatement} +import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphResultSet, GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.datastax.gatling.plugin.utils.{ResponseTime, ResponseTimeBuilder} @@ -138,13 +138,13 @@ abstract class DseResponseHandler[S, RS, R <: DseResponse] extends StrictLogging } } -class GraphResponseHandler[T <: GraphStatement[_]](val next: Action, +class GraphResponseHandler[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B,T]](val next: Action, val session: Session, val system: ActorSystem, val statsEngine: StatsEngine, val responseTimeBuilder: ResponseTimeBuilder, val stmt: T, - val dseAttributes: DseGraphAttributes[T], + val dseAttributes: DseGraphAttributes[T, B], val metricsLogger: MetricsLogger) extends DseResponseHandler[T, AsyncGraphResultSet, GraphResponse] { override protected def tag: String = dseAttributes.tag @@ -155,13 +155,13 @@ class GraphResponseHandler[T <: GraphStatement[_]](val next: Action, override protected def coordinator(rs: AsyncGraphResultSet): Node = rs.getExecutionInfo.getCoordinator } -class CqlResponseHandler[T <: Statement[_]](val next: Action, +class CqlResponseHandler[T <: Statement[T], B <: StatementBuilder[B,T]](val next: Action, val session: Session, val system: ActorSystem, val statsEngine: StatsEngine, val responseTimeBuilder: ResponseTimeBuilder, val stmt: T, - val dseAttributes: DseCqlAttributes[T], + val dseAttributes: DseCqlAttributes[T, B], val metricsLogger: MetricsLogger) extends DseResponseHandler[T, AsyncResultSet, CqlResponse] { override protected def tag: String = dseAttributes.tag From 1c061587f72ff7b2fa58f46ef10c9db655f0abec Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 11 Dec 2019 10:20:07 -0600 Subject: [PATCH 26/62] Initial work on spec fixes --- .../gatling/plugin/DseCqlStatementSpec.scala | 37 +++++++++---------- .../plugin/DseGraphStatementSpec.scala | 12 +++--- .../plugin/base/BaseCassandraServerSpec.scala | 2 +- .../plugin/base/GatlingDseSession.scala | 13 +++---- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala index 632b445..13dfdbc 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala @@ -2,12 +2,12 @@ package com.datastax.gatling.plugin import java.nio.ByteBuffer -import com.datastax.driver.core.ColumnDefinitions.Definition -import com.datastax.driver.core._ import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.exceptions.DseCqlStatementException import com.datastax.gatling.plugin.model._ import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil +import com.datastax.oss.driver.api.core.`type`.{DataType, DataTypes} +import com.datastax.oss.driver.api.core.cql._ import io.gatling.commons.validation._ import io.gatling.core.session.Session import io.gatling.core.session.el.ElCompiler @@ -15,13 +15,10 @@ import org.easymock.EasyMock._ import scala.collection.JavaConverters._ - class DseCqlStatementSpec extends BaseSpec { val prepared = mock[PreparedStatement] val mockColDefinitions = mock[ColumnDefinitions] - val mockDefinitions = mock[Definition] - val mockDefinitionId = mock[Definition] val mockBoundStatement = mock[BoundStatement] val mockCqlTypes = mock[CqlPreparedStatementUtil] @@ -37,6 +34,8 @@ class DseCqlStatementSpec extends BaseSpec { val invalidStmt = "select * from test where invalid = 'test'" val invalidExceptionError = "Prepared Statements must have at least one settable param. Query: " + invalidStmt + implicit def dataTypeToInt(in:DataType):Int = in.getProtocolCode + before { reset(prepared, mockBoundStatement, mockCqlTypes) } @@ -46,7 +45,7 @@ class DseCqlStatementSpec extends BaseSpec { it("should succeed with a passed SimpleStatement", CqlTest) { - val stmt = new SimpleStatement("select * from keyspace.table where id = 5") + val stmt = SimpleStatement.builder("select * from keyspace.table where id = 5").build() val result = DseCqlSimpleStatement(stmt).buildFromSession(validGatlingSession) result shouldBe a[Success[_]] @@ -77,7 +76,7 @@ class DseCqlStatementSpec extends BaseSpec { it("should fail if the expression is wrong and return the 1st error") { expecting { - prepared.getVariables.andStubReturn(mockColDefinitions) + prepared.getVariableDefinitions.andStubReturn(mockColDefinitions) } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { @@ -93,16 +92,16 @@ class DseCqlStatementSpec extends BaseSpec { describe("DseCqlBoundStatementWithParamList") { val validParamList = Seq("foo", "bar") - val paramsList = List[DataType.Name](DataType.Name.TEXT, DataType.Name.INT) + val paramsList = List[Int](DataTypes.TEXT, DataTypes.INT) it("correctly bind values to a prepared statement") { expecting { prepared.bind().andReturn(mockBoundStatement) mockCqlTypes.getParamsList(prepared).andReturn(paramsList) - mockCqlTypes.bindParamByOrder(validGatlingSession, mockBoundStatement, DataType.Name.TEXT, "foo", 0) + mockCqlTypes.bindParamByOrder(validGatlingSession, mockBoundStatement, DataTypes.TEXT, "foo", 0) .andReturn(mockBoundStatement) - mockCqlTypes.bindParamByOrder(validGatlingSession, mockBoundStatement, DataType.Name.INT, "bar", 1) + mockCqlTypes.bindParamByOrder(validGatlingSession, mockBoundStatement, DataTypes.INT, "bar", 1) .andReturn(mockBoundStatement) } @@ -121,8 +120,8 @@ class DseCqlStatementSpec extends BaseSpec { expecting { prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataType.Name.INT)) - mockCqlTypes.bindParamByName(validGatlingSession, mockBoundStatement, DataType.Name.INT, "foo") + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) + mockCqlTypes.bindParamByName(validGatlingSession, mockBoundStatement, DataTypes.INT, "foo") .andReturn(mockBoundStatement) } @@ -141,8 +140,8 @@ class DseCqlStatementSpec extends BaseSpec { val sessionWithStatement: Session = validGatlingSession.set("statementKey", prepared) expecting { prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataType.Name.INT)) - mockCqlTypes.bindParamByName(sessionWithStatement, mockBoundStatement, DataType.Name.INT, "foo") + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) + mockCqlTypes.bindParamByName(sessionWithStatement, mockBoundStatement, DataTypes.INT, "foo") .andReturn(mockBoundStatement) } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { @@ -172,11 +171,11 @@ class DseCqlStatementSpec extends BaseSpec { it("correctly bind values to a prepared statement") { expecting { - mockBoundStatement.getOutgoingPayload.andReturn(Map("test" -> ByteBuffer.wrap(Array(12.toByte))).asJava) - mockBoundStatement.getOutgoingPayload.andReturn(Map("test" -> ByteBuffer.wrap(Array(12.toByte))).asJava) + mockBoundStatement.getCustomPayload.andReturn(Map("test" -> ByteBuffer.wrap(Array(12.toByte))).asJava) + mockBoundStatement.getCustomPayload.andReturn(Map("test" -> ByteBuffer.wrap(Array(12.toByte))).asJava) prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataType.Name.INT)) - mockCqlTypes.bindParamByName(validGatlingSession, mockBoundStatement, DataType.Name.INT, "foo") + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) + mockCqlTypes.bindParamByName(validGatlingSession, mockBoundStatement, DataTypes.INT, "foo") .andReturn(mockBoundStatement) } @@ -190,7 +189,7 @@ class DseCqlStatementSpec extends BaseSpec { describe("DseCqlCustomPayloadStatement") { - val stmt = new SimpleStatement("select * from keyspace.table where id = 5") + val stmt = SimpleStatement.builder("select * from keyspace.table where id = 5").build() it("should succeed with a passed SimpleStatement", CqlTest) { diff --git a/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala index 69c6bd1..088deda 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala @@ -1,8 +1,8 @@ package com.datastax.gatling.plugin -import com.datastax.driver.dse.DseSession -import com.datastax.driver.dse.graph.SimpleGraphStatement -import com.datastax.dse.graph.api.DseGraph +import com.datastax.dse.driver.api.core.DseSession +import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, ScriptGraphStatement} +import com.datastax.dse.driver.api.core.graph.DseGraph.g import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.model.{GraphBoundStatement, GraphFluentStatement, GraphStringStatement} import io.gatling.commons.validation.{Failure, Success} @@ -10,7 +10,6 @@ import io.gatling.core.session.Session import io.gatling.core.session.el.ElCompiler import org.easymock.EasyMock.reset - class DseGraphStatementSpec extends BaseSpec { val mockDseSession = mock[DseSession] @@ -42,8 +41,7 @@ class DseGraphStatementSpec extends BaseSpec { describe("FluentStatement") { - val g = DseGraph.traversal(mockDseSession) - val gStatement = DseGraph.statementFromTraversal(g.V().limit(5)) + val gStatement = FluentGraphStatement.newInstance(g.V().limit(5)) val target = GraphFluentStatement(gStatement) it("should correctly return StringStatement for a valid expression") { @@ -54,7 +52,7 @@ class DseGraphStatementSpec extends BaseSpec { describe("GraphBoundStatement") { - val graphStatement = new SimpleGraphStatement("g.addV(label, vertexLabel).property('type', myType)") + val graphStatement = ScriptGraphStatement.builder("g.addV(label, vertexLabel).property('type', myType)") val target = GraphBoundStatement(graphStatement, Map("test" -> "type")) it("should suceeed with a valid session") { diff --git a/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala b/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala index aee98db..f696720 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala @@ -2,7 +2,7 @@ package com.datastax.gatling.plugin.base import java.nio.file.Files -import com.datastax.driver.dse.DseSession +import com.datastax.dse.driver.api.core.DseSession import org.cassandraunit.utils.EmbeddedCassandraServerHelper /** diff --git a/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala b/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala index 8af4d84..880eb24 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala @@ -1,12 +1,12 @@ package com.datastax.gatling.plugin.base -import com.datastax.driver.dse.{DseCluster, DseSession} +import java.net.InetSocketAddress + +import com.datastax.dse.driver.api.core.DseSession import org.cassandraunit.utils.EmbeddedCassandraServerHelper trait GatlingDseSession { - private var dseCluster: DseCluster = _ - private var session: DseSession = _ /** @@ -29,15 +29,14 @@ trait GatlingDseSession { cPort = EmbeddedCassandraServerHelper.getNativeTransportPort } - dseCluster = + session = try { - DseCluster.builder().addContactPoint(cassandraHost).withPort(cPort).build() + DseSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).build() } catch { - case _: Exception => DseCluster.builder().addContactPoint(cassandraHost).withPort(cPort).build() + case _: Exception => DseSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).build() } - session = dseCluster.connect() session } From 88089e33d2e234f58f0623a8ce290892e6d215e7 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 18 Dec 2019 11:36:55 -0600 Subject: [PATCH 27/62] Code review feedback --- .../plugin/model/DseGraphStatements.scala | 2 +- .../gatling/plugin/utils/ResultSetUtils.scala | 50 +++++++++---------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index e747ba1..31bc64a 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -107,7 +107,7 @@ case class GraphBoundStatement(builder: ScriptB, sessionKeys: Map[String, String sessionKeys foreach { _ match { case (k, v) => builder.setQueryParam(v, gatlingSession(k).as[Object]) - case _ => throw new RuntimeException() + case _ => throw new RuntimeException(s"Observed ${_} instead of expected key-value pair") } } builder diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala index 357dd7f..264eaf1 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/ResultSetUtils.scala @@ -2,34 +2,30 @@ package com.datastax.gatling.plugin.utils import java.util.concurrent.CompletionStage -import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphNode} -import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, Row} +import com.datastax.dse.driver.api.core.graph.{ AsyncGraphResultSet, GraphNode } +import com.datastax.oss.driver.api.core.cql.{ AsyncResultSet, Row } import org.apache.tinkerpop.gremlin.process.traversal.Path -import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} +import org.apache.tinkerpop.gremlin.structure.{ Edge, Property, Vertex, VertexProperty } import collection.JavaConverters._ object ResultSetUtils { - def asyncResultSetToIterator(resultSet:AsyncResultSet): Iterator[Row] = - new AsyncResultSetIterator( - new CqlAsyncRS(resultSet)) + def asyncResultSetToIterator(resultSet: AsyncResultSet): Iterator[Row] = + new IteratorFromAsyncResultSet(new CqlAsyncRS(resultSet)) - def asyncGraphResultSetToIterator(resultSet:AsyncGraphResultSet): Iterator[GraphNode] = - new AsyncResultSetIterator( - new GraphAsyncRS(resultSet)) + def asyncGraphResultSetToIterator(resultSet: AsyncGraphResultSet): Iterator[GraphNode] = + new IteratorFromAsyncResultSet(new GraphAsyncRS(resultSet)) } object GraphResultSetUtils { - private def buildFilterAndMapFn[T] - (filterFn: GraphNode => Boolean, mapFn: GraphNode => T) - (resultSet: AsyncGraphResultSet, key:String):Iterator[T] = { - ResultSetUtils.asyncGraphResultSetToIterator(resultSet ) + private def buildFilterAndMapFn[T](filterFn: GraphNode => Boolean, mapFn: GraphNode => T)(resultSet: AsyncGraphResultSet, key: String): Iterator[T] = + ResultSetUtils + .asyncGraphResultSetToIterator(resultSet) .map(graphNode => graphNode.getByKey(key)) .filter(filterFn) .map(mapFn) - } def edges: (AsyncGraphResultSet, String) => Iterator[Edge] = buildFilterAndMapFn(_.isEdge, _.asEdge) @@ -45,27 +41,27 @@ object GraphResultSetUtils { } trait AsyncRS[T] { - def hasMorePages:Boolean - def currentPage:Iterable[T] - def fetchNextPage:CompletionStage[AsyncRS[T]] + def hasMorePages: Boolean + def currentPage: Iterable[T] + def fetchNextPage: CompletionStage[AsyncRS[T]] } -class CqlAsyncRS(rs:AsyncResultSet) extends AsyncRS[Row] { - override def hasMorePages: Boolean = rs.hasMorePages - override def currentPage: Iterable[Row] = rs.currentPage.asScala +class CqlAsyncRS(rs: AsyncResultSet) extends AsyncRS[Row] { + override def hasMorePages: Boolean = rs.hasMorePages + override def currentPage: Iterable[Row] = rs.currentPage.asScala override def fetchNextPage: CompletionStage[AsyncRS[Row]] = rs.fetchNextPage.thenApplyAsync(new CqlAsyncRS(_)) } -class GraphAsyncRS(rs:AsyncGraphResultSet) extends AsyncRS[GraphNode] { - override def hasMorePages: Boolean = rs.hasMorePages - override def currentPage: Iterable[GraphNode] = rs.currentPage.asScala +class GraphAsyncRS(rs: AsyncGraphResultSet) extends AsyncRS[GraphNode] { + override def hasMorePages: Boolean = rs.hasMorePages + override def currentPage: Iterable[GraphNode] = rs.currentPage.asScala override def fetchNextPage: CompletionStage[AsyncRS[GraphNode]] = rs.fetchNextPage.thenApplyAsync(new GraphAsyncRS(_)) } /* Note that this iterator isn't thread-safe */ -class AsyncResultSetIterator[T](rs:AsyncRS[T]) extends Iterator[T] { - var working = rs - var iter = rs.currentPage.iterator +class IteratorFromAsyncResultSet[T](rs: AsyncRS[T]) extends Iterator[T] { + var working = rs + var iter = rs.currentPage.iterator override def hasNext: Boolean = iter.hasNext || working.hasMorePages override def next: T = { if (!iter.hasNext && working.hasMorePages) { @@ -74,4 +70,4 @@ class AsyncResultSetIterator[T](rs:AsyncRS[T]) extends Iterator[T] { } iter.next } -} \ No newline at end of file +} From 272548b13cc8967135a3b011c74b1c54d6f2aa93 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 18 Dec 2019 17:15:46 -0600 Subject: [PATCH 28/62] Consolidating check API into something which exposes the various ResultSet impls only. Previously defined checks can now be implemented as transforms off of the ResultSet instance via fns defined somewhere. --- .../gatling/plugin/checks/CqlChecks.scala | 20 +--- .../plugin/checks/DseCheckSupport.scala | 29 +---- .../gatling/plugin/checks/GenericChecks.scala | 103 ------------------ .../gatling/plugin/checks/GraphChecks.scala | 54 +-------- .../plugin/model/DseCqlAttributes.scala | 7 +- .../model/DseCqlAttributesBuilder.scala | 5 +- .../plugin/model/DseGraphAttributes.scala | 4 +- .../model/DseGraphAttributesBuilder.scala | 8 +- .../plugin/model/DseGraphStatements.scala | 6 +- .../gatling/plugin/response/DseResponse.scala | 37 ++----- .../plugin/response/DseResponseHandler.scala | 39 +++---- 11 files changed, 37 insertions(+), 275 deletions(-) delete mode 100644 src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala index c1fde95..2729904 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/CqlChecks.scala @@ -6,9 +6,8 @@ package com.datastax.gatling.plugin.checks -import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, Row} +import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, Statement, StatementBuilder} import com.datastax.gatling.plugin.response.CqlResponse -import com.datastax.gatling.plugin.utils.ResultSetUtils import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check._ import io.gatling.core.check.extractor.{Extractor, SingleArity} @@ -16,7 +15,6 @@ import io.gatling.core.session.{Expression, ExpressionSuccessWrapper, Session} import scala.collection.mutable - /** * This class serves as model for the CQL-specific checks. * @@ -53,21 +51,9 @@ private class CqlResponseExtractor[X](val name: String, } object CqlChecks { - val resultSet = + val resultSet:CqlCheckBuilder[AsyncResultSet] = new CqlResponseExtractor[AsyncResultSet]( "resultSet", - r => r.getCqlResultSet) - .toCheckBuilder - - val allRows = - new CqlResponseExtractor[Iterator[Row]]( - "allRows", - r => ResultSetUtils.asyncResultSetToIterator(r.getCqlResultSet)) - .toCheckBuilder - - val oneRow = - new CqlResponseExtractor[Row]( - "oneRow", - r => ResultSetUtils.asyncResultSetToIterator(r.getCqlResultSet).next) + r => r.resultSet) .toCheckBuilder } diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala index cad2d8d..6f67438 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala @@ -6,36 +6,9 @@ package com.datastax.gatling.plugin.checks -import io.gatling.core.session.ExpressionSuccessWrapper - trait DseCheckSupport { - // execution info and subsets - lazy val executionInfo = GenericChecks.executionInfo - lazy val pagingState = GenericChecks.pagingState - lazy val schemaAgreement = GenericChecks.schemaInAgreement - lazy val successfulExecutionIndex = GenericChecks.successfulExecutionIndex - lazy val warnings = GenericChecks.warnings - lazy val coordinator = GenericChecks.coordinator - - // start CQL only checks lazy val resultSet = CqlChecks.resultSet - lazy val allRows = CqlChecks.allRows - lazy val oneRow = CqlChecks.oneRow - - // start Graph only checks - lazy val graphResultSet = GraphChecks.graphResultSet - lazy val allNodes = GraphChecks.allNodes - lazy val oneNode = GraphChecks.oneNode - - def edges(columnName: String) = GraphChecks.edges(columnName) - - def vertexes(columnName: String) = GraphChecks.vertexes(columnName) - - def paths(columnName: String) = GraphChecks.paths(columnName) - - def properties(columnName: String) = GraphChecks.paths(columnName) - - def vertexProperties(columnName: String) = GraphChecks.vertexProperties(columnName) + lazy val graphResultSet = GraphChecks.resultSet } diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala deleted file mode 100644 index e3e1c95..0000000 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GenericChecks.scala +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2018 Datastax Inc. - * - * This software can be used solely with DataStax products. Please consult the file LICENSE.md. - */ - -package com.datastax.gatling.plugin.checks - -import java.nio.ByteBuffer - -import com.datastax.gatling.plugin.response.DseResponse -import com.datastax.oss.driver.api.core.ConsistencyLevel -import com.datastax.oss.driver.api.core.cql._ -import com.datastax.oss.driver.api.core.metadata.Node -import io.gatling.commons.validation.{SuccessWrapper, Validation} -import io.gatling.core.check.extractor.{Extractor, SingleArity} -import io.gatling.core.check._ -import io.gatling.core.session.{Expression, ExpressionSuccessWrapper, Session} - -import scala.collection.mutable - -/** - * This class allows to execute checks on either CQL or Graph responses. - * - * There is no class hierarchy between DseResponseCheck and DseCqlCheck or - * DseGraphCheck on purpose. Otherwise any method that accept DseResponseCheck - * would make it possible to execute CQL checks on Graph responses, or - * vice-versa. - */ -case class GenericCheck(wrapped: Check[DseResponse]) extends Check[DseResponse] { - override def check(response: DseResponse, session: Session)(implicit cache: mutable.Map[Any, Any]): Validation[CheckResult] = { - wrapped.check(response, session) - } -} - -class GenericCheckBuilder[X](extractor: Expression[Extractor[DseResponse, X]]) - extends FindCheckBuilder[GenericCheck, DseResponse, DseResponse, X] { - - private val dseResponseExtender: Extender[GenericCheck, DseResponse] = - wrapped => GenericCheck(wrapped) - - def find: ValidatorCheckBuilder[GenericCheck, DseResponse, DseResponse, X] = { - ValidatorCheckBuilder(dseResponseExtender, x => x.success, extractor) - } -} - -private class GenericResponseExtractor[X](val name: String, - val extractor: DseResponse => X) - extends Extractor[DseResponse, X] with SingleArity { - - override def apply(response: DseResponse): Validation[Option[X]] = { - Some(extractor.apply(response)).success - } - - def toCheckBuilder: GenericCheckBuilder[X] = { - new GenericCheckBuilder[X](this.expressionSuccess) - } -} - -object GenericChecks { - val executionInfo = - new GenericResponseExtractor[ExecutionInfo]( - "executionInfo", - r => r.executionInfo()) - .toCheckBuilder - - val speculativeExecutionsExtractor = - new GenericResponseExtractor[Int]( - "speculativeExecutions", - r => r.speculativeExecutions()) - .toCheckBuilder - - val pagingState = - new GenericResponseExtractor[ByteBuffer]( - "pagingState", - r => r.pagingState()) - .toCheckBuilder - - val warnings = - new GenericResponseExtractor[List[String]]( - "warnings", - r => r.warnings()) - .toCheckBuilder - - val successfulExecutionIndex = - new GenericResponseExtractor[Int]( - "successfulExecutionIndex", - r => r.successFullExecutionIndex()) - .toCheckBuilder - - val schemaInAgreement = - new GenericResponseExtractor[Boolean]( - "schemaInAgreement", - r => r.schemaInAgreement()) - .toCheckBuilder - - val coordinator = - new GenericResponseExtractor[Node]( - "coordinator", - r => r.coordinator()) - .toCheckBuilder -} - diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala index 0a082f4..a04396c 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/GraphChecks.scala @@ -8,17 +8,13 @@ package com.datastax.gatling.plugin.checks import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.response.GraphResponse -import com.datastax.gatling.plugin.utils.{GraphResultSetUtils, ResultSetUtils} import io.gatling.commons.validation.{SuccessWrapper, Validation} import io.gatling.core.check.extractor.{Extractor, SingleArity} import io.gatling.core.check._ import io.gatling.core.session.{Expression, ExpressionSuccessWrapper, Session} -import org.apache.tinkerpop.gremlin.process.traversal.Path -import org.apache.tinkerpop.gremlin.structure.{Edge, Property, Vertex, VertexProperty} import scala.collection.mutable - /** * This class serves as model for the Graph-specific checks. * @@ -55,51 +51,9 @@ private class GraphResponseExtractor[X](val name: String, } object GraphChecks { - val graphResultSet = + val resultSet:GraphCheckBuilder[AsyncGraphResultSet] = new GraphResponseExtractor[AsyncGraphResultSet]( - "graphResultSet", - r => r.getGraphResultSet) - .toCheckBuilder - - val allNodes = - new GraphResponseExtractor[Iterator[GraphNode]]( - "allNodes", - r => ResultSetUtils.asyncGraphResultSetToIterator(r.getGraphResultSet)) - .toCheckBuilder - - val oneNode = - new GraphResponseExtractor[GraphNode]( - "oneNode", - r => ResultSetUtils.asyncGraphResultSetToIterator(r.getGraphResultSet).next) - .toCheckBuilder - - def edges(column: String):GraphCheckBuilder[Iterator[Edge]] = - new GraphResponseExtractor[Iterator[Edge]]( - "edges", - r => GraphResultSetUtils.edges(r.getGraphResultSet,column)) - .toCheckBuilder - - def vertexes(column: String):GraphCheckBuilder[Iterator[Vertex]] = - new GraphResponseExtractor[Iterator[Vertex]]( - "vertices", - r => GraphResultSetUtils.vertexes(r.getGraphResultSet, column)) - .toCheckBuilder - - def paths(column: String):GraphCheckBuilder[Iterator[Path]] = - new GraphResponseExtractor[Iterator[Path]]( - "paths", - r => GraphResultSetUtils.paths(r.getGraphResultSet, column)) - .toCheckBuilder - - def properties(column: String):GraphCheckBuilder[Iterator[Property[_]]] = - new GraphResponseExtractor[Iterator[Property[_]]]( - "properties", - r => GraphResultSetUtils.properties(r.getGraphResultSet, column)) - .toCheckBuilder - - def vertexProperties(column: String):GraphCheckBuilder[Iterator[VertexProperty[_]]] = - new GraphResponseExtractor[Iterator[VertexProperty[_]]]( - "vertexProperties", - r => GraphResultSetUtils.vertexProperties(r.getGraphResultSet, column)) - .toCheckBuilder + "graphResultSet", + r => r.resultSet) + .toCheckBuilder } \ No newline at end of file diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index 1176c8b..5f7383b 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -9,12 +9,11 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer import java.time.Duration +import com.datastax.gatling.plugin.checks.DseCqlCheck import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} -import com.datastax.gatling.plugin.response.{CqlResponse, DseResponse} import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.api.core.metadata.token.Token -import io.gatling.core.check.Check /** * CQL Query Attributes to be applied to the current query @@ -25,7 +24,6 @@ import io.gatling.core.check.Check * @param statement CQL Statement to be sent to Cluster * @param cl Consistency Level to be used * @param cqlChecks Data-level checks to be run after response is returned - * @param genericChecks Low-level checks to be run after response is returned * @param idempotent Set request to be idempotent i.e. whether it can be applied multiple times * @param node Set the node that should handle this query * @param customPayload Custom payload for this request @@ -43,8 +41,7 @@ import io.gatling.core.check.Check case class DseCqlAttributes[T <: Statement[T], B <: StatementBuilder[B,T]] (tag: String, statement: DseCqlStatement[T, B], - cqlChecks: List[Check[CqlResponse]] = List.empty, - genericChecks: List[Check[DseResponse]] = List.empty, + cqlChecks: List[DseCqlCheck] = List.empty, cqlStatements: Seq[String] = Seq.empty, /* General attributes */ cl: Option[ConsistencyLevel] = None, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 1e7a909..1f71011 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -11,7 +11,7 @@ import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} -import com.datastax.gatling.plugin.checks.{DseCqlCheck, GenericCheck} +import com.datastax.gatling.plugin.checks.DseCqlCheck import com.datastax.gatling.plugin.request.CqlRequestActionBuilder import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.api.core.metadata.token.Token @@ -158,7 +158,4 @@ case class DseCqlAttributesBuilder[T <: Statement[T], B <: StatementBuilder[B,T] def check(check: DseCqlCheck):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(cqlChecks = check :: attr.cqlChecks)) - - def check(check: GenericCheck):DseCqlAttributesBuilder[T, B] = - DseCqlAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index 86e831a..3000689 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -10,7 +10,7 @@ import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.dse.driver.api.core.graph.{GraphStatement, GraphStatementBuilderBase} -import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} +import com.datastax.gatling.plugin.checks.DseGraphCheck import com.datastax.oss.driver.api.core.metadata.Node /** @@ -22,7 +22,6 @@ import com.datastax.oss.driver.api.core.metadata.Node * @param statement Graph Statement to be sent to Cluster * @param cl Consistency Level to be used * @param graphChecks Data-level checks to be run after response is returned - * @param genericChecks Low-level checks to be run after response is returned * @param idempotent Set request to be idempotent i.e. whether it can be applied multiple times * @param node Set the node that should handle this query * @param graphName Name of the graph to use if different from the one used when connecting @@ -37,7 +36,6 @@ case class DseGraphAttributes[T <: GraphStatement[T], B <: GraphStatementBuilder (tag: String, statement: DseGraphStatement[T, B], graphChecks: List[DseGraphCheck] = List.empty, - genericChecks: List[GenericCheck] = List.empty, /* General attributes */ cl: Option[ConsistencyLevel] = None, idempotent: Option[Boolean] = None, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index 59d4b74..7264756 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -9,12 +9,10 @@ package com.datastax.gatling.plugin.model import java.time.Duration import com.datastax.oss.driver.api.core.ConsistencyLevel -import com.datastax.oss.driver.api.core.cql.Row -import com.datastax.dse.driver.api.core.graph.{GraphNode, GraphStatement, GraphStatementBuilderBase} -import com.datastax.gatling.plugin.checks.{DseGraphCheck, GenericCheck} +import com.datastax.dse.driver.api.core.graph.{GraphStatement, GraphStatementBuilderBase} +import com.datastax.gatling.plugin.checks.DseGraphCheck import com.datastax.gatling.plugin.request.GraphRequestActionBuilder import com.datastax.oss.driver.api.core.metadata.Node -import com.datastax.oss.driver.shaded.guava.common.base.Function /** * Request Builder for Graph Requests @@ -129,6 +127,4 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T], B <: GraphStatement def check(check: DseGraphCheck):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(graphChecks = check :: attr.graphChecks)) - def check(check: GenericCheck):DseGraphAttributesBuilder[T, B] = - DseGraphAttributesBuilder(attr.copy(genericChecks = check :: attr.genericChecks)) } diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index 31bc64a..19db3e5 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -104,10 +104,10 @@ case class GraphBoundStatement(builder: ScriptB, sessionKeys: Map[String, String def buildFromSession(gatlingSession: Session): Validation[ScriptB] = { Try { - sessionKeys foreach { - _ match { + sessionKeys foreach { k => + k match { case (k, v) => builder.setQueryParam(v, gatlingSession(k).as[Object]) - case _ => throw new RuntimeException(s"Observed ${_} instead of expected key-value pair") + case _ => throw new RuntimeException(s"Observed ${k} instead of expected key-value pair") } } builder diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala index 648a898..b3bcd21 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponse.scala @@ -6,40 +6,17 @@ package com.datastax.gatling.plugin.response -import java.nio.ByteBuffer - -import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} +import com.datastax.gatling.plugin.model.{ DseCqlAttributes, DseGraphAttributes } import com.datastax.oss.driver.api.core.cql._ import com.datastax.dse.driver.api.core.graph._ -import com.datastax.oss.driver.api.core.metadata.Node import com.typesafe.scalalogging.LazyLogging -import scala.collection.JavaConverters._ - -abstract class DseResponse { - def executionInfo(): ExecutionInfo - def coordinator(): Node = executionInfo.getCoordinator - def speculativeExecutions(): Int = executionInfo.getSpeculativeExecutionCount - def pagingState(): ByteBuffer = executionInfo.getPagingState - def warnings(): List[String] = executionInfo.getWarnings.asScala.toList - def successFullExecutionIndex(): Int = executionInfo.getSuccessfulExecutionIndex - def schemaInAgreement(): Boolean = executionInfo.isSchemaInAgreement -} - -class GraphResponse(graphResultSet: AsyncGraphResultSet, dseAttributes: DseGraphAttributes[_, _]) extends DseResponse with LazyLogging { - - override def executionInfo(): ExecutionInfo = graphResultSet.getExecutionInfo.asInstanceOf[ExecutionInfo] - - def getGraphResultSet: AsyncGraphResultSet = graphResultSet - - def getDseAttributes: DseGraphAttributes[_, _] = dseAttributes +class CqlResponse(cqlResultSet: AsyncResultSet, dseAttributes: DseCqlAttributes[_, _]) extends LazyLogging { + def attributes:DseCqlAttributes[_,_] = dseAttributes + def resultSet:AsyncResultSet = cqlResultSet } -class CqlResponse(cqlResultSet: AsyncResultSet, dseAttributes: DseCqlAttributes[_,_]) extends DseResponse with LazyLogging { - - override def executionInfo(): ExecutionInfo = cqlResultSet.getExecutionInfo - - def getCqlResultSet: AsyncResultSet = cqlResultSet - - def getDseAttributes: DseCqlAttributes[_,_] = dseAttributes +class GraphResponse(graphResultSet: AsyncGraphResultSet, dseAttributes: DseGraphAttributes[_,_]) extends LazyLogging { + def attributes:DseGraphAttributes[_,_] = dseAttributes + def resultSet:AsyncGraphResultSet = graphResultSet } diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 208ad09..69eedc9 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -11,7 +11,8 @@ import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem import com.datastax.oss.driver.api.core.cql._ -import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphResultSet, GraphStatement, GraphStatementBuilderBase} +import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, GraphStatement, GraphStatementBuilderBase} +import com.datastax.gatling.plugin.checks.{DseCqlCheck, DseGraphCheck} import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseGraphAttributes} import com.datastax.gatling.plugin.utils.{ResponseTime, ResponseTimeBuilder} @@ -25,8 +26,6 @@ import io.gatling.core.session.Session import io.gatling.core.stats.StatsEngine import io.gatling.core.stats.message.ResponseTimings -import scala.util.Try - object DseResponseHandler { def sanitize(s: String): String = s.replaceAll("""(\r|\n)""", " ") @@ -41,7 +40,7 @@ trait DseResponseCallback[RS] { def onSuccess(result: RS): Unit } -abstract class DseResponseHandler[S, RS, R <: DseResponse] extends StrictLogging with DseResponseCallback[RS] { +abstract class DseResponseHandler[S, RS, R] extends StrictLogging with DseResponseCallback[RS] { protected def responseTimeBuilder: ResponseTimeBuilder protected def system: ActorSystem protected def statsEngine: StatsEngine @@ -52,7 +51,6 @@ abstract class DseResponseHandler[S, RS, R <: DseResponse] extends StrictLogging protected def tag: String protected def queries: Seq[String] protected def specificChecks: List[Check[R]] - protected def genericChecks: List[Check[DseResponse]] protected def newResponse(rs: RS): R protected def coordinator(rs: RS): Node @@ -116,24 +114,15 @@ abstract class DseResponseHandler[S, RS, R <: DseResponse] extends StrictLogging val responseTime = responseTimeBuilder.build() val response = newResponse(result) - val genericResult: (Session => Session, Option[Failure]) = Check.check(response, session, genericChecks) - val genericChecksPassed = genericResult._2.isEmpty - val sessionAfterGenericChecks = genericResult._1(session) - if (genericChecksPassed) { - val specificResult: (Session => Session, Option[Failure]) = Check.check(response, sessionAfterGenericChecks, specificChecks) - val sessionAfterSpecificChecks = genericResult._1(session) - val specificChecksPassed = specificResult._2.isEmpty - if (specificChecksPassed) { - writeSuccess(responseTime) - next ! sessionAfterSpecificChecks.markAsSucceeded - } else { - writeCheckFailure(specificResult, result, responseTime) - next ! sessionAfterSpecificChecks.markAsFailed - } + val specificResult: (Session => Session, Option[Failure]) = Check.check(response, session, specificChecks) + val sessionAfterSpecificChecks = specificResult._1(session) + val specificChecksPassed = specificResult._2.isEmpty + if (specificChecksPassed) { + writeSuccess(responseTime) + next ! sessionAfterSpecificChecks.markAsSucceeded } else { - // Do not run specific checks as the response is already error'ed - writeCheckFailure(genericResult, result, responseTime) - next ! sessionAfterGenericChecks.markAsFailed + writeCheckFailure(specificResult, result, responseTime) + next ! sessionAfterSpecificChecks.markAsFailed } } } @@ -149,8 +138,7 @@ class GraphResponseHandler[T <: GraphStatement[T], B <: GraphStatementBuilderBas extends DseResponseHandler[T, AsyncGraphResultSet, GraphResponse] { override protected def tag: String = dseAttributes.tag override protected def queries: Seq[String] = Seq.empty - override protected def specificChecks: List[Check[GraphResponse]] = dseAttributes.graphChecks - override protected def genericChecks: List[Check[DseResponse]] = dseAttributes.genericChecks + override protected def specificChecks: List[DseGraphCheck] = dseAttributes.graphChecks override protected def newResponse(rs: AsyncGraphResultSet): GraphResponse = new GraphResponse(rs, dseAttributes) override protected def coordinator(rs: AsyncGraphResultSet): Node = rs.getExecutionInfo.getCoordinator } @@ -166,8 +154,7 @@ class CqlResponseHandler[T <: Statement[T], B <: StatementBuilder[B,T]](val next extends DseResponseHandler[T, AsyncResultSet, CqlResponse] { override protected def tag: String = dseAttributes.tag override protected def queries: Seq[String] = Seq.empty - override protected def specificChecks: List[Check[CqlResponse]] = dseAttributes.cqlChecks - override protected def genericChecks: List[Check[DseResponse]] = dseAttributes.genericChecks + override protected def specificChecks: List[DseCqlCheck] = dseAttributes.cqlChecks override protected def newResponse(rs: AsyncResultSet): CqlResponse = new CqlResponse(rs, dseAttributes) override protected def coordinator(rs: AsyncResultSet): Node = rs.getExecutionInfo.getCoordinator } From b8ff9ea770ae46ce4ae5a3f8e04ec2be6650cabd Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 18 Dec 2019 19:29:16 -0600 Subject: [PATCH 29/62] More change from code review --- .../gatling/plugin/model/DseCqlStatements.scala | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 581bd70..4b670fe 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -138,16 +138,13 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, sessionKeys: Seq[String]): BoundS = { val params = cqlTypes.getParamsList(preparedStatement) val completedBuilder = - sessionKeys.foldLeft((0,new BoundB(template))) { - (acc, gatlingSessionKey) => - acc match { - case (cnt, builder) => - (cnt + 1, cqlTypes.bindParamByOrder(gatlingSession, builder, params(cnt), gatlingSessionKey, cnt)) + sessionKeys.zip(Iterable.range(0,sessionKeys.size)).foldLeft(new BoundB(template)) { + (builder, kv) => + kv match { + case (sessionKey, cnt) => cqlTypes.bindParamByOrder(gatlingSession, builder, params(cnt), sessionKey, cnt) } - } - completedBuilder match { - case (_, builder) => builder.build() - } + } + completedBuilder.build() } } @@ -178,7 +175,6 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme val queryParams: Map[String, Int] = cqlTypes.getParamsMap(statement) val completedBuilder = queryParams.foldLeft(new BoundB(statement.bind())) { - (builder, kv) => kv match { case (gatlingSessionKey, valType) => From 02fe912c6d2d27494f1a7da5f58bf55362898956 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 19 Dec 2019 14:06:04 -0600 Subject: [PATCH 30/62] Upgrading to new cassandra-unit which includes 4.2.x driver support) --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 0567d2e..00030c4 100644 --- a/build.sbt +++ b/build.sbt @@ -14,7 +14,7 @@ libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highchar libraryDependencies += "org.fusesource" % "sigar" % "1.6.4" % Test libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % Test libraryDependencies += "org.easymock" % "easymock" % "3.5" % Test -libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "3.3.0.2" % Test +libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "4.2.2.0-SNAPSHOT" % Test libraryDependencies += "org.pegdown" % "pegdown" % "1.6.0" % Test libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.5.11" % Test From bfcb1715240cb1689c3580beca24472882213388 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 19 Dec 2019 14:06:24 -0600 Subject: [PATCH 31/62] Fixing a few tests --- .../model/CqlStatementBuildersSpec.scala | 74 ++++++++------- .../plugin/request/CqlRequestActionSpec.scala | 93 ++++++++++--------- 2 files changed, 90 insertions(+), 77 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala index de40a8f..85da143 100644 --- a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala @@ -1,11 +1,14 @@ package com.datastax.gatling.plugin.model -import com.datastax.driver.core.ConsistencyLevel.{EACH_QUORUM, THREE} -import com.datastax.driver.core._ -import com.datastax.driver.core.policies.FallthroughRetryPolicy +import java.nio.ByteBuffer +import java.time.Duration + import com.datastax.gatling.plugin.DsePredef._ -import com.datastax.gatling.plugin.checks.{CqlChecks, DseCqlCheck, GenericCheck, GenericChecks} -import io.gatling.core.Predef._ +import com.datastax.gatling.plugin.checks.CqlChecks +import com.datastax.oss.driver.api.core.ConsistencyLevel.{EACH_QUORUM, THREE} +import com.datastax.oss.driver.api.core.cql.{SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} +import com.datastax.oss.driver.api.core.metadata.Node +import com.datastax.oss.driver.api.core.metadata.token.Token import io.gatling.core.session.{ExpressionSuccessWrapper, Session} import org.scalatest.easymock.EasyMockSugar import org.scalatest.{FlatSpec, Matchers} @@ -15,63 +18,70 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar it should "build statements from a CQL String" in { - val statementAttributes: DseCqlAttributes = cql("the-tag") + val statementAttributes: DseCqlAttributes[SimpleS,SimpleB] = cql("the-tag") .executeCql("SELECT foo FROM bar.baz LIMIT 1") .build() .dseAttributes - val statement: SimpleStatement = statementAttributes.statement + val statement = statementAttributes.statement .buildFromSession(Session("the-tag", 42)) - .get.asInstanceOf[SimpleStatement] + .get.build statementAttributes.cqlStatements should contain only "SELECT foo FROM bar.baz LIMIT 1" - statement.getQueryString() should be("SELECT foo FROM bar.baz LIMIT 1") + statement.getQuery should be("SELECT foo FROM bar.baz LIMIT 1") } it should "forward all attributs to DseCqlAttributes" in { - val pagingState = mock[PagingState] - val genericCheck = GenericCheck(GenericChecks.exhausted.is(true)) - val cqlCheck = DseCqlCheck(CqlChecks.oneRow.is(mock[Row].expressionSuccess)) - val statementAttributes: DseCqlAttributes = cql("the-session-tag") + val node = mock[Node] + val pagingState = mock[ByteBuffer] + val queryTimestamp = 123L + val routingKey = mock[ByteBuffer] + val routingKeyspace = "some_keyspace" + val routingToken = mock[Token] + val timeout = mock[Duration] + val cqlCheck = CqlChecks.resultSet.find.is(mock[AsyncResultSet].expressionSuccess).build + val statementAttributes: DseCqlAttributes[_,_] = cql("the-session-tag") .executeCql("FOO") .withConsistencyLevel(EACH_QUORUM) - .withUserOrRole("User or role") - .withDefaultTimestamp(-76) .withIdempotency() - .withReadTimeout(99) - .withSerialConsistencyLevel(THREE) - .withRetryPolicy(FallthroughRetryPolicy.INSTANCE) - .withFetchSize(3) + .withNode(node) .withTracingEnabled() + .withPageSize(3) .withPagingState(pagingState) - .check(genericCheck) + .withQueryTimestamp(queryTimestamp) + .withRoutingKey(routingKey) + .withRoutingKeyspace(routingKeyspace) + .withRoutingToken(routingToken) + .withSerialConsistencyLevel(THREE) + .withTimeout(timeout) .check(cqlCheck) .build() .dseAttributes statementAttributes.tag should be("the-session-tag") statementAttributes.cl should be(Some(EACH_QUORUM)) statementAttributes.cqlChecks should contain only cqlCheck - statementAttributes.genericChecks should contain only genericCheck - statementAttributes.userOrRole should be(Some("User or role")) - statementAttributes.readTimeout should be(Some(99)) statementAttributes.idempotent should be(Some(true)) - statementAttributes.defaultTimestamp should be(Some(-76)) + statementAttributes.node should be(Some(node)) statementAttributes.enableTrace should be(Some(true)) - statementAttributes.serialCl should be(Some(THREE)) - statementAttributes.fetchSize should be(Some(3)) - statementAttributes.retryPolicy should be(Some(FallthroughRetryPolicy.INSTANCE)) + statementAttributes.pageSize should be(Some(3)) statementAttributes.pagingState should be(Some(pagingState)) + statementAttributes.queryTimestamp should be(queryTimestamp) + statementAttributes.routingKey should be(routingKey) + statementAttributes.routingKeyspace should be(routingKeyspace) + statementAttributes.routingToken should be(routingToken) + statementAttributes.serialCl should be(Some(THREE)) + statementAttributes.timeout should be(timeout) statementAttributes.cqlStatements should contain only "FOO" } it should "build statements from a SimpleStatement" in { - val statementAttributes: DseCqlAttributes = cql("the-tag") - .executeStatement(new SimpleStatement("Some CQL")) + val statementAttributes: DseCqlAttributes[SimpleS,SimpleB] = cql("the-tag") + .executeStatement(SimpleS.newInstance("Some CQL")) .build() .dseAttributes - val statement: SimpleStatement = statementAttributes.statement + val statement = statementAttributes.statement .buildFromSession(Session("the-tag", 42)) - .get.asInstanceOf[SimpleStatement] + .get.build statementAttributes.cqlStatements should contain only "Some CQL" - statement.getQueryString() should be("Some CQL") + statement.getQuery should be("Some CQL") } // it should "build statements from a PreparedStatement" in { diff --git a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala index 553e778..2fe04da 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala @@ -1,21 +1,24 @@ package com.datastax.gatling.plugin.request -import java.util.concurrent.{Executor, TimeUnit} +import java.nio.ByteBuffer +import java.time.Duration +import java.util.concurrent.{CompletableFuture, CompletionStage, Executor, TimeUnit} import akka.actor.{ActorSystem, Props} import akka.testkit.TestKitBase import ch.qos.logback.classic.{Level, Logger} import ch.qos.logback.classic.spi.ILoggingEvent import ch.qos.logback.core.read.ListAppender -import com.datastax.driver.core._ -import com.datastax.driver.core.policies.FallthroughRetryPolicy -import com.datastax.driver.dse.DseSession +import com.datastax.dse.driver.api.core.DseSession import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.metrics.NoopMetricsLogger import com.datastax.gatling.plugin.utils.GatlingTimingSource import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseCqlStatement} -import com.google.common.util.concurrent.{Futures, ListenableFuture} +import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.cql.{SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} +import com.datastax.oss.driver.api.core.metadata.Node +import com.datastax.oss.driver.api.core.metadata.token.Token import io.gatling.commons.validation.SuccessWrapper import io.gatling.core.action.Exit import io.gatling.core.config.GatlingConfiguration @@ -29,12 +32,19 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { implicit lazy val system:ActorSystem = ActorSystem() val gatlingTestConfig: GatlingConfiguration = GatlingConfiguration.loadForTest() val dseSession: DseSession = mock[DseSession] - val dseCqlStatement: DseCqlStatement = mock[DseCqlStatement] - val pagingState: PagingState = mock[PagingState] + val dseCqlStatement: DseCqlStatement[SimpleS,SimpleB] = mock[DseCqlStatement[SimpleS,SimpleB]] + val node:Node = mock[Node] + val pageSize = 3 + val pagingState: ByteBuffer = mock[ByteBuffer] + val queryTimestamp = 123L + val routingKey:ByteBuffer = mock[ByteBuffer] + val routingKeyspace = "some_keyspace" + val routingToken:Token = mock[Token] + val timeout:Duration = mock[Duration] val statsEngine: StatsEngine = mock[StatsEngine] val gatlingSession = Session("scenario", 1) - def getTarget(dseAttributes: DseCqlAttributes): CqlRequestAction = { + def getTarget(dseAttributes: DseCqlAttributes[SimpleS,SimpleB]): CqlRequestAction[SimpleS,SimpleB = { new CqlRequestAction( "sample-dse-request", new Exit(system.actorOf(Props[DseRequestActor]), statsEngine), @@ -47,17 +57,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { GatlingTimingSource()) } - private def mockResultSetFuture(): ResultSetFuture = new ResultSetFuture { - val delegate: ListenableFuture[ResultSet] = Futures.immediateFuture(mock[ResultSet]) - override def cancel(b: Boolean): Boolean = false - override def getUninterruptibly: ResultSet = delegate.get() - override def getUninterruptibly(duration: Long, timeUnit: TimeUnit): ResultSet = delegate.get(duration, timeUnit) - override def addListener(listener: Runnable, executor: Executor): Unit = delegate.addListener(listener, executor) - override def isCancelled: Boolean = delegate.isCancelled - override def isDone: Boolean = delegate.isDone - override def get(): ResultSet = delegate.get() - override def get(timeout: Long, unit: TimeUnit): ResultSet = delegate.get(timeout, unit) - } + private def mockAsyncResultSetFuture(): CompletionStage[AsyncResultSet] = CompletableFuture.completedFuture(mock[AsyncResultSet]) before { reset(dseCqlStatement, dseSession, pagingState, statsEngine) @@ -68,16 +68,16 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { } describe("CQL") { - val statementCapture = EasyMock.newCapture[RegularStatement] + val statementCapture = EasyMock.newCapture[SimpleS] it("should have default CQL attributes set if nothing passed") { val cqlAttributesWithDefaults = DseCqlAttributes( "test", dseCqlStatement) expecting { - dseCqlStatement.buildFromSession(gatlingSession).andReturn(new SimpleStatement("select * from test") + dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleS.builder("select * from test") .success) - dseSession.executeAsync(capture(statementCapture)) andReturn mockResultSetFuture() + dseSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() } whenExecuting(dseCqlStatement, dseSession) { @@ -85,36 +85,36 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { } val capturedStatement = statementCapture.getValue - capturedStatement shouldBe a[SimpleStatement] + capturedStatement shouldBe a[SimpleS] capturedStatement.getConsistencyLevel shouldBe null capturedStatement.getSerialConsistencyLevel shouldBe null - capturedStatement.getFetchSize shouldBe 0 - capturedStatement.getDefaultTimestamp shouldBe -9223372036854775808L - capturedStatement.getReadTimeoutMillis shouldBe -2147483648 - capturedStatement.getRetryPolicy shouldBe null + capturedStatement.getPageSize shouldBe 0 capturedStatement.isIdempotent shouldBe null capturedStatement.isTracing shouldBe false - capturedStatement.getQueryString should be("select * from test") + capturedStatement.getQuery should be("select * from test") } it("should enable all the CQL Attributes in DseAttributes") { - val cqlAttributes = DseCqlAttributes( + val cqlAttributes = new DseCqlAttributes[SimpleS,SimpleB]( "test", dseCqlStatement, cl = Some(ConsistencyLevel.ANY), - userOrRole = Some("test_user"), - readTimeout = Some(12), - defaultTimestamp = Some(1498167845000L), idempotent = Some(true), - fetchSize = Some(50), + node = Some(node), + enableTrace = Some(true), + pagingState = Some(pagingState), + pageSize = Some(pageSize), + queryTimestamp = Some(queryTimestamp), + routingKey = Some(routingKey), + routingKeyspace = Some(routingKeyspace), + routingToken = Some(routingToken), serialCl = Some(ConsistencyLevel.LOCAL_SERIAL), - retryPolicy = Some(FallthroughRetryPolicy.INSTANCE), - enableTrace = Some(true)) + timeout = Some(timeout)) expecting { - dseCqlStatement.buildFromSession(gatlingSession).andReturn(new SimpleStatement("select * from test") + dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleS.builder("select * from test") .success) - dseSession.executeAsync(capture(statementCapture)) andReturn mockResultSetFuture() + dseSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() } whenExecuting(dseCqlStatement, dseSession) { @@ -122,16 +122,19 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { } val capturedStatement = statementCapture.getValue - capturedStatement shouldBe a[SimpleStatement] + capturedStatement shouldBe a[SimpleS] capturedStatement.getConsistencyLevel shouldBe ConsistencyLevel.ANY - capturedStatement.getDefaultTimestamp shouldBe 1498167845000L - capturedStatement.getReadTimeoutMillis shouldBe 12 capturedStatement.isIdempotent shouldBe true - capturedStatement.getFetchSize shouldBe 50 - capturedStatement.getSerialConsistencyLevel shouldBe ConsistencyLevel.LOCAL_SERIAL - capturedStatement.getRetryPolicy shouldBe FallthroughRetryPolicy.INSTANCE - capturedStatement.getQueryString should be("select * from test") + capturedStatement.getNode shouldBe node capturedStatement.isTracing shouldBe true + capturedStatement.getPageSize shouldBe pageSize + capturedStatement.getPagingState shouldBe pagingState + capturedStatement.getQueryTimestamp shouldBe queryTimestamp + capturedStatement.getRoutingKey shouldBe routingKey + capturedStatement.getRoutingKeyspace shouldBe routingKeyspace + capturedStatement.getRoutingToken shouldBe routingToken + capturedStatement.getSerialConsistencyLevel shouldBe ConsistencyLevel.LOCAL_SERIAL + capturedStatement.getTimeout shouldBe timeout } it("should log exceptions encountered") { @@ -147,7 +150,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { val cqlRequestAction = getTarget(cqlAttributesWithDefaults) - val classLogger = LoggerFactory.getLogger(classOf[CqlRequestAction]).asInstanceOf[Logger] + val classLogger = LoggerFactory.getLogger(classOf[CqlRequestAction[SimpleS,SimpleB]]).asInstanceOf[Logger] val listAppender: ListAppender[ILoggingEvent] = new ListAppender[ILoggingEvent] listAppender.start() classLogger.addAppender(listAppender) From 2f5c474869c4c6e59ce7bfdd40638b6743c9eda4 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 6 Jan 2020 12:12:04 -0600 Subject: [PATCH 32/62] Specs should at least compile now --- .../plugin/request/CqlRequestActionSpec.scala | 2 +- .../request/GraphRequestActionSpec.scala | 93 ++--- .../utils/CqlPreparedStatementUtilSpec.scala | 350 +++++++++--------- 3 files changed, 199 insertions(+), 246 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala index 2fe04da..d75daf6 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala @@ -44,7 +44,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { val statsEngine: StatsEngine = mock[StatsEngine] val gatlingSession = Session("scenario", 1) - def getTarget(dseAttributes: DseCqlAttributes[SimpleS,SimpleB]): CqlRequestAction[SimpleS,SimpleB = { + def getTarget(dseAttributes: DseCqlAttributes[SimpleS,SimpleB]): CqlRequestAction[SimpleS,SimpleB] = { new CqlRequestAction( "sample-dse-request", new Exit(system.actorOf(Props[DseRequestActor]), statsEngine), diff --git a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala index 2c61336..cd0fc09 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala @@ -1,18 +1,20 @@ package com.datastax.gatling.plugin.request -import java.util.concurrent.{Executor, TimeUnit} +import java.nio.ByteBuffer +import java.time.Duration +import java.util.concurrent.{CompletableFuture, CompletionStage} import akka.actor.{ActorSystem, Props} import akka.testkit.TestKitBase -import com.datastax.driver.core._ -import com.datastax.driver.dse.DseSession -import com.datastax.driver.dse.graph.{GraphResultSet, RegularGraphStatement, SimpleGraphStatement} +import com.datastax.dse.driver.api.core.DseSession +import com.datastax.dse.driver.api.core.graph.{ScriptGraphStatement => ScriptS, ScriptGraphStatementBuilder => ScriptB, _} import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.metrics.NoopMetricsLogger import com.datastax.gatling.plugin.utils.GatlingTimingSource import com.datastax.gatling.plugin.DseProtocol -import com.datastax.gatling.plugin.model.{DseGraphStatement, DseGraphAttributes} -import com.google.common.util.concurrent.{Futures, ListenableFuture} +import com.datastax.gatling.plugin.model.{DseGraphAttributes, DseGraphStatement} +import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.metadata.Node import io.gatling.commons.validation.SuccessWrapper import io.gatling.core.action.Exit import io.gatling.core.config.GatlingConfiguration @@ -25,12 +27,16 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { implicit lazy val system = ActorSystem() val gatlingTestConfig = GatlingConfiguration.loadForTest() val dseSession = mock[DseSession] - val dseGraphStatement = mock[DseGraphStatement] - val pagingState = mock[PagingState] + val dseGraphStatement = mock[DseGraphStatement[ScriptS,ScriptB]] + val node:Node = mock[Node] + val subProtocol = "graph-binary-3.0" + val timeout:Duration = mock[Duration] + val timestamp = 123L + val pagingState:ByteBuffer = mock[ByteBuffer] val statsEngine: StatsEngine = mock[StatsEngine] val gatlingSession = Session("scenario", 1) - def getTarget(dseAttributes: DseGraphAttributes): GraphRequestAction = { + def getTarget(dseAttributes: DseGraphAttributes[ScriptS,ScriptB]): GraphRequestAction[ScriptS,ScriptB] = { new GraphRequestAction( "sample-dse-request", new Exit(system.actorOf(Props[DseRequestActor]), statsEngine), @@ -43,17 +49,8 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { GatlingTimingSource()) } - private def mockResultSetFuture(): ResultSetFuture = new ResultSetFuture { - val delegate: ListenableFuture[ResultSet] = Futures.immediateFuture(mock[ResultSet]) - override def cancel(b: Boolean): Boolean = false - override def getUninterruptibly: ResultSet = delegate.get() - override def getUninterruptibly(duration: Long, timeUnit: TimeUnit): ResultSet = delegate.get(duration, timeUnit) - override def addListener(listener: Runnable, executor: Executor): Unit = delegate.addListener(listener, executor) - override def isCancelled: Boolean = delegate.isCancelled - override def isDone: Boolean = delegate.isDone - override def get(): ResultSet = delegate.get() - override def get(timeout: Long, unit: TimeUnit): ResultSet = delegate.get(timeout, unit) - } + private def mockAsyncGraphResultSetFuture(): CompletionStage[AsyncGraphResultSet] = + CompletableFuture.completedFuture(mock[AsyncGraphResultSet]) before { reset(dseGraphStatement, dseSession, pagingState, statsEngine) @@ -64,26 +61,24 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { } describe("Graph") { - val statementCapture = EasyMock.newCapture[RegularGraphStatement] + val statementCapture = EasyMock.newCapture[ScriptS] it("should enable all the Graph Attributes in DseAttributes") { - val graphAttributes = DseGraphAttributes("test", dseGraphStatement, + val graphAttributes = new DseGraphAttributes("test", dseGraphStatement, cl = Some(ConsistencyLevel.ANY), - userOrRole = Some("test_user"), - readTimeout = Some(12), - defaultTimestamp = Some(1498167845000L), idempotent = Some(true), - readCL = Some(ConsistencyLevel.LOCAL_QUORUM), - writeCL = Some(ConsistencyLevel.LOCAL_QUORUM), + node = Some(node), graphName = Some("MyGraph"), - graphLanguage = Some("english"), - graphSource = Some("mysource"), - graphInternalOptions = Some(Seq(("get", "this"))), - graphTransformResults = None + readCL = Some(ConsistencyLevel.LOCAL_QUORUM), + subProtocol = Some(subProtocol), + timeout = Some(timeout), + timestamp = Some(timestamp), + traversalSource = Some("g.V()"), + writeCL = Some(ConsistencyLevel.LOCAL_QUORUM) ) expecting { - dseGraphStatement.buildFromSession(gatlingSession).andReturn(new SimpleGraphStatement("g.V()").success) - dseSession.executeGraphAsync(capture(statementCapture)) andReturn Futures.immediateFuture(mock[GraphResultSet]) + dseGraphStatement.buildFromSession(gatlingSession) andReturn(ScriptS.builder("g.V()").success) + dseSession.executeAsync(capture(statementCapture)) andReturn mockAsyncGraphResultSetFuture() } whenExecuting(dseGraphStatement, dseSession) { @@ -91,41 +86,11 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { } val capturedStatement = statementCapture.getValue - capturedStatement shouldBe a[SimpleGraphStatement] + capturedStatement shouldBe a[ScriptS] capturedStatement.getConsistencyLevel shouldBe ConsistencyLevel.ANY - capturedStatement.getDefaultTimestamp shouldBe 1498167845000L - capturedStatement.getReadTimeoutMillis shouldBe 12 capturedStatement.isIdempotent shouldBe true capturedStatement.getGraphName shouldBe "MyGraph" - capturedStatement.getGraphLanguage shouldBe "english" - capturedStatement.getGraphReadConsistencyLevel shouldBe ConsistencyLevel.LOCAL_QUORUM - capturedStatement.getGraphWriteConsistencyLevel shouldBe ConsistencyLevel.LOCAL_QUORUM - capturedStatement.getGraphSource shouldBe "mysource" capturedStatement.isSystemQuery shouldBe false - capturedStatement.getGraphInternalOption("get") shouldBe "this" - } - - it("should override the graph name if system") { - val graphAttributes = DseGraphAttributes( - "test", - dseGraphStatement, - graphName = Some("MyGraph"), - isSystemQuery = Some(true), - ) - - expecting { - dseGraphStatement.buildFromSession(gatlingSession).andReturn(new SimpleGraphStatement("g.V()").success) - dseSession.executeGraphAsync(capture(statementCapture)) andReturn Futures.immediateFuture(mock[GraphResultSet]) - } - - whenExecuting(dseGraphStatement, dseSession) { - getTarget(graphAttributes).sendQuery(gatlingSession) - } - - val capturedStatement = statementCapture.getValue - capturedStatement shouldBe a[SimpleGraphStatement] - capturedStatement.getGraphName shouldBe null - capturedStatement.isSystemQuery shouldBe true } } } diff --git a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala index d373c2c..ff5268b 100644 --- a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala @@ -3,12 +3,16 @@ package com.datastax.gatling.plugin.utils import java.math.BigInteger import java.net.InetAddress import java.nio.ByteBuffer +import java.time.{Instant, LocalDate} +import java.util.Optional -import com.datastax.driver.core.utils.UUIDs -import com.datastax.driver.core.{DataType, _} -import com.datastax.driver.dse.geometry._ +import com.datastax.dse.driver.api.core.data.geometry._ import com.datastax.gatling.plugin.base.BaseCassandraServerSpec import com.datastax.gatling.plugin.exceptions.CqlTypeException +import com.datastax.oss.driver.api.core.`type`.{DataTypes, UserDefinedType} +import com.datastax.oss.driver.api.core.cql.BoundStatement +import com.datastax.oss.driver.api.core.data.{TupleValue, UdtValue} +import com.datastax.oss.driver.api.core.uuid.Uuids import com.github.nscala_time.time.Imports.DateTime import io.gatling.core.session.Session @@ -44,7 +48,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { "inetStr" -> "127.0.0.1", "inet" -> InetAddress.getByName("127.0.0.1"), - "localDate" -> LocalDate.fromMillisSinceEpoch(1483299340813L), + "localDate" -> LocalDate.from(Instant.ofEpochMilli(1483299340813L)), "stringDate" -> "2016-10-05", "set" -> Set(1), @@ -68,12 +72,13 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { "javaNumber" -> 12.asInstanceOf[Number], "javaDate" -> new java.util.Date(), + "javaInstant" -> Instant.now(), "isoDateString" -> "2008-03-01T13:00:00Z", "dateString" -> "2016-10-05", - "uuid" -> UUIDs.random(), + "uuid" -> Uuids.random(), "uuidString" -> "252a3806-b8be-42d3-929d-4cbb380a433e", - "timeUuid" -> UUIDs.timeBased(), + "timeUuid" -> Uuids.timeBased(), "byte" -> 12.toByte, "short" -> 12.toShort, @@ -88,9 +93,9 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { "null_type" -> null, - "point_type" -> new Point(1.0, 1.0), - "linestring_type" -> new LineString(new Point(1.0, 1.0), new Point(2.0, 2.0)), - "polygon_type" -> new Polygon(new Point(1.0, 1.0), new Point(2.0, 2.0), new Point(3.0, 3.0), new Point(4.0, 4.0)) + "point_type" -> Point.fromCoordinates(1.0, 1.0), + "linestring_type" -> LineString.fromPoints(Point.fromCoordinates(1.0, 1.0), Point.fromCoordinates(2.0, 2.0)), + "polygon_type" -> Polygon.fromPoints(Point.fromCoordinates(1.0, 1.0), Point.fromCoordinates(2.0, 2.0), Point.fromCoordinates(3.0, 3.0), Point.fromCoordinates(4.0, 4.0)) ) val defaultGatlingSession: Session = gatlingSession.setAll(defaultSessionVars) @@ -108,7 +113,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = ?") val paramList = CqlPreparedStatementUtil.getParamsList(preparedStatement) - paramList should contain(DataType.Name.INT) + paramList should contain(DataTypes.INT) } } @@ -120,7 +125,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = :id") val paramsMap = CqlPreparedStatementUtil.getParamsMap(preparedStatement) - paramsMap("id") shouldBe DataType.Name.INT + paramsMap("id") shouldBe DataTypes.INT } } @@ -387,28 +392,28 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { describe("asDate") { it("should accept a date string") { - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "stringDate") shouldBe a[LocalDate] - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "stringDate").getDay.equals(5) + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "stringDate") shouldBe a[LocalDate] + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "stringDate").getDayOfMonth.equals(5) } it("should accept a long") { - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "long") shouldBe a[LocalDate] - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "long").getDay.equals(1) + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "long") shouldBe a[LocalDate] + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "long").getDayOfMonth.equals(1) } it("should accept an int") { - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "int") shouldBe a[LocalDate] - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "int").getDay.equals(13) + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "int") shouldBe a[LocalDate] + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "int").getDayOfMonth.equals(13) } it("should accept an native localDate") { - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "localDate") shouldBe a[LocalDate] - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "localDate").getDay.equals(1) + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "localDate") shouldBe a[LocalDate] + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "localDate").getDayOfMonth.equals(1) } it("should not accept a float and produce a CqlTypeException") { intercept[CqlTypeException] { - CqlPreparedStatementUtil.asDate(defaultGatlingSession, "float") shouldBe a[LocalDate] + CqlPreparedStatementUtil.asLocalDate(defaultGatlingSession, "float") shouldBe a[LocalDate] } } @@ -418,83 +423,78 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { describe("asSet") { it("should accept a scala set") { - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "set") shouldBe a[java.util.Set[_]] - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "set") shouldBe + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "set", classOf[Int]) shouldBe a[java.util.Set[_]] + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "set", classOf[Int]) shouldBe defaultSessionVars("set").asInstanceOf[Set[Int]].asJava } it("should accept a java set") { - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "setJava") shouldBe a[java.util.Set[_]] - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "setJava") shouldBe + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "setJava", classOf[Int]) shouldBe a[java.util.Set[_]] + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "setJava", classOf[Int]) shouldBe defaultSessionVars("set").asInstanceOf[Set[Int]].asJava } it("should accept a scala seq of ints") { - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seq") shouldBe a[java.util.Set[_]] - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seq") shouldBe + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seq", classOf[Int]) shouldBe a[java.util.Set[_]] + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seq", classOf[Int]) shouldBe defaultSessionVars("set").asInstanceOf[Set[Int]].asJava } it("should accept a scala seq of strings") { - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seqString") shouldBe a[java.util.Set[_]] - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seqString") shouldBe + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seqString", classOf[String]) shouldBe a[java.util.Set[_]] + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "seqString", classOf[String]) shouldBe defaultSessionVars("setString").asInstanceOf[Set[String]].asJava } it("should not accept a float and produce a CqlTypeException") { intercept[CqlTypeException] { - CqlPreparedStatementUtil.asSet(defaultGatlingSession, "float") shouldBe a[java.util.Set[_]] + CqlPreparedStatementUtil.asSet(defaultGatlingSession, "float", classOf[Float]) shouldBe a[java.util.Set[_]] } } - } - describe("asList") { it("should accept a scala set") { - CqlPreparedStatementUtil.asList(defaultGatlingSession, "list") shouldBe a[java.util.List[_]] - CqlPreparedStatementUtil.asList(defaultGatlingSession, "list") shouldBe + CqlPreparedStatementUtil.asList(defaultGatlingSession, "list", classOf[Int]) shouldBe a[java.util.List[_]] + CqlPreparedStatementUtil.asList(defaultGatlingSession, "list", classOf[Int]) shouldBe defaultSessionVars("list").asInstanceOf[List[Int]].asJava } it("should accept a java set") { - CqlPreparedStatementUtil.asList(defaultGatlingSession, "listJava") shouldBe a[java.util.List[_]] + CqlPreparedStatementUtil.asList(defaultGatlingSession, "listJava", classOf[Int]) shouldBe a[java.util.List[_]] } it("should accept a scala seq") { - CqlPreparedStatementUtil.asList(defaultGatlingSession, "seq") shouldBe a[java.util.List[_]] - CqlPreparedStatementUtil.asList(defaultGatlingSession, "seq") shouldBe + CqlPreparedStatementUtil.asList(defaultGatlingSession, "seq", classOf[Int]) shouldBe a[java.util.List[_]] + CqlPreparedStatementUtil.asList(defaultGatlingSession, "seq", classOf[Int]) shouldBe defaultSessionVars("list").asInstanceOf[List[Int]].asJava } it("should not accept a float and produce a CqlTypeException") { intercept[CqlTypeException] { - CqlPreparedStatementUtil.asList(defaultGatlingSession, "float") shouldBe a[java.util.List[_]] + CqlPreparedStatementUtil.asList(defaultGatlingSession, "float", classOf[Float]) shouldBe a[java.util.List[_]] } } - } - describe("asMap") { - it("should accept a scala set") { - CqlPreparedStatementUtil.asMap(defaultGatlingSession, "map") shouldBe a[java.util.Map[_, _]] - CqlPreparedStatementUtil.asMap(defaultGatlingSession, "map") shouldBe + it("should accept a scala map") { + CqlPreparedStatementUtil.asMap(defaultGatlingSession, "map", classOf[Int], classOf[Int]) shouldBe a[java.util.Map[_,_]] + CqlPreparedStatementUtil.asMap(defaultGatlingSession, "map", classOf[Int], classOf[Int]) shouldBe defaultSessionVars("map").asInstanceOf[Map[Int, Int]].asJava } - it("should accept a java set") { - CqlPreparedStatementUtil.asMap(defaultGatlingSession, "mapJava") shouldBe a[java.util.Map[_, _]] + it("should accept a java map") { + CqlPreparedStatementUtil.asMap(defaultGatlingSession, "mapJava", classOf[Int], classOf[Int]) shouldBe a[java.util.Map[_,_]] } it("should not accept a float and produce a CqlTypeException") { intercept[CqlTypeException] { - CqlPreparedStatementUtil.asMap(defaultGatlingSession, "float").get(1) shouldBe 1 + CqlPreparedStatementUtil.asMap(defaultGatlingSession, "float", classOf[Int], classOf[Int]).get(1) shouldBe 1 } } - } describe("asInet") { @@ -707,32 +707,32 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { describe("asTimestamp") { it("should accept an epoch long") { - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "epoch") shouldBe a[java.util.Date] - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "epoch") shouldBe + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "epoch") shouldBe a[Instant] + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "epoch") shouldBe new java.util.Date(defaultSessionVars("epoch").asInstanceOf[Long]) } - it("should accept a java Date") { - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "javaDate") shouldBe a[java.util.Date] - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "javaDate") shouldBe - defaultSessionVars("javaDate").asInstanceOf[java.util.Date] + it("should accept a java Instant") { + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "javaInstant") shouldBe a[Instant] + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "javaInstant") shouldBe + defaultSessionVars("javaInstant").asInstanceOf[Instant] } it("should accept a date string") { - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "dateString") shouldBe a[java.util.Date] - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "dateString") shouldBe - DateTime.parse(defaultSessionVars("dateString").asInstanceOf[String]).toDate + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "dateString") shouldBe a[Instant] + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "dateString") shouldBe + DateTime.parse(defaultSessionVars("dateString").asInstanceOf[String]).toInstant } it("should accept a isoDateString string") { - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "isoDateString") shouldBe a[java.util.Date] - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "isoDateString") shouldBe - DateTime.parse(defaultSessionVars("isoDateString").asInstanceOf[String]).toDate + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "isoDateString") shouldBe a[Instant] + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "isoDateString") shouldBe + DateTime.parse(defaultSessionVars("isoDateString").asInstanceOf[String]).toInstant } it("should not accept a float and produce a CqlTypeException") { intercept[CqlTypeException] { - CqlPreparedStatementUtil.asTimestamp(defaultGatlingSession, "float") shouldBe a[java.util.Date] + CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "float") shouldBe a[Instant] } } @@ -770,9 +770,10 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { createType(keyspace, typeName, "firstname text, lastname text") createTable(keyspace, table, "id int, name frozen, PRIMARY KEY(id)") - val addressType = dseSession.getCluster.getMetadata.getKeyspace(keyspace).getUserType(typeName) + val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType(typeName)) + addressType should not be Optional.empty - val insertFullName = addressType.newValue() + val insertFullName = addressType.get.newValue() .setString("firstname", "John") .setString("lastname", "Smith") @@ -781,23 +782,19 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val udtSession: Session = gatlingSession.setAll(newSessionVars) it("should accept a UDTValue") { - CqlPreparedStatementUtil.asUdt(udtSession, "fullname") shouldBe a[UDTValue] + CqlPreparedStatementUtil.asUdt(udtSession, "fullname") shouldBe a[UdtValue] } it("should not accept a float and produce a CqlTypeException") { intercept[CqlTypeException] { - CqlPreparedStatementUtil.asUdt(udtSession, "invalid") shouldBe a[UDTValue] + CqlPreparedStatementUtil.asUdt(udtSession, "invalid") shouldBe a[UdtValue] } } - } describe("asTuple") { - val table = "tuple_test" - createTable(keyspace, table, "id int, tuple_type tuple, PRIMARY KEY (id)") - - val tupleType = dseSession.getCluster.getMetadata.newTupleType(DataType.varchar(), DataType.varchar()) + val tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.TEXT) val insertTuple = tupleType.newValue("test", "test2") val newSessionVars = Map("tuple_type" -> insertTuple, "invalid" -> "string") val tupleSession: Session = gatlingSession.setAll(newSessionVars) @@ -811,15 +808,11 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { CqlPreparedStatementUtil.asTuple(tupleSession, "invalid") shouldBe a[TupleValue] } } - } - } - describe("boundStatementFunctions") { - val typeName = "fullname2" createType(keyspace, typeName, "firstname text, lastname text") @@ -843,7 +836,6 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { |timeuuid_type, |int_type, |text_type, - |varchar_type, |ascii_type, |float_type, |double_type, @@ -866,168 +858,168 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { |null_type, |none_type) |VALUES - |(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""".stripMargin + |(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""".stripMargin val boundStatementKeys = dseSession.prepare(preparedStatementInsert).bind() it("should bind with a UUID") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.UUID, "uuid", 0) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.UUID.getProtocolCode, "uuid", 0) result shouldBe a[BoundStatement] result.isSet(0) shouldBe true } it("should bind with a timeUuid") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TIMEUUID, "timeUuid", 1) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMEUUID.getProtocolCode, "timeUuid", 1) result shouldBe a[BoundStatement] result.isSet(1) shouldBe true } it("should bind with a int") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.INT, "int", 2) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.INT.getProtocolCode, "int", 2) result shouldBe a[BoundStatement] result.isSet(2) shouldBe true } it("should bind with a text") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TEXT, "string", 3) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, "string", 3) result shouldBe a[BoundStatement] result.isSet(3) shouldBe true } - it("should bind with a varchar") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.VARCHAR, "string", 4) - result shouldBe a[BoundStatement] - result.isSet(4) shouldBe true - } - it("should bind with a ascii") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.ASCII, "string", 5) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.ASCII.getProtocolCode, "string", 4) result shouldBe a[BoundStatement] - result.isSet(5) shouldBe true + result.isSet(4) shouldBe true } it("should bind with a float") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.FLOAT, "float", 6) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.FLOAT.getProtocolCode, "float", 5) result shouldBe a[BoundStatement] - result.isSet(6) shouldBe true + result.isSet(5) shouldBe true } it("should bind with a double") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.DOUBLE, "double", 7) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DOUBLE.getProtocolCode, "double", 6) result shouldBe a[BoundStatement] - result.isSet(7) shouldBe true + result.isSet(6) shouldBe true } it("should bind with a decimal") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.DECIMAL, "double", 8) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DECIMAL.getProtocolCode, "double", 7) result shouldBe a[BoundStatement] - result.isSet(8) shouldBe true + result.isSet(7) shouldBe true } it("should bind with a boolean") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.BOOLEAN, "boolean", 9) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BOOLEAN.getProtocolCode, "boolean", 8) result shouldBe a[BoundStatement] - result.isSet(9) shouldBe true + result.isSet(8) shouldBe true } it("should bind with a inetAddress") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.INET, "inetStr", 10) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.INET.getProtocolCode, "inetStr", 9) result shouldBe a[BoundStatement] - result.isSet(10) shouldBe true + result.isSet(9) shouldBe true } it("should bind with a timestamp") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TIMESTAMP, "epoch", 11) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMESTAMP.getProtocolCode, "epoch", 10) result shouldBe a[BoundStatement] - result.isSet(11) shouldBe true + result.isSet(10) shouldBe true } it("should bind with a bigInt") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.BIGINT, "bigInteger", 12) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BIGINT.getProtocolCode, "bigInteger", 11) result shouldBe a[BoundStatement] - result.isSet(12) shouldBe true + result.isSet(11) shouldBe true } it("should bind with a blob_type") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.BLOB, "byteArray", 13) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BLOB.getProtocolCode, "byteArray", 12) result shouldBe a[BoundStatement] - result.isSet(13) shouldBe true + result.isSet(12) shouldBe true } it("should bind with a varint") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.VARINT, "int", 14) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.VARINT.getProtocolCode, "int", 13) result shouldBe a[BoundStatement] - result.isSet(14) shouldBe true + result.isSet(13) shouldBe true } it("should bind with a list") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.LIST, "list", 15) + val protocolCode = DataTypes.listOf(DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "list", 14) result shouldBe a[BoundStatement] - result.isSet(15) shouldBe true + result.isSet(14) shouldBe true } it("should bind with a set") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.SET, "set", 16) + val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "set", 15) result shouldBe a[BoundStatement] - result.isSet(16) shouldBe true + result.isSet(15) shouldBe true } it("should bind with a map") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.MAP, "map", 17) + val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "map", 16) result shouldBe a[BoundStatement] - result.isSet(17) shouldBe true + result.isSet(16) shouldBe true } it("should bind with a date") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.DATE, "epoch", 18) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DATE.getProtocolCode, "epoch", 17) result shouldBe a[BoundStatement] - result.isSet(18) shouldBe true + result.isSet(17) shouldBe true } it("should bind with a smallInt") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.SMALLINT, "int", 19) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.SMALLINT.getProtocolCode, "int", 18) result shouldBe a[BoundStatement] - result.isSet(19) shouldBe true + result.isSet(18) shouldBe true } it("should bind with a tinyint") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TINYINT, "int", 20) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT.getProtocolCode, "int", 19) result shouldBe a[BoundStatement] - result.isSet(20) shouldBe true + result.isSet(19) shouldBe true } it("should bind with a time") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TIME, "epoch", 21) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIME.getProtocolCode, "epoch", 20) result shouldBe a[BoundStatement] - result.isSet(21) shouldBe true + result.isSet(20) shouldBe true } it("should bind with a tuple") { - val tupleType = dseSession.getCluster.getMetadata.newTupleType(DataType.varchar(), DataType.varchar()) + val tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.TEXT) val insertTuple = tupleType.newValue("test", "test2") val newSessionVars = Map("tuple_type" -> insertTuple, "invalid" -> "string") val tupleSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByOrder(tupleSession, boundStatementKeys, DataType.Name.TUPLE, "tuple_type", 22) + val result = CqlPreparedStatementUtil.bindParamByOrder(tupleSession, boundStatementKeys, tupleType.getProtocolCode, "tuple_type", 21) result shouldBe a[BoundStatement] - result.isSet(22) shouldBe true + result.isSet(21) shouldBe true } it("should bind with a udt") { - val addressType = dseSession.getCluster.getMetadata.getKeyspace(keyspace).getUserType("fullname2") - val insertFullName = addressType.newValue() - .setString("firstname", "John") - .setString("lastname", "Smith") + val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname")) + addressType should not be Optional.empty + + val insertFullName = addressType.get.newValue() + .setString("firstname", "John") + .setString("lastname", "Smith") + val newSessionVars = Map("fullname2" -> insertFullName, "invalid" -> "string") val udtSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByOrder(udtSession, boundStatementKeys, DataType.Name.UDT, "fullname2", 23) + val result = CqlPreparedStatementUtil.bindParamByOrder(udtSession, boundStatementKeys, addressType.get.getProtocolCode, "fullname2", 22) result shouldBe a[BoundStatement] - result.isSet(23) shouldBe true + result.isSet(22) shouldBe true } @@ -1038,7 +1030,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val boundStatementCounter = dseSession.prepare(preparedStatementInsertCounter).bind() - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementCounter, DataType.Name.COUNTER, "int", 0) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementCounter, DataTypes.COUNTER.getProtocolCode, "int", 0) result shouldBe a[BoundStatement] result.isSet(0) shouldBe true } @@ -1047,7 +1039,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { boundStatementKeys.isSet("null_type") shouldBe false - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TINYINT, "null_type", 24) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT.getProtocolCode, "null_type", 24) result shouldBe a[BoundStatement] boundStatementKeys.isSet("null_type") shouldBe true @@ -1058,17 +1050,17 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val field = "none_type" - CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TEXT, field, 25) shouldBe a[BoundStatement] + CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] boundStatementKeys.isSet(field) shouldBe false val newSessionVars = Map(field -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - CqlPreparedStatementUtil.bindParamByOrder(newSession, boundStatementKeys, DataType.Name.TEXT, field, 25) shouldBe a[BoundStatement] + CqlPreparedStatementUtil.bindParamByOrder(newSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] boundStatementKeys.isSet(field) shouldBe true boundStatementKeys.getString(field) shouldBe "test" - CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataType.Name.TEXT, field, 25) shouldBe a[BoundStatement] + CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] boundStatementKeys.isSet(field) shouldBe false } @@ -1078,7 +1070,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map("missing" -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - CqlPreparedStatementUtil.bindParamByOrder(newSession, boundStatementKeys, DataType.Name.TEXT, field, 25) shouldBe a[BoundStatement] + CqlPreparedStatementUtil.bindParamByOrder(newSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] boundStatementKeys.isSet(field) shouldBe false } } @@ -1092,7 +1084,6 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { |timeuuid_type, |int_type, |text_type, - |varchar_type, |ascii_type, |float_type, |double_type, @@ -1147,10 +1138,9 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val defaultSessionVars = Map( "uuid_type" -> java.util.UUID.randomUUID(), - "timeuuid_type" -> UUIDs.timeBased(), + "timeuuid_type" -> Uuids.timeBased(), "int_type" -> 12, "text_type" -> "string", - "varchar_type" -> "string", "ascii_type" -> "string", "float_type" -> 12.0.toFloat, "double_type" -> 12.0, @@ -1177,84 +1167,77 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should bind with a UUID") { val paramName = "uuid_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.UUID, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.UUID.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a timeUuid") { val paramName = "timeuuid_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TIMEUUID, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMEUUID.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a int") { val paramName = "int_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.INT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a text") { val paramName = "text_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TEXT, paramName) - result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true - } - - it("should bind with a varchar") { - val paramName = "varchar_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.VARCHAR, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a ascii") { val paramName = "ascii_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.ASCII, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.ASCII.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a float") { val paramName = "float_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.FLOAT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.FLOAT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a double") { val paramName = "double_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.DOUBLE, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DOUBLE.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a decimal") { val paramName = "decimal_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.DECIMAL, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DECIMAL.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a boolean") { val paramName = "boolean_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.BOOLEAN, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BOOLEAN.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a inetAddress") { val paramName = "inet_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.INET, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INET.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a timestamp") { val paramName = "timestamp_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TIMESTAMP, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMESTAMP.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true @@ -1262,97 +1245,103 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should bind with a bigInt") { val paramName = "bigint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.BIGINT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BIGINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a blob_type") { val paramName = "blob_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.BLOB, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BLOB.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a varint") { val paramName = "varint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.VARINT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.VARINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a list") { val paramName = "list_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.LIST, paramName) + val protocolCode = DataTypes.listOf(DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a set") { val paramName = "set_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.SET, paramName) + val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a map") { val paramName = "map_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.MAP, paramName) + val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a date") { val paramName = "date_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.DATE, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DATE.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a smallInt") { val paramName = "smallint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.SMALLINT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.SMALLINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a tinyint") { val paramName = "tinyint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TINYINT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a time") { val paramName = "time_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TIME, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIME.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } it("should bind with a tuple") { val paramName = "tuple_type" - val tupleType = dseSession.getCluster.getMetadata.newTupleType(DataType.varchar(), DataType.varchar()) + val tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.TEXT) val insertTuple = tupleType.newValue("test", "test2") - val newSessionVars = Map("tuple_type" -> insertTuple, "invalid" -> "string") + val newSessionVars = Map(paramName -> insertTuple, "invalid" -> "string") val tupleSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByName(tupleSession, boundStatementNames, DataType.Name.TUPLE, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(tupleSession, boundStatementNames, tupleType.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } - it("should bind with a udt") { + val paramName = "udt_type" - val addressType = dseSession.getCluster.getMetadata.getKeyspace(keyspace).getUserType("fullname2") - val insertFullName = addressType.newValue() - .setString("firstname", "John") - .setString("lastname", "Smith") - val newSessionVars = Map("udt_type" -> insertFullName, "invalid" -> "string") + + val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname")) + addressType should not be Optional.empty + + val insertFullName = addressType.get.newValue() + .setString("firstname", "John") + .setString("lastname", "Smith") + val newSessionVars = Map(paramName -> insertFullName, "invalid" -> "string") val udtSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByName(udtSession, boundStatementNames, DataType.Name.UDT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(udtSession, boundStatementNames, addressType.get.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true } @@ -1365,7 +1354,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val boundNamedStatementCounter = dseSession.prepare(preparedStatementInsertCounter).bind() - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundNamedStatementCounter, DataType.Name.COUNTER, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundNamedStatementCounter, DataTypes.COUNTER.getProtocolCode, paramName) result shouldBe a[BoundStatement] } @@ -1374,7 +1363,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val paramName = "null_type" boundStatementNames.isSet(paramName) shouldBe false - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TINYINT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true @@ -1385,19 +1374,19 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val paramName = "none_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TEXT, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) result shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe false val newSessionVars = Map(paramName -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - val result2 = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataType.Name.TEXT, paramName) + val result2 = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) result2 shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe true boundStatementNames.getString(paramName) shouldBe "test" - val result3 = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataType.Name.TEXT, paramName) + val result3 = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) result3 shouldBe a[BoundStatement] boundStatementNames.isSet(paramName) shouldBe false } @@ -1408,11 +1397,10 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map("missing" -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataType.Name.TEXT, field) + val result = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, field) result shouldBe a[BoundStatement] boundStatementNames.isSet(field) shouldBe false } - } } } From 9da8ccadb09974cf4b8adebffbd036d0a1f032f6 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 7 Jan 2020 15:06:57 -0600 Subject: [PATCH 33/62] Base compilation now succeeds... on to actually fixing tests --- .../cql/BatchStatementSimulation.scala | 10 ++--- .../cql/BoundCqlTypesSimulation.scala | 45 ++++++++++--------- .../cql/NamedStatementSimulation.scala | 12 +++-- .../cql/PreparedStatementSimulation.scala | 15 ++++--- .../cql/SimpleStatementSimulation.scala | 12 +++-- .../cql/UdtStatementSimulation.scala | 36 ++++++++------- .../graph/GraphStatementSimulation.scala | 38 ++++++---------- 7 files changed, 88 insertions(+), 80 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BatchStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BatchStatementSimulation.scala index e4a7bb9..c9a1d67 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BatchStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BatchStatementSimulation.scala @@ -1,8 +1,8 @@ package com.datastax.gatling.plugin.simulations.cql -import com.datastax.driver.core.ResultSet import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation +import com.datastax.oss.driver.api.core.`type`.UserDefinedType import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -17,7 +17,7 @@ class BatchStatementSimulation extends BaseCqlSimulation { val cqlConfig = cql.session(session) //Initialize Gatling DSL with your session - val addressType = session.getCluster.getMetadata.getKeyspace(testKeyspace).getUserType("fullname") + val addressType:UserDefinedType = session.getMetadata.getKeyspace(testKeyspace).flatMap(_.getUserDefinedType(udt_name)).get val simpleId = 1 val preparedId = 2 @@ -42,8 +42,8 @@ class BatchStatementSimulation extends BaseCqlSimulation { val scn = scenario("BatchStatement") .feed(preparedFeed) .exec(insertPreparedCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) setUp( @@ -53,7 +53,7 @@ class BatchStatementSimulation extends BaseCqlSimulation { ) - def createTable: ResultSet = { + private def createTable = { val udt = s""" diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala index 89dcf8a..4c8f9f6 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala @@ -3,10 +3,11 @@ package com.datastax.gatling.plugin.simulations.cql import java.nio.ByteBuffer import java.sql.Timestamp -import com.datastax.driver.core.utils.UUIDs -import com.datastax.driver.core.{DataType, ResultSet} import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation +import com.datastax.oss.driver.api.core.`type`.{DataTypes, UserDefinedType} +import com.datastax.oss.driver.api.core.cql.Row +import com.datastax.oss.driver.api.core.uuid.Uuids import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -20,16 +21,16 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { createTable val cqlConfig = cql.session(session) - val udtType = session.getCluster.getMetadata.getKeyspace(testKeyspace).getUserType("fullname") + val addressType:UserDefinedType = session.getMetadata.getKeyspace(testKeyspace).flatMap(_.getUserDefinedType("fullname")).get - val insertFullName = udtType.newValue() + val insertFullName = addressType.newValue() .setString("firstname", "John") .setString("lastname", "Smith") - val tupleType = session.getCluster.getMetadata.newTupleType(DataType.text(), DataType.text()) + val tupleType = DataTypes.tupleOf(DataTypes.TEXT, DataTypes.TEXT) val insertTuple = tupleType.newValue("one", "two") - val uuid = UUIDs.random() + val uuid = Uuids.random() val preparedStatementInsert = s"""INSERT INTO $testKeyspace.$table_name ( @@ -58,7 +59,7 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { val preparedFeed = Iterator.continually( Map( "uuid_type" -> uuid, - "timeuuid_type" -> UUIDs.timeBased(), + "timeuuid_type" -> Uuids.timeBased(), "int_type" -> 1, "text_type" -> "text", "float_type" -> 4.50, @@ -110,37 +111,43 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { ) // End counter details + // A predicate function can be useful when we want to do multiple comparisons on data in a single row + private def preparedCqlPredicate(row:Row):Boolean = + row.getBoolean("boolean_type") && (!row.getString("null_type").equals("test")) + + // In most cases we can simply extrat a value from the row and compare that extracted value to an expected value + // via the Gatling API + private def counterCqlExtract(row:Row):Int = + row.getInt("counter_type") val scn = scenario("BoundCqlStatement") .feed(preparedFeed) .exec(insertPreparedCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(100.millis) .exec(selectPreparedCql .withParams(List("uuid_type")) - .check(rowCount is 1) - .check(columnValue("name") not "") - .check(columnValue("null_type") not "test") - .check(columnValue("boolean_type") is true) + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => preparedCqlPredicate(rs.one)) is true) ) .pause(100.millis) .feed(counterFeed) .exec(insertCounterPreparedCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(100.millis) .exec(selectCounterPreparedCql .withParams(List("uuid_type")) - .check(rowCount is 1) - .check(columnValue("counter_type") is 2) + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => counterCqlExtract(rs.one)) is 2) ) .pause(100.millis) @@ -151,8 +158,7 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { global.failedRequests.count.is(0) ) - - def createTable: ResultSet = { + private def createTable = { val udt = s""" @@ -213,5 +219,4 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { val time: Long = (offset + (Math.random() * diff)).toLong new Timestamp(time) } - } diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/NamedStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/NamedStatementSimulation.scala index cf88192..9000064 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/NamedStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/NamedStatementSimulation.scala @@ -2,6 +2,7 @@ package com.datastax.gatling.plugin.simulations.cql import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation +import com.datastax.oss.driver.api.core.cql.Row import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -39,17 +40,20 @@ class NamedStatementSimulation extends BaseCqlSimulation { val selectCql = cql("NamedParam Select Statement") .executeNamed(preparedSelect) + private def selectCqlExtract(row:Row):String = + row.getString("str") + val scn = scenario("NamedStatement") .feed(feeder) .exec(insertCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(1.seconds) .exec(selectCql - .check(rowCount is 1) - .check(columnValue("str") is insertStr) + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => selectCqlExtract(rs.one)) is insertStr) ) diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala index f634abd..8542c20 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala @@ -2,6 +2,7 @@ package com.datastax.gatling.plugin.simulations.cql import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation +import com.datastax.oss.driver.api.core.cql.Row import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -47,24 +48,26 @@ class PreparedStatementSimulation extends BaseCqlSimulation { .executePrepared(preparedSelect) .withParams(List("id", "str")) + private def selectCqlExtract(row:Row):String = + row.getString("name") val scnPassed = scenario("ABCPreparedStatement") .feed(feeder) .exec(insertCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(1.seconds) .exec(selectCql - .check(rowCount is 1) - .check(columnValue("name") is insertName) + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => selectCqlExtract(rs.one)) is insertName) ) .pause(1.seconds) .exec(selectCqlSessionParam - .check(rowCount is 1) - .check(columnValue("name") is insertName) + .check(resultSet.transform(_.remaining) is 0) + .check(resultSet.transform(rs => selectCqlExtract(rs.one)) is insertName) ) diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala index a314aad..3d6b397 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala @@ -2,6 +2,7 @@ package com.datastax.gatling.plugin.simulations.cql import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation +import com.datastax.oss.driver.api.core.cql.Row import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -27,16 +28,19 @@ class SimpleStatementSimulation extends BaseCqlSimulation { val selectCql = cql("Select_Statement") .executeCql(simpleStatementSelect) + private def selectCqlExtract(row:Row):String = + row.getString("str") + val scn = scenario("SimpleStatement") .exec(insertCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(1.seconds) .group("TestGroup") { exec(selectCql - .check(rowCount is 1) - .check(columnValue("str") is insertStr) + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => selectCqlExtract(rs.one)) is insertStr) ) } diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala index 1406973..8fb1e31 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala @@ -1,8 +1,9 @@ package com.datastax.gatling.plugin.simulations.cql -import com.datastax.driver.core.ResultSet import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation +import com.datastax.oss.driver.api.core.`type`.UserDefinedType +import com.datastax.oss.driver.api.core.cql.Row import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -17,7 +18,7 @@ class UdtStatementSimulation extends BaseCqlSimulation { val cqlConfig = cql.session(session) //Initialize Gatling DSL with your session - val addressType = session.getCluster.getMetadata.getKeyspace(testKeyspace).getUserType("fullname") + val addressType:UserDefinedType = session.getMetadata.getKeyspace(testKeyspace).flatMap(_.getUserDefinedType("fullname")).get val simpleId = 1 val preparedId = 2 @@ -26,7 +27,6 @@ class UdtStatementSimulation extends BaseCqlSimulation { .setString("firstname", "John") .setString("lastname", "Smith") - val simpleStatementInsert = s"""INSERT INTO $testKeyspace.$table_name (id, name) VALUES ($simpleId, $insertFullName)""" val simpleStatementSelect = s"""SELECT * FROM $testKeyspace.$table_name WHERE id = $simpleId""" @@ -74,44 +74,47 @@ class UdtStatementSimulation extends BaseCqlSimulation { ) ) + private def extractFirstNameFromRow(row:Row):String = + row.getUdtValue("name").getString(0) + val scn = scenario("SimpleStatement") .exec(insertCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(100.millis) .exec(selectCql - .check(rowCount is 1) - .check(columnValue("name").find(0) not "") + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => extractFirstNameFromRow(rs.one)) not "") ) .pause(100.millis) .feed(preparedFeed) .exec(insertPreparedCql .withParams(List("id", "fullname")) - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(100.millis) .exec(selectPreparedCql .withParams(List("id")) - .check(rowCount is 1) - .check(columnValue("name").find(0) not "") + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => extractFirstNameFromRow(rs.one)) not "") ) .pause(100.millis) .feed(namedFeed) .exec(insertNamedCql - .check(exhausted is true) - .check(rowCount is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.hasMorePages) is false) + .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything ) .pause(100.millis) .exec(selectNamedCql - .check(rowCount is 1) - .check(columnValue("name").find(0) not "") + .check(resultSet.transform(_.remaining) is 1) + .check(resultSet.transform(rs => extractFirstNameFromRow(rs.one)) not "") ) setUp( @@ -120,8 +123,7 @@ class UdtStatementSimulation extends BaseCqlSimulation { global.failedRequests.count.is(0) ) - - def createTable: ResultSet = { + private def createTable = { val udt = s""" diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala index 8f2fce2..1ac3f73 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala @@ -1,12 +1,10 @@ package com.datastax.gatling.plugin.simulations.graph -import com.datastax.driver.core.ConsistencyLevel -import com.datastax.driver.dse.graph.{GraphStatement, SimpleGraphStatement} -import com.datastax.dse.graph.api.DseGraph +import com.datastax.dse.driver.api.core.graph.{DseGraph, FluentGraphStatement, ScriptGraphStatement} import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseGraphSimulation +import com.datastax.oss.driver.api.core.ConsistencyLevel import io.gatling.core.Predef._ -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal import org.scalatest.Ignore import scala.concurrent.duration.DurationInt @@ -15,42 +13,36 @@ import scala.concurrent.duration.DurationInt class GraphStatementSimulation extends BaseGraphSimulation { val table_name = "test_table" - - session.getCluster.getConfiguration.getGraphOptions.setGraphName("demo") + val graph_name = "demo" val graphConfig = graph.session(session) //Initialize Gatling DSL with your session val r = scala.util.Random - val graphStatement = new SimpleGraphStatement("g.addV(label, vertexLabel).property('type', myType)") - def getInt: String = { "test_" + r.nextInt(100).toString } + val insertStatement = ScriptGraphStatement.newInstance("g.addV(label, vertexLabel).property('type', myType)") val insertGraph = graph("Graph Statement") - .executeGraphStatement(graphStatement) - .withSetParams(Array("vertexLabel", "myType")) - .consistencyLevel(ConsistencyLevel.LOCAL_ONE) + .executeGraph(insertStatement) + .withParams("vertexLabel", "myType") + .withConsistencyLevel(ConsistencyLevel.LOCAL_ONE) + .withName(graph_name) val queryGraph = graph("Graph Query") .executeGraph("g.V().limit(5)") + .withName(graph_name) - val g = DseGraph.traversal(session) - val t: GraphTraversal[_,_] = g.V().limit(5) - val st: GraphStatement = DseGraph.statementFromTraversal(t) - + val queryStatement: FluentGraphStatement = FluentGraphStatement.newInstance(DseGraph.g.V().limit(5)) val queryGraphNative = graph("Graph Fluent") - .executeGraphFluent(st) - - val queryGraphFeederTraversal = graph("Graph Feeder") - .executeGraphFeederTraversal("traversal") + .executeGraphFluent(queryStatement) + .withName(graph_name) val feeder = Iterator.continually( Map[String, Any]( "vertexLabel" -> getInt, - "myType" -> r.nextInt(100), - "traversal" -> t + "myType" -> r.nextInt(100) ) ) @@ -60,12 +52,10 @@ class GraphStatementSimulation extends BaseGraphSimulation { .pause(1.seconds) .exec(queryGraph - .check(rowCount greaterThan 1) + .check(graphResultSet.transform(_.remaining) greaterThan 1) ) .pause(1.seconds) .exec(queryGraphNative) - .pause(1.seconds) - .exec(queryGraphFeederTraversal) .exec(session => { // println(session("test").asOption[String].toString) session From 17117d1cfdd0eff35945e1e30000ab9340827e00 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 9 Jan 2020 05:49:59 -0600 Subject: [PATCH 34/62] Fixes for various spec failures. Don't try to create mocks for Durations... it makes them ANGRY! --- .../gatling/plugin/DseCqlStatementSpec.scala | 3 +-- .../plugin/model/CqlStatementBuildersSpec.scala | 12 ++++++------ .../plugin/request/CqlRequestActionSpec.scala | 7 ++++--- .../plugin/request/GraphRequestActionSpec.scala | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala index 13dfdbc..a74e532 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala @@ -49,9 +49,8 @@ class DseCqlStatementSpec extends BaseSpec { val result = DseCqlSimpleStatement(stmt).buildFromSession(validGatlingSession) result shouldBe a[Success[_]] - result.get.toString shouldBe stmt.toString + result.get.build.getQuery shouldBe stmt.getQuery } - } diff --git a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala index 85da143..dcf09cf 100644 --- a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala @@ -36,7 +36,7 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar val routingKey = mock[ByteBuffer] val routingKeyspace = "some_keyspace" val routingToken = mock[Token] - val timeout = mock[Duration] + val timeout = Duration.ofHours(1) val cqlCheck = CqlChecks.resultSet.find.is(mock[AsyncResultSet].expressionSuccess).build val statementAttributes: DseCqlAttributes[_,_] = cql("the-session-tag") .executeCql("FOO") @@ -63,12 +63,12 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar statementAttributes.enableTrace should be(Some(true)) statementAttributes.pageSize should be(Some(3)) statementAttributes.pagingState should be(Some(pagingState)) - statementAttributes.queryTimestamp should be(queryTimestamp) - statementAttributes.routingKey should be(routingKey) - statementAttributes.routingKeyspace should be(routingKeyspace) - statementAttributes.routingToken should be(routingToken) + statementAttributes.queryTimestamp should be(Some(queryTimestamp)) + statementAttributes.routingKey should be(Some(routingKey)) + statementAttributes.routingKeyspace should be(Some(routingKeyspace)) + statementAttributes.routingToken should be(Some(routingToken)) statementAttributes.serialCl should be(Some(THREE)) - statementAttributes.timeout should be(timeout) + statementAttributes.timeout should be(Some(timeout)) statementAttributes.cqlStatements should contain only "FOO" } diff --git a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala index d75daf6..a9028d2 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala @@ -16,6 +16,7 @@ import com.datastax.gatling.plugin.utils.GatlingTimingSource import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseCqlStatement} import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.config.DefaultDriverOption import com.datastax.oss.driver.api.core.cql.{SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.api.core.metadata.token.Token @@ -40,7 +41,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { val routingKey:ByteBuffer = mock[ByteBuffer] val routingKeyspace = "some_keyspace" val routingToken:Token = mock[Token] - val timeout:Duration = mock[Duration] + val timeout:Duration = Duration.ofHours(1) val statsEngine: StatsEngine = mock[StatsEngine] val gatlingSession = Session("scenario", 1) @@ -88,7 +89,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { capturedStatement shouldBe a[SimpleS] capturedStatement.getConsistencyLevel shouldBe null capturedStatement.getSerialConsistencyLevel shouldBe null - capturedStatement.getPageSize shouldBe 0 + capturedStatement.getPageSize should be <= 0 capturedStatement.isIdempotent shouldBe null capturedStatement.isTracing shouldBe false capturedStatement.getQuery should be("select * from test") @@ -131,7 +132,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { capturedStatement.getPagingState shouldBe pagingState capturedStatement.getQueryTimestamp shouldBe queryTimestamp capturedStatement.getRoutingKey shouldBe routingKey - capturedStatement.getRoutingKeyspace shouldBe routingKeyspace + capturedStatement.getRoutingKeyspace.toString shouldBe routingKeyspace capturedStatement.getRoutingToken shouldBe routingToken capturedStatement.getSerialConsistencyLevel shouldBe ConsistencyLevel.LOCAL_SERIAL capturedStatement.getTimeout shouldBe timeout diff --git a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala index cd0fc09..069b40e 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala @@ -30,7 +30,7 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { val dseGraphStatement = mock[DseGraphStatement[ScriptS,ScriptB]] val node:Node = mock[Node] val subProtocol = "graph-binary-3.0" - val timeout:Duration = mock[Duration] + val timeout:Duration = Duration.ofHours(1) val timestamp = 123L val pagingState:ByteBuffer = mock[ByteBuffer] val statsEngine: StatsEngine = mock[StatsEngine] From e00ad38cdeecda8e82faef182720efeb80de8348 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 9 Jan 2020 16:40:20 -0600 Subject: [PATCH 35/62] Fighting with mocks is awesome --- .../plugin/model/DseCqlStatements.scala | 74 ++++++++++++++---- .../gatling/plugin/DseCqlStatementSpec.scala | 75 ++++++++++--------- 2 files changed, 99 insertions(+), 50 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 4b670fe..b39780a 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -45,7 +45,9 @@ case class DseCqlSimpleStatement(statement: SimpleS) * * @param preparedStatement the prepared statement on which to bind parameters */ -case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement) +case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, + preparedStatement: PreparedStatement, + builderFn: (BoundS) => BoundB) extends DseCqlStatement[BoundS, BoundB] { def buildFromSession(gatlingSession: Session): Validation[BoundB] = { @@ -53,7 +55,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare gatlingSession, preparedStatement.bind(), cqlTypes.getParamsMap(preparedStatement)) - new BoundB(template).success + builderFn(template).success } /** @@ -67,7 +69,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare protected def bindParams(gatlingSession: Session, template: BoundS, queryParams: Map[String, Int]): BoundS = { val completedBuilder = - queryParams.foldLeft(new BoundB(template)) { + queryParams.foldLeft(builderFn(template)) { (builder, kv) => kv match { case (gatlingSessionKey, valType) => @@ -78,6 +80,14 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare } } +object DseCqlBoundStatementNamed { + val defaultBuilderFn = (s:BoundS) => new BoundB(s) + + def apply(cqlTypes: CqlPreparedStatementUtil, + preparedStatement: PreparedStatement):DseCqlBoundStatementNamed = + new DseCqlBoundStatementNamed(cqlTypes, preparedStatement, defaultBuilderFn) +} + /** * Bind Gatling session values to the CQL Prepared Statement * @@ -86,6 +96,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, prepare */ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, + builderFn: (BoundS) => BoundB, params: Expression[AnyRef]*) extends DseCqlStatement[BoundS, BoundB] { @@ -100,11 +111,20 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt firstError.toString().failure } else { val template:BoundS = preparedStatement.bind(parsedParams.map(_.get): _*) - new BoundB(template).success + builderFn(template).success } } } +object DseCqlBoundStatementWithPassedParams { + val defaultBuilderFn = (s:BoundS) => new BoundB(s) + + def apply(cqlTypes: CqlPreparedStatementUtil, + preparedStatement: PreparedStatement, + params: Expression[AnyRef]*):DseCqlBoundStatementWithPassedParams = + new DseCqlBoundStatementWithPassedParams(cqlTypes, preparedStatement, defaultBuilderFn, params:_*) +} + /** * Bind Gatling session params to the CQL Prepared Statement * @@ -112,7 +132,8 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt */ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - sessionKeys: Seq[String]) + sessionKeys: Seq[String], + builderFn: (BoundS) => BoundB) extends DseCqlStatement[BoundS, BoundB] { /** @@ -123,7 +144,7 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, */ def buildFromSession(gatlingSession: Session): Validation[BoundB] = { val template:BoundS = bindParams(gatlingSession, preparedStatement.bind(), sessionKeys) - new BoundB(template).success + builderFn(template).success } /** @@ -138,7 +159,7 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, sessionKeys: Seq[String]): BoundS = { val params = cqlTypes.getParamsList(preparedStatement) val completedBuilder = - sessionKeys.zip(Iterable.range(0,sessionKeys.size)).foldLeft(new BoundB(template)) { + sessionKeys.zip(Iterable.range(0,sessionKeys.size)).foldLeft(builderFn(template)) { (builder, kv) => kv match { case (sessionKey, cnt) => cqlTypes.bindParamByOrder(gatlingSession, builder, params(cnt), sessionKey, cnt) @@ -148,13 +169,23 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, } } +object DseCqlBoundStatementWithParamList { + val defaultBuilderFn = (s:BoundS) => new BoundB(s) + + def apply(cqlTypes: CqlPreparedStatementUtil, + preparedStatement: PreparedStatement, + sessionKeys: Seq[String]):DseCqlBoundStatementWithParamList = + new DseCqlBoundStatementWithParamList(cqlTypes, preparedStatement, sessionKeys, defaultBuilderFn) +} /** * Bound CQL Prepared Statement from Named Params * * @param statements CQL Prepared Statements */ -case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, statements: Seq[PreparedStatement]) +case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, + statements: Seq[PreparedStatement], + builderFn: (BoundS) => BoundB) extends DseCqlStatement[BatchS, BatchB] { def buildFromSession(gatlingSession: Session): Validation[BatchB] = { @@ -163,7 +194,6 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme builder.addStatements(batchables:_*).success } - /** * Bind Gatling Session Params to CQL Statement by Name and Type * @@ -171,10 +201,11 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme * @param statement CQL Prepared Statement * @return */ - protected def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundS = { + def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundS = { val queryParams: Map[String, Int] = cqlTypes.getParamsMap(statement) + val initBuilder:BoundB = builderFn(statement.bind()) val completedBuilder = - queryParams.foldLeft(new BoundB(statement.bind())) { + queryParams.foldLeft(initBuilder) { (builder, kv) => kv match { case (gatlingSessionKey, valType) => @@ -185,6 +216,13 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, stateme } } +object DseCqlBoundBatchStatement { + val defaultBuilderFn = (s:BoundS) => new BoundB(s) + + def apply(cqlTypes: CqlPreparedStatementUtil, + statements: Seq[PreparedStatement]):DseCqlBoundBatchStatement = + new DseCqlBoundBatchStatement(cqlTypes, statements, defaultBuilderFn) +} /** * Set a custom payload on the statement @@ -216,7 +254,9 @@ case class DseCqlCustomPayloadStatement(statement: SimpleS, payloadRef: String) * * @param sessionKey the session key which is associated to a PreparedStatement */ -case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, sessionKey: String) +case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, + sessionKey: String, + builderFn: (BoundS) => BoundB) extends DseCqlStatement[BoundS, BoundB] { def buildFromSession(gatlingSession: Session): Validation[BoundB] = { @@ -224,6 +264,14 @@ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUt throw new DseCqlStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } val preparedStatement = gatlingSession(sessionKey).as[PreparedStatement] - DseCqlBoundStatementNamed(cqlTypes, preparedStatement).buildFromSession(gatlingSession) + DseCqlBoundStatementNamed(cqlTypes, preparedStatement, builderFn).buildFromSession(gatlingSession) } } + +object DseCqlBoundStatementNamedFromSession { + val defaultBuilderFn = (s:BoundS) => new BoundB(s) + + def apply(cqlTypes: CqlPreparedStatementUtil, + sessionKey: String):DseCqlBoundStatementNamedFromSession = + new DseCqlBoundStatementNamedFromSession(cqlTypes, sessionKey, defaultBuilderFn) +} \ No newline at end of file diff --git a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala index a74e532..ebd9fae 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala @@ -40,7 +40,6 @@ class DseCqlStatementSpec extends BaseSpec { reset(prepared, mockBoundStatement, mockCqlTypes) } - describe("DseCqlSimpleStatement") { it("should succeed with a passed SimpleStatement", CqlTest) { @@ -53,25 +52,26 @@ class DseCqlStatementSpec extends BaseSpec { } } - describe("DseCqlBoundStatementWithPassedParams") { val e1 = ElCompiler.compile[AnyRef]("${foo}") val e2 = ElCompiler.compile[AnyRef]("${bar}") + val mockBuilder = mock[BoundStatementBuilder] + it("correctly bind values to a prepared statement") { expecting { prepared.bind(fooValue, barValue).andReturn(mockBoundStatement) + mockBuilder.build().andReturn(mockBoundStatement) } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementWithPassedParams(mockCqlTypes, prepared, e1, e2) + DseCqlBoundStatementWithPassedParams(mockCqlTypes, prepared, (_) => mockBuilder, e1, e2) .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } - it("should fail if the expression is wrong and return the 1st error") { expecting { @@ -87,64 +87,69 @@ class DseCqlStatementSpec extends BaseSpec { } } - describe("DseCqlBoundStatementWithParamList") { val validParamList = Seq("foo", "bar") - val paramsList = List[Int](DataTypes.TEXT, DataTypes.INT) + val paramsList = List(DataTypes.TEXT, DataTypes.INT).map(_.getProtocolCode) + + val mockBuilder = mock[BoundStatementBuilder] it("correctly bind values to a prepared statement") { expecting { prepared.bind().andReturn(mockBoundStatement) mockCqlTypes.getParamsList(prepared).andReturn(paramsList) - mockCqlTypes.bindParamByOrder(validGatlingSession, mockBoundStatement, DataTypes.TEXT, "foo", 0) - .andReturn(mockBoundStatement) - mockCqlTypes.bindParamByOrder(validGatlingSession, mockBoundStatement, DataTypes.INT, "bar", 1) - .andReturn(mockBoundStatement) + mockCqlTypes.bindParamByOrder(validGatlingSession, mockBuilder, DataTypes.TEXT.getProtocolCode, "foo", 0) + .andReturn(mockBuilder) + mockCqlTypes.bindParamByOrder(validGatlingSession, mockBuilder, DataTypes.INT.getProtocolCode, "bar", 1) + .andReturn(mockBuilder) + mockBuilder.build().andReturn(mockBoundStatement) } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementWithParamList(mockCqlTypes, prepared, validParamList) + DseCqlBoundStatementWithParamList(mockCqlTypes, prepared, validParamList, (_) => mockBuilder) .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } } - - describe("DseCqlBoundStatementNamed") { + val mockBuilder = mock[BoundStatementBuilder] + it("correctly bind values to a prepared statement") { expecting { prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) - mockCqlTypes.bindParamByName(validGatlingSession, mockBoundStatement, DataTypes.INT, "foo") - .andReturn(mockBoundStatement) + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT.getProtocolCode)) + mockCqlTypes.bindParamByName(validGatlingSession, mockBuilder, DataTypes.INT.getProtocolCode, "foo") + .andReturn(mockBuilder) + mockBuilder.build().andReturn(mockBoundStatement) } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementNamed(mockCqlTypes, prepared) + DseCqlBoundStatementNamed(mockCqlTypes, prepared, (_) => mockBuilder) .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } } + describe("DseCqlBoundStatementNamedFromSession") { + val mockBuilder = mock[BoundStatementBuilder] - - describe("DseCqlBoundStatementNamedFromSession") { it("correctly bind values to a prepared statement in session") { val sessionWithStatement: Session = validGatlingSession.set("statementKey", prepared) expecting { prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) - mockCqlTypes.bindParamByName(sessionWithStatement, mockBoundStatement, DataTypes.INT, "foo") - .andReturn(mockBoundStatement) + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT.getProtocolCode)) + mockCqlTypes.bindParamByName(sessionWithStatement, mockBuilder, DataTypes.INT.getProtocolCode, fooKey) + .andReturn(mockBuilder) + mockBuilder.build().andReturn(mockBoundStatement) } + whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementNamedFromSession(mockCqlTypes, "statementKey") + DseCqlBoundStatementNamedFromSession(mockCqlTypes, "statementKey", (_) => mockBuilder) .buildFromSession(sessionWithStatement) shouldBe a[Success[_]] } } @@ -162,30 +167,28 @@ class DseCqlStatementSpec extends BaseSpec { } } - - - describe("DseCqlBoundBatchStatement") { + val mockBuilder = mock[BoundStatementBuilder] + it("correctly bind values to a prepared statement") { expecting { - mockBoundStatement.getCustomPayload.andReturn(Map("test" -> ByteBuffer.wrap(Array(12.toByte))).asJava) - mockBoundStatement.getCustomPayload.andReturn(Map("test" -> ByteBuffer.wrap(Array(12.toByte))).asJava) prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) - mockCqlTypes.bindParamByName(validGatlingSession, mockBoundStatement, DataTypes.INT, "foo") - .andReturn(mockBoundStatement) + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT.getProtocolCode)) + mockCqlTypes.bindParamByName(validGatlingSession, mockBuilder, DataTypes.INT.getProtocolCode, fooKey) + .andReturn(mockBuilder).anyTimes() + mockBuilder.build().andReturn(mockBoundStatement) } - whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundBatchStatement(mockCqlTypes, Seq(prepared)) - .buildFromSession(validGatlingSession) shouldBe a[Success[_]] + whenExecuting(prepared, mockCqlTypes, mockBoundStatement, mockBuilder) { + DseCqlBoundBatchStatement(mockCqlTypes, Seq(prepared), (_) => mockBuilder) + //.buildFromSession(validGatlingSession) shouldBe a[Success[_]] + .bindParams(validGatlingSession)(prepared) shouldBe mockBoundStatement } } } - describe("DseCqlCustomPayloadStatement") { val stmt = SimpleStatement.builder("select * from keyspace.table where id = 5").build() @@ -218,8 +221,6 @@ class DseCqlStatementSpec extends BaseSpec { DseCqlCustomPayloadStatement(stmt, "payload") .buildFromSession(payloadGatlingSession) shouldBe a[Failure] } - } - } From 64f9bb45a4779f6a570b3aafbeada7ef6b0f1d18 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 9 Jan 2020 19:23:59 -0600 Subject: [PATCH 36/62] All non-cassandra-unit specs should be passing now --- .../gatling/plugin/DseCqlStatementSpec.scala | 10 ++++++---- .../request/GraphRequestActionSpec.scala | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala index ebd9fae..6784f09 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala @@ -183,8 +183,7 @@ class DseCqlStatementSpec extends BaseSpec { whenExecuting(prepared, mockCqlTypes, mockBoundStatement, mockBuilder) { DseCqlBoundBatchStatement(mockCqlTypes, Seq(prepared), (_) => mockBuilder) - //.buildFromSession(validGatlingSession) shouldBe a[Success[_]] - .bindParams(validGatlingSession)(prepared) shouldBe mockBoundStatement + .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } } @@ -195,15 +194,18 @@ class DseCqlStatementSpec extends BaseSpec { it("should succeed with a passed SimpleStatement", CqlTest) { + val expectedCustomPayload = Map("test" -> ByteBuffer.wrap(Array(12.toByte))) val payloadGatlingSession = new Session("name", 1, Map( - "payload" -> Map("test" -> ByteBuffer.wrap(Array(12.toByte)))) + "payload" -> expectedCustomPayload) ) val result = DseCqlCustomPayloadStatement(stmt, "payload") .buildFromSession(payloadGatlingSession) result shouldBe a[Success[_]] - result.get.toString shouldBe stmt.toString + val resultStmt = result.get.build + resultStmt.getCustomPayload shouldBe expectedCustomPayload.asJava + resultStmt.getQuery shouldBe stmt.getQuery } it("should fail with non existent sessionKey", CqlTest) { diff --git a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala index 069b40e..2803f9c 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala @@ -29,9 +29,13 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { val dseSession = mock[DseSession] val dseGraphStatement = mock[DseGraphStatement[ScriptS,ScriptB]] val node:Node = mock[Node] + val readConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM val subProtocol = "graph-binary-3.0" val timeout:Duration = Duration.ofHours(1) val timestamp = 123L + val traversalSource = "g.V()" + val writeConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM + val pagingState:ByteBuffer = mock[ByteBuffer] val statsEngine: StatsEngine = mock[StatsEngine] val gatlingSession = Session("scenario", 1) @@ -68,12 +72,12 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { idempotent = Some(true), node = Some(node), graphName = Some("MyGraph"), - readCL = Some(ConsistencyLevel.LOCAL_QUORUM), + readCL = Some(readConsistencyLevel), subProtocol = Some(subProtocol), timeout = Some(timeout), timestamp = Some(timestamp), - traversalSource = Some("g.V()"), - writeCL = Some(ConsistencyLevel.LOCAL_QUORUM) + traversalSource = Some(traversalSource), + writeCL = Some(writeConsistencyLevel) ) expecting { @@ -89,8 +93,14 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { capturedStatement shouldBe a[ScriptS] capturedStatement.getConsistencyLevel shouldBe ConsistencyLevel.ANY capturedStatement.isIdempotent shouldBe true + capturedStatement.getNode shouldBe node capturedStatement.getGraphName shouldBe "MyGraph" - capturedStatement.isSystemQuery shouldBe false + capturedStatement.getReadConsistencyLevel shouldBe readConsistencyLevel + capturedStatement.getSubProtocol shouldBe subProtocol + capturedStatement.getTimeout shouldBe timeout + capturedStatement.getTimestamp shouldBe timestamp + capturedStatement.getTraversalSource shouldBe traversalSource + capturedStatement.getWriteConsistencyLevel shouldBe writeConsistencyLevel } } } From 1bffa1a8d6d8ba226004abbfa22bf07682870290 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 14 Jan 2020 14:58:26 -0600 Subject: [PATCH 37/62] Various test fixes. Includes a fix to get cassandra-util tests running again; new version of cassandra-util calls initSession() when trying to retrieve a session from a (possibly not yet initialized) embedded instance. As a result our old pattern of only creating the embedded instance if the session is null was bound to fail. Since we're creating the instance in an object anyway it seems safe to do without the guard. --- .../plugin/base/BaseCassandraServerSpec.scala | 4 +- .../plugin/base/GatlingDseSession.scala | 2 +- .../utils/CqlPreparedStatementUtilSpec.scala | 38 +++++++++++-------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala b/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala index f696720..93a1548 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala @@ -1,6 +1,7 @@ package com.datastax.gatling.plugin.base import java.nio.file.Files +import java.util.concurrent.atomic.AtomicBoolean import com.datastax.dse.driver.api.core.DseSession import org.cassandraunit.utils.EmbeddedCassandraServerHelper @@ -45,12 +46,11 @@ class BaseCassandraServerSpec extends BaseSpec { } object BaseCassandraServerSpec { - if (EmbeddedCassandraServerHelper.getSession == null) { + EmbeddedCassandraServerHelper.startEmbeddedCassandra( "cassandra.yaml", Files.createTempDirectory("gatling-dse-plugin.").toString, 30000L) - } private val dseSession: DseSession = GatlingDseSession.getSession } diff --git a/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala b/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala index 880eb24..fe3b516 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala @@ -31,7 +31,7 @@ trait GatlingDseSession { session = try { - DseSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).build() + DseSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).withLocalDatacenter("datacenter1").build() } catch { case _: Exception => DseSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).build() diff --git a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala index ff5268b..527b40b 100644 --- a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala @@ -3,7 +3,7 @@ package com.datastax.gatling.plugin.utils import java.math.BigInteger import java.net.InetAddress import java.nio.ByteBuffer -import java.time.{Instant, LocalDate} +import java.time.{Duration, Instant, LocalDate, LocalTime} import java.util.Optional import com.datastax.dse.driver.api.core.data.geometry._ @@ -24,6 +24,13 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { createKeyspace(keyspace) + def toLocalDate(epochMillis:Long):LocalDate = { + + val end = Instant.ofEpochMilli(epochMillis) + val d = Duration.between(Instant.EPOCH,end) + LocalDate.ofEpochDay(d.toDays) + } + val gatlingSession = new Session("test", 1L) val defaultSessionVars = Map( "string" -> "string", @@ -43,12 +50,13 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { "floatStr" -> "12.4", "double" -> 12.0, "epoch" -> 1483299340813L, + "epochInstant" -> Instant.ofEpochMilli(1483299340813L), "number" -> 12.asInstanceOf[Number], "inetStr" -> "127.0.0.1", "inet" -> InetAddress.getByName("127.0.0.1"), - "localDate" -> LocalDate.from(Instant.ofEpochMilli(1483299340813L)), + "localDate" -> toLocalDate(1483299340813L), "stringDate" -> "2016-10-05", "set" -> Set(1), @@ -113,7 +121,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = ?") val paramList = CqlPreparedStatementUtil.getParamsList(preparedStatement) - paramList should contain(DataTypes.INT) + paramList should contain(DataTypes.INT.getProtocolCode) } } @@ -125,7 +133,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = :id") val paramsMap = CqlPreparedStatementUtil.getParamsMap(preparedStatement) - paramsMap("id") shouldBe DataTypes.INT + paramsMap("id") shouldBe DataTypes.INT.getProtocolCode } } @@ -520,21 +528,21 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { describe("asTime") { it("should accept a Long") { - CqlPreparedStatementUtil.asTime(defaultGatlingSession, "long") shouldBe a[java.lang.Long] + CqlPreparedStatementUtil.asTime(defaultGatlingSession, "long") shouldBe a[LocalTime] } describe("should accept a String") { it("should accept a String time w/o nanoseconds") { val validHour = CqlPreparedStatementUtil.asTime(defaultGatlingSession, "hourTime") - validHour shouldBe a[java.lang.Long] - validHour shouldBe 3661000000000L + validHour shouldBe a[LocalTime] + validHour.toNanoOfDay shouldBe 3661000000000L } it("should accept a String time w/ nanoseconds") { val validNano = CqlPreparedStatementUtil.asTime(defaultGatlingSession, "nanoTime") - validNano shouldBe a[java.lang.Long] - validNano shouldBe 3661343000000L + validNano shouldBe a[LocalTime] + validNano.toNanoOfDay shouldBe 3661343000000L } it("should not accept invalid hour and produce a CqlTypeException") { @@ -704,18 +712,18 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { } - describe("asTimestamp") { + describe("asInstant") { it("should accept an epoch long") { CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "epoch") shouldBe a[Instant] CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "epoch") shouldBe - new java.util.Date(defaultSessionVars("epoch").asInstanceOf[Long]) + defaultSessionVars("epochInstant") } it("should accept a java Instant") { CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "javaInstant") shouldBe a[Instant] CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "javaInstant") shouldBe - defaultSessionVars("javaInstant").asInstanceOf[Instant] + defaultSessionVars("javaInstant") } it("should accept a date string") { @@ -735,7 +743,6 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "float") shouldBe a[Instant] } } - } describe("asByte") { @@ -818,7 +825,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val tableName = "type_table" createTable(keyspace, tableName, "uuid_type uuid, timeuuid_type timeuuid, int_type int, text_type text, " + - "varchar_type varchar, ascii_type ascii, float_type float, double_type double, decimal_type decimal, " + + "ascii_type ascii, float_type float, double_type double, decimal_type decimal, " + "boolean_type boolean, inet_type inet, timestamp_type timestamp, bigint_type bigint, blob_type blob, " + "varint_type varint, list_type list, set_type set, map_type map, date_type date, " + "smallint_type smallint, tinyint_type tinyint, time_type time, tuple_type tuple, " + @@ -923,7 +930,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { } it("should bind with a timestamp") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMESTAMP.getProtocolCode, "epoch", 10) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMESTAMP.getProtocolCode, "epochInstant", 10) result shouldBe a[BoundStatement] result.isSet(10) shouldBe true } @@ -1110,7 +1117,6 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { |:timeuuid_type, |:int_type, |:text_type, - |:varchar_type, |:ascii_type, |:float_type, |:double_type, From 29e69f3aa554171d6c0cb7c4d01df6848287b5ca Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 15 Jan 2020 16:25:36 -0600 Subject: [PATCH 38/62] CqlPreparedStatementUtil spec now passes! --- .../utils/CqlPreparedStatementUtil.scala | 117 ++++++++++++--- .../utils/CqlPreparedStatementUtilSpec.scala | 137 +++++++++++------- 2 files changed, 181 insertions(+), 73 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index a89fe0f..9479624 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -9,7 +9,8 @@ package com.datastax.gatling.plugin.utils import java.math.BigInteger import java.net.InetAddress import java.nio.ByteBuffer -import java.time.{Instant, LocalDate, LocalTime} +import java.time.{Duration, Instant, LocalDate, LocalTime} +import java.lang import java.util import com.datastax.dse.driver.api.core.data.geometry._ @@ -17,12 +18,12 @@ import com.datastax.oss.driver.api.core.cql._ import com.datastax.oss.protocol.internal.ProtocolConstants.DataType._ import com.datastax.gatling.plugin.exceptions.CqlTypeException import com.datastax.oss.driver.api.core.data.{TupleValue, UdtValue} +import com.github.nscala_time.time.Imports.DateTime import io.gatling.core.session.Session import scala.collection.JavaConverters._ import scala.util.matching.Regex - trait CqlPreparedStatementUtil { protected val hourMinSecRegEx: Regex = """(\d+):(\d+):(\d+)""".r @@ -44,12 +45,80 @@ trait CqlPreparedStatementUtil { def getParamsList(preparedStatement: PreparedStatement): List[Int] } +object SessionCollectionResolver { + def get(session:Session, name:String):Option[Any] = session.attributes.get(name) + + def getClz[T <: Any](session:Session, name:String):Option[Class[T]] = { + get(session,name).flatMap((sessionVal) => { + sessionVal match { + case clz:Class[T] => Option(clz) + case _ => Option.empty + } + }) + } + + def getIterable[T <: Any](session:Session, name:String):Option[lang.Iterable[T]] = { + get(session,name).flatMap((sessionVal) => { + sessionVal match { + case rv:Iterable[T] => Option(rv.asJava) + case rv:lang.Iterable[T] => Option(rv) + case _ => Option.empty + } + }) + } + + def getMap[K <: Any, V <: Any](session:Session, name:String):Option[util.Map[K,V]] = { + get(session,name).flatMap((sessionVal) => { + sessionVal match { + case rv:Map[K,V] => Option(rv.asJava) + case rv:util.Map[K,V] => Option(rv) + case _ => Option.empty + } + }) + } + + def getIterableClz[T <: Any](session:Session, name:String):Class[_ <: T] = { + val sessionOption:Option[Class[T]] = getClz(session, name + "-clz") + if (sessionOption.isDefined) { + sessionOption.get + } else { + val iterableOption:Option[lang.Iterable[T]] = getIterable(session, name) + if (iterableOption.isEmpty) { + throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is unavailable, cannot determine list type") + } + val iterator = iterableOption.get.iterator + if (!iterator.hasNext) { + throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is empty, cannot determine list type") + } + iterator.next.getClass + } + } + + def getMapClzs[K <: Any, V <: Any](session:Session, name:String):(Class[_ <: K],Class[_ <: V]) = { + val sessionKeyOption:Option[Class[K]] = getClz(session, name + "-key-clz") + val sessionValOption:Option[Class[V]] = getClz(session, name + "-val-clz") + if (sessionKeyOption.isDefined && sessionValOption.isDefined) { + (sessionKeyOption.get, sessionValOption.get) + } else { + val mapOption:Option[util.Map[K,V]] = getMap(session, name) + if (mapOption.isEmpty) { + throw new IllegalStateException("Map classes weren't defined in Gatling session and Map is unavailable, cannot determine list type") + } + val iterator = mapOption.get.entrySet.iterator + if (!iterator.hasNext) { + throw new IllegalStateException("Map classes wasn't defined in Gatling session and Map is empty, cannot determine list type") + } + val entry = iterator.next + (entry.getKey.getClass, entry.getValue.getClass) + } + } +} + /** * Utilities for CQL Statement building */ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { - /** * Bind CQL Prepared statement params by key order * @@ -68,8 +137,6 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { } else { bindable } } - val stringClz = classOf[String] - gatlingSession.attributes.get(paramName) match { case Some(null) => bindable.setToNull(paramName) @@ -106,11 +173,17 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { case VARINT => bindable.setBigInteger(key, asVarInt(gatlingSession, paramName)) case LIST => - bindable.setList(key, asList(gatlingSession, paramName, stringClz), stringClz) + val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) + bindable.setList(key, asList(gatlingSession, paramName, clz), clz) case SET => - bindable.setSet(key, asSet(gatlingSession, paramName, stringClz), stringClz) + val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) + bindable.setSet(key, asSet(gatlingSession, paramName, clz), clz) case MAP => - bindable.setMap(key, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) + val clzs = SessionCollectionResolver.getMapClzs(gatlingSession, paramName) + clzs match { + case (keyClz, valClz) => bindable.setMap(key, asMap(gatlingSession, paramName, keyClz, valClz), keyClz, valClz) + case _ => throw new IllegalStateException("Unexpected value observed when computing map classes") + } case UDT => bindable.setUdtValue(key, asUdt(gatlingSession, paramName)) case TUPLE => @@ -162,12 +235,10 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { gatlingSession.attributes.get(paramName) match { case Some(null) => bindable.setToNull(paramName) - bindable case Some(None) => if (bindable.isSet(paramName)) { bindable.unset(paramName) - } - bindable + } else { bindable } case _ => paramType match { case (VARCHAR | ASCII) => @@ -197,11 +268,17 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { case VARINT => bindable.setBigInteger(paramName, asVarInt(gatlingSession, paramName)) case LIST => - bindable.setList(paramName, asList(gatlingSession, paramName, stringClz), stringClz) + val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) + bindable.setList(paramName, asList(gatlingSession, paramName, clz), clz) case SET => - bindable.setSet(paramName, asSet(gatlingSession, paramName, stringClz), stringClz) + val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) + bindable.setSet(paramName, asSet(gatlingSession, paramName, clz), clz) case MAP => - bindable.setMap(paramName, asMap(gatlingSession, paramName, stringClz, stringClz), stringClz, stringClz) + val clzs = SessionCollectionResolver.getMapClzs(gatlingSession, paramName) + clzs match { + case (keyClz, valClz) => bindable.setMap(paramName, asMap(gatlingSession, paramName, keyClz, valClz), keyClz, valClz) + case _ => throw new IllegalStateException("Unexpected value observed when computing map classes") + } case UDT => bindable.setUdtValue(paramName, asUdt(gatlingSession, paramName)) case TUPLE => @@ -491,7 +568,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { case Some(l: Long) => Instant.ofEpochMilli(l) case Some(s: String) => - Instant.parse(s) + Instant.ofEpochMilli(DateTime.parse(s).getMillis) case Some(i: Instant) => i case _ => @@ -765,9 +842,9 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { val dateSplit = s.split("-").toList LocalDate.of(dateSplit.head.toInt, dateSplit(1).toInt, dateSplit(2).toInt) case Some(l: Long) => - LocalDate.ofEpochDay(l) + toLocalDate(l) case Some(i: Int) => - LocalDate.ofEpochDay(i) + toLocalDate(i) case Some(ld: LocalDate) => ld case _ => @@ -856,4 +933,10 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { throw new CqlTypeException(s"$paramName expected to be type of ByteBuffer, Array[Byte] or Byte") } } + + def toLocalDate(epochMillis:Long):LocalDate = { + val end = Instant.ofEpochMilli(epochMillis) + val d = Duration.between(Instant.EPOCH,end) + LocalDate.ofEpochDay(d.toDays) + } } diff --git a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala index 527b40b..8c9b755 100644 --- a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala @@ -3,7 +3,7 @@ package com.datastax.gatling.plugin.utils import java.math.BigInteger import java.net.InetAddress import java.nio.ByteBuffer -import java.time.{Duration, Instant, LocalDate, LocalTime} +import java.time.{Instant, LocalDate, LocalTime} import java.util.Optional import com.datastax.dse.driver.api.core.data.geometry._ @@ -24,13 +24,6 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { createKeyspace(keyspace) - def toLocalDate(epochMillis:Long):LocalDate = { - - val end = Instant.ofEpochMilli(epochMillis) - val d = Duration.between(Instant.EPOCH,end) - LocalDate.ofEpochDay(d.toDays) - } - val gatlingSession = new Session("test", 1L) val defaultSessionVars = Map( "string" -> "string", @@ -56,18 +49,25 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { "inetStr" -> "127.0.0.1", "inet" -> InetAddress.getByName("127.0.0.1"), - "localDate" -> toLocalDate(1483299340813L), + "localDate" -> CqlPreparedStatementUtil.toLocalDate(1483299340813L), "stringDate" -> "2016-10-05", "set" -> Set(1), + "set-clz" -> classOf[Integer], "setString" -> Set("test"), "setJava" -> Set(1).asJava, + "anotherSet" -> Set(1), "list" -> List(1), + "list-clz" -> classOf[Integer], "listJava" -> List(1).asJava, + "anotherList" -> List(1), "map" -> Map(1 -> 1), + "map-key-clz" -> classOf[Integer], + "map-val-clz" -> classOf[Integer], "mapJava" -> Map(1 -> 1).asJava, + "anotherMap" -> Map(1 -> 1), "seq" -> Seq(1), "seqString" -> Seq("test"), @@ -729,13 +729,13 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should accept a date string") { CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "dateString") shouldBe a[Instant] CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "dateString") shouldBe - DateTime.parse(defaultSessionVars("dateString").asInstanceOf[String]).toInstant + Instant.ofEpochMilli(DateTime.parse(defaultSessionVars("dateString").toString).getMillis) } it("should accept a isoDateString string") { CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "isoDateString") shouldBe a[Instant] CqlPreparedStatementUtil.asInstant(defaultGatlingSession, "isoDateString") shouldBe - DateTime.parse(defaultSessionVars("isoDateString").asInstanceOf[String]).toInstant + Instant.ofEpochMilli(DateTime.parse(defaultSessionVars("isoDateString").toString).getMillis) } it("should not accept a float and produce a CqlTypeException") { @@ -960,6 +960,13 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { result.isSet(14) shouldBe true } + it("should bind with a list when inferring types") { + val protocolCode = DataTypes.listOf(DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "anotherList", 14) + result shouldBe a[BoundStatement] + result.isSet(14) shouldBe true + } + it("should bind with a set") { val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "set", 15) @@ -967,6 +974,13 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { result.isSet(15) shouldBe true } + it("should bind with a set when inferring types") { + val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "anotherSet", 15) + result shouldBe a[BoundStatement] + result.isSet(15) shouldBe true + } + it("should bind with a map") { val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "map", 16) @@ -974,6 +988,13 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { result.isSet(16) shouldBe true } + it("should bind with a map when inferring types") { + val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "anotherMap", 16) + result shouldBe a[BoundStatement] + result.isSet(16) shouldBe true + } + it("should bind with a date") { val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DATE.getProtocolCode, "epoch", 17) result shouldBe a[BoundStatement] @@ -1014,7 +1035,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should bind with a udt") { - val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname")) + val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname2")) addressType should not be Optional.empty val insertFullName = addressType.get.newValue() @@ -1046,29 +1067,33 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { boundStatementKeys.isSet("null_type") shouldBe false - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT.getProtocolCode, "null_type", 24) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT.getProtocolCode, "null_type", 23) result shouldBe a[BoundStatement] - boundStatementKeys.isSet("null_type") shouldBe true - boundStatementKeys.isNull("null_type") shouldBe true + result.isSet("null_type") shouldBe true + result.isNull("null_type") shouldBe true } it("should not set and unset a None value") { val field = "none_type" - - CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] boundStatementKeys.isSet(field) shouldBe false + val result1 = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 24) + result1 shouldBe a[BoundStatement] + result1.isSet(field) shouldBe false + val newSessionVars = Map(field -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - CqlPreparedStatementUtil.bindParamByOrder(newSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] - boundStatementKeys.isSet(field) shouldBe true - boundStatementKeys.getString(field) shouldBe "test" + val result2 = CqlPreparedStatementUtil.bindParamByOrder(newSession, result1, DataTypes.TEXT.getProtocolCode, field, 24) + result2 shouldBe a[BoundStatement] + result2.isSet(field) shouldBe true + result2.getString(field) shouldBe "test" - CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] - boundStatementKeys.isSet(field) shouldBe false + val result3 = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, result2, DataTypes.TEXT.getProtocolCode, field, 24) + result3 shouldBe a[BoundStatement] + result3.isSet(field) shouldBe false } it("should not set a missing session value") { @@ -1175,99 +1200,98 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val paramName = "uuid_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.UUID.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a timeUuid") { val paramName = "timeuuid_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMEUUID.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a int") { val paramName = "int_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a text") { val paramName = "text_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a ascii") { val paramName = "ascii_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.ASCII.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a float") { val paramName = "float_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.FLOAT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a double") { val paramName = "double_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DOUBLE.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a decimal") { val paramName = "decimal_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DECIMAL.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a boolean") { val paramName = "boolean_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BOOLEAN.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a inetAddress") { val paramName = "inet_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INET.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a timestamp") { val paramName = "timestamp_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMESTAMP.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true - + result.isSet(paramName) shouldBe true } it("should bind with a bigInt") { val paramName = "bigint_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BIGINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a blob_type") { val paramName = "blob_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BLOB.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a varint") { val paramName = "varint_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.VARINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a list") { @@ -1275,7 +1299,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val protocolCode = DataTypes.listOf(DataTypes.INT).getProtocolCode val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a set") { @@ -1283,7 +1307,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a map") { @@ -1291,35 +1315,35 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a date") { val paramName = "date_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DATE.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a smallInt") { val paramName = "smallint_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.SMALLINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a tinyint") { val paramName = "tinyint_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a time") { val paramName = "time_type" val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIME.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a tuple") { @@ -1331,14 +1355,14 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val result = CqlPreparedStatementUtil.bindParamByName(tupleSession, boundStatementNames, tupleType.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } it("should bind with a udt") { val paramName = "udt_type" - val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname")) + val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname2")) addressType should not be Optional.empty val insertFullName = addressType.get.newValue() @@ -1349,7 +1373,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val result = CqlPreparedStatementUtil.bindParamByName(udtSession, boundStatementNames, addressType.get.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true + result.isSet(paramName) shouldBe true } @@ -1372,29 +1396,30 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true - boundStatementNames.isNull(paramName) shouldBe true + result.isSet(paramName) shouldBe true + result.isNull(paramName) shouldBe true } it("should not set and unset a None value") { val paramName = "none_type" + boundStatementNames.isSet(paramName) shouldBe false val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) result shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe false + result.isSet(paramName) shouldBe false val newSessionVars = Map(paramName -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - val result2 = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) + val result2 = CqlPreparedStatementUtil.bindParamByName(newSession, result, DataTypes.TEXT.getProtocolCode, paramName) result2 shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe true - boundStatementNames.getString(paramName) shouldBe "test" + result2.isSet(paramName) shouldBe true + result2.getString(paramName) shouldBe "test" - val result3 = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) + val result3 = CqlPreparedStatementUtil.bindParamByName(typeSession, result2, DataTypes.TEXT.getProtocolCode, paramName) result3 shouldBe a[BoundStatement] - boundStatementNames.isSet(paramName) shouldBe false + result3.isSet(paramName) shouldBe false } it("should not set a missing session value") { @@ -1405,7 +1430,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val result = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, field) result shouldBe a[BoundStatement] - boundStatementNames.isSet(field) shouldBe false + result.isSet(field) shouldBe false } } } From 2f48dc2e02d9feaf8d3b902b54ab0f209bced4e8 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 17 Jan 2020 14:38:47 -0600 Subject: [PATCH 39/62] Explicitly specify traversal source for graph queries. This doesn't actually matter in practice since cassandra-unit only runs these simulations against a base C* instance which won't understand graph queries anyway. Still, I'm including it here in case this situation should change. --- .../plugin/simulations/graph/GraphStatementSimulation.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala index 1ac3f73..8476488 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/graph/GraphStatementSimulation.scala @@ -28,10 +28,12 @@ class GraphStatementSimulation extends BaseGraphSimulation { .executeGraph(insertStatement) .withParams("vertexLabel", "myType") .withConsistencyLevel(ConsistencyLevel.LOCAL_ONE) + .withTraversalSource("g") .withName(graph_name) val queryGraph = graph("Graph Query") .executeGraph("g.V().limit(5)") + .withTraversalSource("g") .withName(graph_name) val queryStatement: FluentGraphStatement = FluentGraphStatement.newInstance(DseGraph.g.V().limit(5)) From 637cd78d4135af5cf8edaab12021faa0e0071de0 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Sat, 18 Jan 2020 21:46:02 -0600 Subject: [PATCH 40/62] At long last... we have a clean run of tests! --- build.sbt | 28 ++++++---- .../model/DseCqlAttributesBuilder.scala | 2 +- .../plugin/response/DseResponseHandler.scala | 22 +++++++- .../cql/BoundCqlTypesSimulation.scala | 25 +++++---- .../cql/PreparedStatementSimulation.scala | 21 +++++--- .../cql/SimpleStatementSimulation.scala | 54 +++++++++---------- .../cql/UdtStatementSimulation.scala | 15 ++++-- 7 files changed, 107 insertions(+), 60 deletions(-) diff --git a/build.sbt b/build.sbt index 00030c4..6cbde46 100644 --- a/build.sbt +++ b/build.sbt @@ -4,19 +4,21 @@ val gatlingVersion = "2.3.0" scalacOptions += "-target:jvm-1.8" -libraryDependencies += "com.datastax.dse" % "dse-java-driver-core" % "2.3.0" -libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "2.18.0" -libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.1" -libraryDependencies += "org.hdrhistogram" % "HdrHistogram" % "2.1.10" +libraryDependencies += "com.datastax.dse" % "dse-java-driver-core" % "2.3.0" +libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "2.18.0" +libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.1" +libraryDependencies += "org.hdrhistogram" % "HdrHistogram" % "2.1.10" -libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion % Provided +libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion % Provided + +libraryDependencies += "org.fusesource" % "sigar" % "1.6.4" % Test +libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % Test +libraryDependencies += "org.easymock" % "easymock" % "3.5" % Test +libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "4.2.2.0-SNAPSHOT" % Test +libraryDependencies += "org.pegdown" % "pegdown" % "1.6.0" % Test +libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.5.11" % Test +libraryDependencies += "com.datastax.dse" % "dse-java-driver-query-builder" % "2.3.0" % Test -libraryDependencies += "org.fusesource" % "sigar" % "1.6.4" % Test -libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % Test -libraryDependencies += "org.easymock" % "easymock" % "3.5" % Test -libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "4.2.2.0-SNAPSHOT" % Test -libraryDependencies += "org.pegdown" % "pegdown" % "1.6.0" % Test -libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.5.11" % Test resolvers += Resolver.mavenLocal resolvers += Resolver.mavenCentral @@ -42,6 +44,7 @@ assemblyMergeStrategy in assembly := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first } +test in assembly := {} // // Releases should reuse credentials from other build systems. @@ -70,6 +73,7 @@ val lookupM2Settings = { } } +/* publishTo := { if (isSnapshot.value) { Some("Artifactory Realm" at "http://datastax.jfrog.io/datastax/datastax-public-snapshots-local;build.timestamp=" + new java.util.Date().getTime) @@ -77,6 +81,8 @@ publishTo := { Some("Artifactory Realm" at "http://datastax.jfrog.io/datastax/datastax-public-releases-local") } } + */ +publishTo := Some(MavenCache("local-maven", file("/work/maven/repo"))) releaseUseGlobalVersion := false diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 1f71011..b64ac41 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -157,5 +157,5 @@ case class DseCqlAttributesBuilder[T <: Statement[T], B <: StatementBuilder[B,T] withConsistencyLevel(level) def check(check: DseCqlCheck):DseCqlAttributesBuilder[T, B] = - DseCqlAttributesBuilder(attr.copy(cqlChecks = check :: attr.cqlChecks)) + DseCqlAttributesBuilder(attr.copy(cqlChecks = (attr.cqlChecks :+ check))) } diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index 69eedc9..de1ac92 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -26,6 +26,8 @@ import io.gatling.core.session.Session import io.gatling.core.stats.StatsEngine import io.gatling.core.stats.message.ResponseTimings +import collection.JavaConverters._ + object DseResponseHandler { def sanitize(s: String): String = s.replaceAll("""(\r|\n)""", " ") @@ -153,8 +155,26 @@ class CqlResponseHandler[T <: Statement[T], B <: StatementBuilder[B,T]](val next val metricsLogger: MetricsLogger) extends DseResponseHandler[T, AsyncResultSet, CqlResponse] { override protected def tag: String = dseAttributes.tag - override protected def queries: Seq[String] = Seq.empty + override protected def queries: Seq[String] = formatStatement(stmt) override protected def specificChecks: List[DseCqlCheck] = dseAttributes.cqlChecks override protected def newResponse(rs: AsyncResultSet): CqlResponse = new CqlResponse(rs, dseAttributes) override protected def coordinator(rs: AsyncResultSet): Node = rs.getExecutionInfo.getCoordinator + + def formatSimpleStatement(s:SimpleStatement):String = s.getQuery + + def formatBoundStatement(s:BoundStatement):String = s.getPreparedStatement.getQuery + + def formatStatement(stmt:Statement[T]):Seq[String] = { + + stmt match { + case s:SimpleStatement => Seq(formatSimpleStatement(s)) + case s:BoundStatement => Seq(formatBoundStatement(s)) + case s:BatchStatement => s.iterator.asScala.map((stmt) => { + stmt match { + case s:SimpleStatement => formatSimpleStatement(s) + case s:BoundStatement => formatBoundStatement(s) + } + }).toSeq + } + } } diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala index 4c8f9f6..4df0ca5 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala @@ -2,12 +2,14 @@ package com.datastax.gatling.plugin.simulations.cql import java.nio.ByteBuffer import java.sql.Timestamp +import java.time.Instant import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation import com.datastax.oss.driver.api.core.`type`.{DataTypes, UserDefinedType} import com.datastax.oss.driver.api.core.cql.Row import com.datastax.oss.driver.api.core.uuid.Uuids +import com.datastax.oss.driver.api.querybuilder.QueryBuilder import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -45,7 +47,10 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { |:tinyint_type, :time_type, :null_type, :udt_type, :tuple_type, :frozen_set_type, :set_string_type |)""".stripMargin - val preparedStatementSelect = s"""SELECT * FROM $testKeyspace.$table_name WHERE uuid_type = ?""" + val preparedStatementSelect = QueryBuilder.selectFrom(testKeyspace, table_name) + .all() + .whereColumn("uuid_type").isEqualTo(QueryBuilder.bindMarker()) + .build() val preparedInsert = session.prepare(preparedStatementInsert) val preparedSelect = session.prepare(preparedStatementSelect) @@ -113,12 +118,12 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { // A predicate function can be useful when we want to do multiple comparisons on data in a single row private def preparedCqlPredicate(row:Row):Boolean = - row.getBoolean("boolean_type") && (!row.getString("null_type").equals("test")) + row.getBoolean("boolean_type") && row.isNull("null_type") - // In most cases we can simply extrat a value from the row and compare that extracted value to an expected value + // In most cases we can simply extract a value from the row and compare that extracted value to an expected value // via the Gatling API - private def counterCqlExtract(row:Row):Int = - row.getInt("counter_type") + private def counterCqlExtract(row:Row):Long = + row.getLong("counter_type") val scn = scenario("BoundCqlStatement") @@ -147,7 +152,7 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { .exec(selectCounterPreparedCql .withParams(List("uuid_type")) .check(resultSet.transform(_.remaining) is 1) - .check(resultSet.transform(rs => counterCqlExtract(rs.one)) is 2) + .check(resultSet.transform(rs => counterCqlExtract(rs.one)) is 2L) ) .pause(100.millis) @@ -212,11 +217,11 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { } - def getRandomEpoch: Timestamp = { - val offset: Long = Timestamp.valueOf("2012-01-01 00:00:00").getTime + def getRandomEpoch: Instant = { + val offset = Timestamp.valueOf("2012-01-01 00:00:00").getTime val end = Timestamp.valueOf("2017-01-01 00:00:00").getTime val diff = end - offset + 1 - val time: Long = (offset + (Math.random() * diff)).toLong - new Timestamp(time) + val time = (offset + (Math.random() * diff)).toLong + Instant.ofEpochMilli(time) } } diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala index 8542c20..45103e3 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/PreparedStatementSimulation.scala @@ -3,6 +3,7 @@ package com.datastax.gatling.plugin.simulations.cql import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation import com.datastax.oss.driver.api.core.cql.Row +import com.datastax.oss.driver.api.querybuilder.QueryBuilder import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -20,8 +21,16 @@ class PreparedStatementSimulation extends BaseCqlSimulation { val insertStr = "two" val insertName = "test" - val statementInsert = s"""INSERT INTO $testKeyspace.$table_name (id, str, name) VALUES (?, ?, ?)""" - val statementSelect = s"""SELECT * FROM $testKeyspace.$table_name WHERE id = ? AND str = ?""" + val statementInsert = QueryBuilder.insertInto(testKeyspace, table_name) + .value("id", QueryBuilder.bindMarker()) + .value("str", QueryBuilder.bindMarker()) + .value("name", QueryBuilder.bindMarker()) + .build() + val statementSelect = QueryBuilder.selectFrom(testKeyspace, table_name) + .all() + .whereColumn("id").isEqualTo(QueryBuilder.bindMarker()) + .whereColumn("str").isEqualTo(QueryBuilder.bindMarker()) + .build() val preparedInsert = session.prepare(statementInsert) val preparedSelect = session.prepare(statementSelect) @@ -37,15 +46,15 @@ class PreparedStatementSimulation extends BaseCqlSimulation { ) val insertCql = cql("Insert_Statement") - .executePrepared(preparedInsert) + .executeStatement(preparedInsert) .withParams("${id}", "${str}", "${name}") val selectCql = cql("Select_Statement") - .executePrepared(preparedSelect) + .executeStatement(preparedSelect) .withParams("${id}", "${str}") val selectCqlSessionParam = cql("Select_Statement_Array") - .executePrepared(preparedSelect) + .executeStatement(preparedSelect) .withParams(List("id", "str")) private def selectCqlExtract(row:Row):String = @@ -66,7 +75,7 @@ class PreparedStatementSimulation extends BaseCqlSimulation { .pause(1.seconds) .exec(selectCqlSessionParam - .check(resultSet.transform(_.remaining) is 0) + .check(resultSet.transform(_.remaining) is 1) .check(resultSet.transform(rs => selectCqlExtract(rs.one)) is insertName) ) diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala index 3d6b397..51fea11 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/SimpleStatementSimulation.scala @@ -2,7 +2,9 @@ package com.datastax.gatling.plugin.simulations.cql import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation +import com.datastax.oss.driver.api.core.`type`.DataTypes import com.datastax.oss.driver.api.core.cql.Row +import com.datastax.oss.driver.api.querybuilder.{QueryBuilder, SchemaBuilder} import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -12,36 +14,46 @@ class SimpleStatementSimulation extends BaseCqlSimulation { val table_name = "test_table_simple" createTestKeyspace - createTable + + val createTable = SchemaBuilder.createTable(testKeyspace, table_name) + .ifNotExists + .withPartitionKey("id",DataTypes.INT) + .withClusteringColumn("str", DataTypes.TEXT) + .build + session.execute(createTable) val dseProtocol = dseProtocolBuilder.session(session) //Initialize Gatling DSL with your session val insertId = 1 val insertStr = "one" - val simpleStatementInsert = s"""INSERT INTO $testKeyspace.$table_name (id, str) VALUES ($insertId, '$insertStr')""" - val simpleStatementSelect = s"""SELECT * FROM $testKeyspace.$table_name WHERE id = $insertId""" - - val insertCql = cql("Insert_Statement") - .executeCql(simpleStatementInsert) - - val selectCql = cql("Select_Statement") - .executeCql(simpleStatementSelect) + val simpleStatementInsert = QueryBuilder.insertInto(testKeyspace, table_name) + .value("id", QueryBuilder.literal(insertId)) + .value("str", QueryBuilder.literal(insertStr)) + .build() + val simpleStatementSelect = QueryBuilder.selectFrom(testKeyspace, table_name) + .all() + .whereColumn("id").isEqualTo(QueryBuilder.literal(insertId)) + .build() private def selectCqlExtract(row:Row):String = row.getString("str") val scn = scenario("SimpleStatement") - .exec(insertCql + .exec( + cql("Insert_Statement") + .executeStatement(simpleStatementInsert) .check(resultSet.transform(_.hasMorePages) is false) - .check(resultSet.transform(_.remaining) is 0) // "normal" INSERTs don't return anything + .check(resultSet.transform(_.remaining()) is 0) // "normal" INSERTs don't return anything ) .pause(1.seconds) .group("TestGroup") { - exec(selectCql - .check(resultSet.transform(_.remaining) is 1) - .check(resultSet.transform(rs => selectCqlExtract(rs.one)) is insertStr) - ) + exec( + cql("Select_Statement") + .executeStatement(simpleStatementSelect) + .check(resultSet.transform(_.getExecutionInfo.getWarnings.size).is(0)) + .check(resultSet.transform(_.remaining()) is 1) + .check(resultSet.transform(rs => selectCqlExtract(rs.one)) is insertStr)) } setUp( @@ -49,16 +61,4 @@ class SimpleStatementSimulation extends BaseCqlSimulation { ).assertions( global.failedRequests.count.is(0) ) - - def createTable = { - val table = - s""" - CREATE TABLE IF NOT EXISTS $testKeyspace.$table_name ( - id int, - str text, - PRIMARY KEY (id) - );""" - - session.execute(table) - } } diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala index 8fb1e31..87b7e36 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/UdtStatementSimulation.scala @@ -4,6 +4,7 @@ import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.base.BaseCqlSimulation import com.datastax.oss.driver.api.core.`type`.UserDefinedType import com.datastax.oss.driver.api.core.cql.Row +import com.datastax.oss.driver.api.querybuilder.QueryBuilder import io.gatling.core.Predef._ import scala.concurrent.duration.DurationInt @@ -27,14 +28,20 @@ class UdtStatementSimulation extends BaseCqlSimulation { .setString("firstname", "John") .setString("lastname", "Smith") - val simpleStatementInsert = s"""INSERT INTO $testKeyspace.$table_name (id, name) VALUES ($simpleId, $insertFullName)""" - val simpleStatementSelect = s"""SELECT * FROM $testKeyspace.$table_name WHERE id = $simpleId""" + val simpleStatementInsert = QueryBuilder.insertInto(testKeyspace, table_name) + .value("id", QueryBuilder.literal(simpleId)) + .value("name", QueryBuilder.literal(insertFullName)) + .build() + val simpleStatementSelect = QueryBuilder.selectFrom(testKeyspace, table_name) + .all() + .whereColumn("id").isEqualTo(QueryBuilder.literal(simpleId)) + .build() val insertCql = cql("Insert Simple Statements") - .executeCql(simpleStatementInsert) + .executeStatement(simpleStatementInsert) val selectCql = cql("Select Simple Statement") - .executeCql(simpleStatementSelect) + .executeStatement(simpleStatementSelect) val preparedStatementInsert = s"""INSERT INTO $testKeyspace.$table_name (id, name) VALUES (?, ?)""" val preparedStatementSelect = s"""SELECT * FROM $testKeyspace.$table_name WHERE id = ?""" From d1be0a6388b0672972646fe6b3a85cabc088e3f8 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Sat, 18 Jan 2020 21:52:54 -0600 Subject: [PATCH 41/62] Removing sbt changes that were accidentally committed --- build.sbt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build.sbt b/build.sbt index 6cbde46..795bbf9 100644 --- a/build.sbt +++ b/build.sbt @@ -44,7 +44,6 @@ assemblyMergeStrategy in assembly := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first } -test in assembly := {} // // Releases should reuse credentials from other build systems. @@ -73,7 +72,6 @@ val lookupM2Settings = { } } -/* publishTo := { if (isSnapshot.value) { Some("Artifactory Realm" at "http://datastax.jfrog.io/datastax/datastax-public-snapshots-local;build.timestamp=" + new java.util.Date().getTime) @@ -81,8 +79,6 @@ publishTo := { Some("Artifactory Realm" at "http://datastax.jfrog.io/datastax/datastax-public-releases-local") } } - */ -publishTo := Some(MavenCache("local-maven", file("/work/maven/repo"))) releaseUseGlobalVersion := false From 3432a92228e48caef163100d203ed148db121c2f Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Sat, 18 Jan 2020 22:20:57 -0600 Subject: [PATCH 42/62] cassandra-unit released an official 4.x release while work was ongoing --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 795bbf9..46b7602 100644 --- a/build.sbt +++ b/build.sbt @@ -14,7 +14,7 @@ libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highchar libraryDependencies += "org.fusesource" % "sigar" % "1.6.4" % Test libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % Test libraryDependencies += "org.easymock" % "easymock" % "3.5" % Test -libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "4.2.2.0-SNAPSHOT" % Test +libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "4.3.1.0" % Test libraryDependencies += "org.pegdown" % "pegdown" % "1.6.0" % Test libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.5.11" % Test libraryDependencies += "com.datastax.dse" % "dse-java-driver-query-builder" % "2.3.0" % Test From 539edf96cab4ac01885dcd63ae1662cb2c7d943b Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Sat, 18 Jan 2020 22:55:57 -0600 Subject: [PATCH 43/62] Shift to an API based on DataType rather than ints coming off of getProtocolCode() --- .../plugin/model/DseCqlStatements.scala | 15 +- .../utils/CqlPreparedStatementUtil.scala | 25 ++-- .../gatling/plugin/DseCqlStatementSpec.scala | 20 ++- .../utils/CqlPreparedStatementUtilSpec.scala | 137 ++++++++---------- 4 files changed, 89 insertions(+), 108 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index b39780a..3743adf 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -8,17 +8,10 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer -import com.datastax.oss.driver.api.core.cql.{ - BatchStatement => BatchS, - BatchStatementBuilder => BatchB, - BoundStatement => BoundS, - BoundStatementBuilder => BoundB, - SimpleStatement => SimpleS, - SimpleStatementBuilder => SimpleB, - _ -} +import com.datastax.oss.driver.api.core.cql.{BatchStatement => BatchS, BatchStatementBuilder => BatchB, BoundStatement => BoundS, BoundStatementBuilder => BoundB, SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} import com.datastax.gatling.plugin.exceptions.DseCqlStatementException import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil +import com.datastax.oss.driver.api.core.`type`.DataType import io.gatling.commons.validation._ import io.gatling.core.session._ @@ -67,7 +60,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, * @return */ protected def bindParams(gatlingSession: Session, template: BoundS, - queryParams: Map[String, Int]): BoundS = { + queryParams: Map[String, DataType]): BoundS = { val completedBuilder = queryParams.foldLeft(builderFn(template)) { (builder, kv) => @@ -202,7 +195,7 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, * @return */ def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundS = { - val queryParams: Map[String, Int] = cqlTypes.getParamsMap(statement) + val queryParams: Map[String, DataType] = cqlTypes.getParamsMap(statement) val initBuilder:BoundB = builderFn(statement.bind()) val completedBuilder = queryParams.foldLeft(initBuilder) { diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index 9479624..4c03ff6 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -15,6 +15,7 @@ import java.util import com.datastax.dse.driver.api.core.data.geometry._ import com.datastax.oss.driver.api.core.cql._ +import com.datastax.oss.driver.api.core.`type`._ import com.datastax.oss.protocol.internal.ProtocolConstants.DataType._ import com.datastax.gatling.plugin.exceptions.CqlTypeException import com.datastax.oss.driver.api.core.data.{TupleValue, UdtValue} @@ -31,18 +32,18 @@ trait CqlPreparedStatementUtil { def bindParamByOrder[T <: Bindable[T]](gatlingSession: Session, bindable: T, - paramType: Int, + paramType: DataType, paramName: String, key: Int): T def bindParamByName[T <: Bindable[T]](gatlingSession: Session, bindable: T, - paramType: Int, + paramType: DataType, paramName: String): T - def getParamsMap(preparedStatement: PreparedStatement): Map[String, Int] + def getParamsMap(preparedStatement: PreparedStatement): Map[String, DataType] - def getParamsList(preparedStatement: PreparedStatement): List[Int] + def getParamsList(preparedStatement: PreparedStatement): List[DataType] } object SessionCollectionResolver { @@ -128,7 +129,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName Gatling Session Attribute Name * @param key Key/Order of param */ - def bindParamByOrder[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: Int, + def bindParamByOrder[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: DataType, paramName: String, key: Int): T = { if (!gatlingSession.attributes.contains(paramName)) { @@ -145,7 +146,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { bindable.unset(paramName) } else { bindable } case _ => - paramType match { + paramType.getProtocolCode match { case (VARCHAR | ASCII) => bindable.setString(key, asString(gatlingSession, paramName)) case INT => @@ -221,7 +222,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramType Type of param ie String, int, boolean * @param paramName Gatling Session Attribute Value */ - def bindParamByName[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: Int, + def bindParamByName[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: DataType, paramName: String): T = { if (!gatlingSession.attributes.contains(paramName)) { @@ -240,7 +241,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { bindable.unset(paramName) } else { bindable } case _ => - paramType match { + paramType.getProtocolCode match { case (VARCHAR | ASCII) => bindable.setString(paramName, asString(gatlingSession, paramName)) case INT => @@ -315,10 +316,10 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param preparedStatement CQL Prepared Stated * @return */ - def getParamsMap(preparedStatement: PreparedStatement): Map[String, Int] = { + def getParamsMap(preparedStatement: PreparedStatement): Map[String, DataType] = { val paramVariables = preparedStatement.getVariableDefinitions val paramIterator = paramVariables.iterator.asScala - paramIterator.map(p => (p.getName.asCql(true), p.getType.getProtocolCode)).toMap + paramIterator.map(p => (p.getName.asCql(true), p.getType)).toMap } @@ -328,9 +329,9 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param preparedStatement CQL Prepared Stated * @return */ - def getParamsList(preparedStatement: PreparedStatement): List[Int] = { + def getParamsList(preparedStatement: PreparedStatement): List[DataType] = { val paramVariables = preparedStatement.getVariableDefinitions - paramVariables.iterator.asScala.map(p => p.getType.getProtocolCode).toList + paramVariables.iterator.asScala.map(_.getType).toList } diff --git a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala index 6784f09..51954a0 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala @@ -34,8 +34,6 @@ class DseCqlStatementSpec extends BaseSpec { val invalidStmt = "select * from test where invalid = 'test'" val invalidExceptionError = "Prepared Statements must have at least one settable param. Query: " + invalidStmt - implicit def dataTypeToInt(in:DataType):Int = in.getProtocolCode - before { reset(prepared, mockBoundStatement, mockCqlTypes) } @@ -90,7 +88,7 @@ class DseCqlStatementSpec extends BaseSpec { describe("DseCqlBoundStatementWithParamList") { val validParamList = Seq("foo", "bar") - val paramsList = List(DataTypes.TEXT, DataTypes.INT).map(_.getProtocolCode) + val paramsList = List(DataTypes.TEXT, DataTypes.INT) val mockBuilder = mock[BoundStatementBuilder] @@ -99,9 +97,9 @@ class DseCqlStatementSpec extends BaseSpec { expecting { prepared.bind().andReturn(mockBoundStatement) mockCqlTypes.getParamsList(prepared).andReturn(paramsList) - mockCqlTypes.bindParamByOrder(validGatlingSession, mockBuilder, DataTypes.TEXT.getProtocolCode, "foo", 0) + mockCqlTypes.bindParamByOrder(validGatlingSession, mockBuilder, DataTypes.TEXT, "foo", 0) .andReturn(mockBuilder) - mockCqlTypes.bindParamByOrder(validGatlingSession, mockBuilder, DataTypes.INT.getProtocolCode, "bar", 1) + mockCqlTypes.bindParamByOrder(validGatlingSession, mockBuilder, DataTypes.INT, "bar", 1) .andReturn(mockBuilder) mockBuilder.build().andReturn(mockBoundStatement) } @@ -121,8 +119,8 @@ class DseCqlStatementSpec extends BaseSpec { expecting { prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT.getProtocolCode)) - mockCqlTypes.bindParamByName(validGatlingSession, mockBuilder, DataTypes.INT.getProtocolCode, "foo") + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) + mockCqlTypes.bindParamByName(validGatlingSession, mockBuilder, DataTypes.INT, "foo") .andReturn(mockBuilder) mockBuilder.build().andReturn(mockBoundStatement) } @@ -142,8 +140,8 @@ class DseCqlStatementSpec extends BaseSpec { val sessionWithStatement: Session = validGatlingSession.set("statementKey", prepared) expecting { prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT.getProtocolCode)) - mockCqlTypes.bindParamByName(sessionWithStatement, mockBuilder, DataTypes.INT.getProtocolCode, fooKey) + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) + mockCqlTypes.bindParamByName(sessionWithStatement, mockBuilder, DataTypes.INT, fooKey) .andReturn(mockBuilder) mockBuilder.build().andReturn(mockBoundStatement) } @@ -175,8 +173,8 @@ class DseCqlStatementSpec extends BaseSpec { expecting { prepared.bind().andReturn(mockBoundStatement) - mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT.getProtocolCode)) - mockCqlTypes.bindParamByName(validGatlingSession, mockBuilder, DataTypes.INT.getProtocolCode, fooKey) + mockCqlTypes.getParamsMap(prepared).andReturn(Map(fooKey -> DataTypes.INT)) + mockCqlTypes.bindParamByName(validGatlingSession, mockBuilder, DataTypes.INT, fooKey) .andReturn(mockBuilder).anyTimes() mockBuilder.build().andReturn(mockBoundStatement) } diff --git a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala index 8c9b755..a51e35b 100644 --- a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala @@ -121,9 +121,8 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = ?") val paramList = CqlPreparedStatementUtil.getParamsList(preparedStatement) - paramList should contain(DataTypes.INT.getProtocolCode) + paramList should contain(DataTypes.INT) } - } describe("getParamsMap") { @@ -133,9 +132,8 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = :id") val paramsMap = CqlPreparedStatementUtil.getParamsMap(preparedStatement) - paramsMap("id") shouldBe DataTypes.INT.getProtocolCode + paramsMap("id") shouldBe DataTypes.INT } - } } @@ -870,151 +868,145 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val boundStatementKeys = dseSession.prepare(preparedStatementInsert).bind() it("should bind with a UUID") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.UUID.getProtocolCode, "uuid", 0) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.UUID, "uuid", 0) result shouldBe a[BoundStatement] result.isSet(0) shouldBe true } it("should bind with a timeUuid") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMEUUID.getProtocolCode, "timeUuid", 1) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMEUUID, "timeUuid", 1) result shouldBe a[BoundStatement] result.isSet(1) shouldBe true } it("should bind with a int") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.INT.getProtocolCode, "int", 2) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.INT, "int", 2) result shouldBe a[BoundStatement] result.isSet(2) shouldBe true } it("should bind with a text") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, "string", 3) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT, "string", 3) result shouldBe a[BoundStatement] result.isSet(3) shouldBe true } it("should bind with a ascii") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.ASCII.getProtocolCode, "string", 4) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.ASCII, "string", 4) result shouldBe a[BoundStatement] result.isSet(4) shouldBe true } it("should bind with a float") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.FLOAT.getProtocolCode, "float", 5) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.FLOAT, "float", 5) result shouldBe a[BoundStatement] result.isSet(5) shouldBe true } it("should bind with a double") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DOUBLE.getProtocolCode, "double", 6) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DOUBLE, "double", 6) result shouldBe a[BoundStatement] result.isSet(6) shouldBe true } it("should bind with a decimal") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DECIMAL.getProtocolCode, "double", 7) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DECIMAL, "double", 7) result shouldBe a[BoundStatement] result.isSet(7) shouldBe true } it("should bind with a boolean") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BOOLEAN.getProtocolCode, "boolean", 8) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BOOLEAN, "boolean", 8) result shouldBe a[BoundStatement] result.isSet(8) shouldBe true } it("should bind with a inetAddress") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.INET.getProtocolCode, "inetStr", 9) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.INET, "inetStr", 9) result shouldBe a[BoundStatement] result.isSet(9) shouldBe true } it("should bind with a timestamp") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMESTAMP.getProtocolCode, "epochInstant", 10) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIMESTAMP, "epochInstant", 10) result shouldBe a[BoundStatement] result.isSet(10) shouldBe true } it("should bind with a bigInt") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BIGINT.getProtocolCode, "bigInteger", 11) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BIGINT, "bigInteger", 11) result shouldBe a[BoundStatement] result.isSet(11) shouldBe true } it("should bind with a blob_type") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BLOB.getProtocolCode, "byteArray", 12) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.BLOB, "byteArray", 12) result shouldBe a[BoundStatement] result.isSet(12) shouldBe true } it("should bind with a varint") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.VARINT.getProtocolCode, "int", 13) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.VARINT, "int", 13) result shouldBe a[BoundStatement] result.isSet(13) shouldBe true } it("should bind with a list") { - val protocolCode = DataTypes.listOf(DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "list", 14) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.listOf(DataTypes.INT), "list", 14) result shouldBe a[BoundStatement] result.isSet(14) shouldBe true } it("should bind with a list when inferring types") { - val protocolCode = DataTypes.listOf(DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "anotherList", 14) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.listOf(DataTypes.INT), "anotherList", 14) result shouldBe a[BoundStatement] result.isSet(14) shouldBe true } it("should bind with a set") { - val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "set", 15) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.setOf(DataTypes.INT), "set", 15) result shouldBe a[BoundStatement] result.isSet(15) shouldBe true } it("should bind with a set when inferring types") { - val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "anotherSet", 15) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.setOf(DataTypes.INT), "anotherSet", 15) result shouldBe a[BoundStatement] result.isSet(15) shouldBe true } it("should bind with a map") { - val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "map", 16) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.mapOf(DataTypes.INT, DataTypes.INT), "map", 16) result shouldBe a[BoundStatement] result.isSet(16) shouldBe true } it("should bind with a map when inferring types") { - val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, protocolCode, "anotherMap", 16) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.mapOf(DataTypes.INT, DataTypes.INT), "anotherMap", 16) result shouldBe a[BoundStatement] result.isSet(16) shouldBe true } it("should bind with a date") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DATE.getProtocolCode, "epoch", 17) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DATE, "epoch", 17) result shouldBe a[BoundStatement] result.isSet(17) shouldBe true } it("should bind with a smallInt") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.SMALLINT.getProtocolCode, "int", 18) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.SMALLINT, "int", 18) result shouldBe a[BoundStatement] result.isSet(18) shouldBe true } it("should bind with a tinyint") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT.getProtocolCode, "int", 19) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT, "int", 19) result shouldBe a[BoundStatement] result.isSet(19) shouldBe true } it("should bind with a time") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIME.getProtocolCode, "epoch", 20) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TIME, "epoch", 20) result shouldBe a[BoundStatement] result.isSet(20) shouldBe true } @@ -1026,7 +1018,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map("tuple_type" -> insertTuple, "invalid" -> "string") val tupleSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByOrder(tupleSession, boundStatementKeys, tupleType.getProtocolCode, "tuple_type", 21) + val result = CqlPreparedStatementUtil.bindParamByOrder(tupleSession, boundStatementKeys, tupleType, "tuple_type", 21) result shouldBe a[BoundStatement] result.isSet(21) shouldBe true @@ -1045,7 +1037,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map("fullname2" -> insertFullName, "invalid" -> "string") val udtSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByOrder(udtSession, boundStatementKeys, addressType.get.getProtocolCode, "fullname2", 22) + val result = CqlPreparedStatementUtil.bindParamByOrder(udtSession, boundStatementKeys, addressType.get, "fullname2", 22) result shouldBe a[BoundStatement] result.isSet(22) shouldBe true } @@ -1058,7 +1050,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val boundStatementCounter = dseSession.prepare(preparedStatementInsertCounter).bind() - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementCounter, DataTypes.COUNTER.getProtocolCode, "int", 0) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementCounter, DataTypes.COUNTER, "int", 0) result shouldBe a[BoundStatement] result.isSet(0) shouldBe true } @@ -1067,7 +1059,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { boundStatementKeys.isSet("null_type") shouldBe false - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT.getProtocolCode, "null_type", 23) + val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TINYINT, "null_type", 23) result shouldBe a[BoundStatement] result.isSet("null_type") shouldBe true @@ -1079,19 +1071,19 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val field = "none_type" boundStatementKeys.isSet(field) shouldBe false - val result1 = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 24) + val result1 = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.TEXT, field, 24) result1 shouldBe a[BoundStatement] result1.isSet(field) shouldBe false val newSessionVars = Map(field -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - val result2 = CqlPreparedStatementUtil.bindParamByOrder(newSession, result1, DataTypes.TEXT.getProtocolCode, field, 24) + val result2 = CqlPreparedStatementUtil.bindParamByOrder(newSession, result1, DataTypes.TEXT, field, 24) result2 shouldBe a[BoundStatement] result2.isSet(field) shouldBe true result2.getString(field) shouldBe "test" - val result3 = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, result2, DataTypes.TEXT.getProtocolCode, field, 24) + val result3 = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, result2, DataTypes.TEXT, field, 24) result3 shouldBe a[BoundStatement] result3.isSet(field) shouldBe false } @@ -1102,7 +1094,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map("missing" -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - CqlPreparedStatementUtil.bindParamByOrder(newSession, boundStatementKeys, DataTypes.TEXT.getProtocolCode, field, 25) shouldBe a[BoundStatement] + CqlPreparedStatementUtil.bindParamByOrder(newSession, boundStatementKeys, DataTypes.TEXT, field, 25) shouldBe a[BoundStatement] boundStatementKeys.isSet(field) shouldBe false } } @@ -1198,150 +1190,147 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should bind with a UUID") { val paramName = "uuid_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.UUID.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.UUID, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a timeUuid") { val paramName = "timeuuid_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMEUUID.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMEUUID, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a int") { val paramName = "int_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a text") { val paramName = "text_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a ascii") { val paramName = "ascii_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.ASCII.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.ASCII, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a float") { val paramName = "float_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.FLOAT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.FLOAT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a double") { val paramName = "double_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DOUBLE.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DOUBLE, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a decimal") { val paramName = "decimal_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DECIMAL.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DECIMAL, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a boolean") { val paramName = "boolean_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BOOLEAN.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BOOLEAN, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a inetAddress") { val paramName = "inet_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INET.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.INET, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a timestamp") { val paramName = "timestamp_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMESTAMP.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIMESTAMP, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a bigInt") { val paramName = "bigint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BIGINT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BIGINT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a blob_type") { val paramName = "blob_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BLOB.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.BLOB, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a varint") { val paramName = "varint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.VARINT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.VARINT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a list") { val paramName = "list_type" - val protocolCode = DataTypes.listOf(DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.listOf(DataTypes.INT), paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a set") { val paramName = "set_type" - val protocolCode = DataTypes.setOf(DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.setOf(DataTypes.INT), paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a map") { val paramName = "map_type" - val protocolCode = DataTypes.mapOf(DataTypes.INT, DataTypes.INT).getProtocolCode - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, protocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.mapOf(DataTypes.INT, DataTypes.INT), paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a date") { val paramName = "date_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DATE.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.DATE, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a smallInt") { val paramName = "smallint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.SMALLINT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.SMALLINT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a tinyint") { val paramName = "tinyint_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } it("should bind with a time") { val paramName = "time_type" - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIME.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TIME, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } @@ -1353,7 +1342,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map(paramName -> insertTuple, "invalid" -> "string") val tupleSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByName(tupleSession, boundStatementNames, tupleType.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(tupleSession, boundStatementNames, tupleType, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } @@ -1371,7 +1360,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map(paramName -> insertFullName, "invalid" -> "string") val udtSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByName(udtSession, boundStatementNames, addressType.get.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(udtSession, boundStatementNames, addressType.get, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true } @@ -1384,7 +1373,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val boundNamedStatementCounter = dseSession.prepare(preparedStatementInsertCounter).bind() - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundNamedStatementCounter, DataTypes.COUNTER.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundNamedStatementCounter, DataTypes.COUNTER, paramName) result shouldBe a[BoundStatement] } @@ -1393,7 +1382,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val paramName = "null_type" boundStatementNames.isSet(paramName) shouldBe false - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TINYINT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe true @@ -1405,19 +1394,19 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val paramName = "none_type" boundStatementNames.isSet(paramName) shouldBe false - val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, paramName) + val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundStatementNames, DataTypes.TEXT, paramName) result shouldBe a[BoundStatement] result.isSet(paramName) shouldBe false val newSessionVars = Map(paramName -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - val result2 = CqlPreparedStatementUtil.bindParamByName(newSession, result, DataTypes.TEXT.getProtocolCode, paramName) + val result2 = CqlPreparedStatementUtil.bindParamByName(newSession, result, DataTypes.TEXT, paramName) result2 shouldBe a[BoundStatement] result2.isSet(paramName) shouldBe true result2.getString(paramName) shouldBe "test" - val result3 = CqlPreparedStatementUtil.bindParamByName(typeSession, result2, DataTypes.TEXT.getProtocolCode, paramName) + val result3 = CqlPreparedStatementUtil.bindParamByName(typeSession, result2, DataTypes.TEXT, paramName) result3 shouldBe a[BoundStatement] result3.isSet(paramName) shouldBe false } @@ -1428,7 +1417,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val newSessionVars = Map("missing" -> "test") val newSession: Session = gatlingSession.setAll(newSessionVars) - val result = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataTypes.TEXT.getProtocolCode, field) + val result = CqlPreparedStatementUtil.bindParamByName(newSession, boundStatementNames, DataTypes.TEXT, field) result shouldBe a[BoundStatement] result.isSet(field) shouldBe false } From a70f4afa1fd01b54baf9ae9086cf29b3d4818735 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Sun, 19 Jan 2020 14:02:16 -0600 Subject: [PATCH 44/62] Upgrade to unified driver --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 46b7602..0d6e9e9 100644 --- a/build.sbt +++ b/build.sbt @@ -4,7 +4,7 @@ val gatlingVersion = "2.3.0" scalacOptions += "-target:jvm-1.8" -libraryDependencies += "com.datastax.dse" % "dse-java-driver-core" % "2.3.0" +libraryDependencies += "com.datastax.oss" % "java-driver-core" % "4.4.0" libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "2.18.0" libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.1" libraryDependencies += "org.hdrhistogram" % "HdrHistogram" % "2.1.10" @@ -17,7 +17,7 @@ libraryDependencies += "org.easymock" % "easymock" libraryDependencies += "org.cassandraunit" % "cassandra-unit" % "4.3.1.0" % Test libraryDependencies += "org.pegdown" % "pegdown" % "1.6.0" % Test libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.5.11" % Test -libraryDependencies += "com.datastax.dse" % "dse-java-driver-query-builder" % "2.3.0" % Test +libraryDependencies += "com.datastax.oss" % "java-driver-query-builder" % "4.4.0" % Test resolvers += Resolver.mavenLocal From 545df5517622c4b5111f9545cdfedb69ec47e250 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Fri, 24 Jan 2020 13:58:16 -0600 Subject: [PATCH 45/62] Fixing compile warnings re: unchecked types due to type erasure --- .../plugin/utils/CqlPreparedStatementUtil.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index 4c03ff6..c67690d 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -52,7 +52,7 @@ object SessionCollectionResolver { def getClz[T <: Any](session:Session, name:String):Option[Class[T]] = { get(session,name).flatMap((sessionVal) => { sessionVal match { - case clz:Class[T] => Option(clz) + case clz:Class[T]@unchecked => Option(clz) case _ => Option.empty } }) @@ -61,8 +61,8 @@ object SessionCollectionResolver { def getIterable[T <: Any](session:Session, name:String):Option[lang.Iterable[T]] = { get(session,name).flatMap((sessionVal) => { sessionVal match { - case rv:Iterable[T] => Option(rv.asJava) - case rv:lang.Iterable[T] => Option(rv) + case rv:Iterable[T]@unchecked => Option(rv.asJava) + case rv:lang.Iterable[T]@unchecked => Option(rv) case _ => Option.empty } }) @@ -71,8 +71,8 @@ object SessionCollectionResolver { def getMap[K <: Any, V <: Any](session:Session, name:String):Option[util.Map[K,V]] = { get(session,name).flatMap((sessionVal) => { sessionVal match { - case rv:Map[K,V] => Option(rv.asJava) - case rv:util.Map[K,V] => Option(rv) + case rv:Map[K,V]@unchecked => Option(rv.asJava) + case rv:util.Map[K,V]@unchecked => Option(rv) case _ => Option.empty } }) From 993aaa4b748aff7237470304f5a7222ccb93543c Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 28 Jan 2020 14:24:41 -0600 Subject: [PATCH 46/62] Replace DseSession with CqlSession refs --- .../scala/com/datastax/gatling/plugin/DseProtocol.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala b/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala index 312201d..17c8f88 100644 --- a/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala +++ b/src/main/scala/com/datastax/gatling/plugin/DseProtocol.scala @@ -11,10 +11,10 @@ import java.util.concurrent.atomic.AtomicLong import akka.Done import akka.actor.ActorSystem -import com.datastax.dse.driver.api.core.DseSession import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.request.{CqlRequestActionBuilder, GraphRequestActionBuilder} import com.datastax.gatling.plugin.utils.GatlingTimingSource +import com.datastax.oss.driver.api.core.CqlSession import com.typesafe.scalalogging.StrictLogging import io.gatling.core.CoreComponents import io.gatling.core.config.GatlingConfiguration @@ -63,7 +63,7 @@ object DseProtocol extends StrictLogging { } } -case class DseProtocol(session: DseSession) extends Protocol +case class DseProtocol(session: CqlSession) extends Protocol object DseComponents { private val componentsCache = mutable.Map[ActorSystem, DseComponents]() @@ -126,10 +126,10 @@ case class DseComponents(dseProtocol: DseProtocol, object DseProtocolBuilder { - def session(session: DseSession) = DseProtocolBuilder(session) + def session(session: CqlSession) = DseProtocolBuilder(session) } -case class DseProtocolBuilder(session: DseSession) { +case class DseProtocolBuilder(session: CqlSession) { def build = DseProtocol(session) } From c6962bb2d7247769986773c7f2c93b202aa2f7ec Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 28 Jan 2020 14:38:42 -0600 Subject: [PATCH 47/62] Changing _all_ refs to DseSession to CqlSession instead --- .../plugin/model/DseCqlStatements.scala | 2 +- .../plugin/request/CqlRequestAction.scala | 4 ++-- .../plugin/request/GraphRequestAction.scala | 4 ++-- .../plugin/DseGraphStatementSpec.scala | 6 +++--- .../plugin/base/BaseCassandraServerSpec.scala | 12 ++++++------ .../plugin/base/BaseCqlSimulation.scala | 2 +- .../plugin/base/BaseGraphSimulation.scala | 2 +- ...eSession.scala => GatlingCqlSession.scala} | 18 +++++++++--------- .../plugin/request/CqlRequestActionSpec.scala | 19 +++++++++---------- .../request/GraphRequestActionSpec.scala | 15 +++++++-------- .../utils/CqlPreparedStatementUtilSpec.scala | 18 +++++++++--------- 11 files changed, 50 insertions(+), 52 deletions(-) rename src/test/scala/com/datastax/gatling/plugin/base/{GatlingDseSession.scala => GatlingCqlSession.scala} (71%) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 3743adf..7484a9d 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -132,7 +132,7 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, /** * Apply the Gatling session params to the Prepared statement * - * @param gatlingSession DseSession + * @param gatlingSession current Gatling session * @return */ def buildFromSession(gatlingSession: Session): Validation[BoundB] = { diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index 582c375..8c13c03 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -35,11 +35,11 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * free the Gatling `injector` actor as fast as possible. * * The plugin router (and its actors) execute the driver code in order to locate the best replica that should receive - * each query, through `DseSession.executeAsync()` or `DseSession.executeGraphAsync()`. A driver I/O thread encodes + * each query, through `CqlSession.executeAsync()` or `CqlSession.executeGraphAsync()`. A driver I/O thread encodes * the request and sends it over the wire. * * Once the response is received, a driver I/O thread (Netty) decodes the response into a Java Object. It then - * completes the `Future` that was returned by `DseSession.executeAsync()`. + * completes the `Future` that was returned by `CqlSession.executeAsync()`. * * Completing that future results in immediately delegating the latency recording work to the plugin router. That * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index d27f822..6f606ea 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -34,11 +34,11 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} * free the Gatling `injector` actor as fast as possible. * * The plugin router (and its actors) execute the driver code in order to locate the best replica that should receive - * each query, through `DseSession.executeAsync()` or `DseSession.executeGraphAsync()`. A driver I/O thread encodes + * each query, through `CqlSession.executeAsync()` or `CqlSession.executeGraphAsync()`. A driver I/O thread encodes * the request and sends it over the wire. * * Once the response is received, a driver I/O thread (Netty) decodes the response into a Java Object. It then - * completes the `Future` that was returned by `DseSession.executeAsync()`. + * completes the `Future` that was returned by `CqlSession.executeAsync()`. * * Completing that future results in immediately delegating the latency recording work to the plugin router. That * work includes recording it in HDR histograms through non-blocking data structures, and forwarding the result to diff --git a/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala index 088deda..63371d4 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseGraphStatementSpec.scala @@ -1,10 +1,10 @@ package com.datastax.gatling.plugin -import com.datastax.dse.driver.api.core.DseSession import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, ScriptGraphStatement} import com.datastax.dse.driver.api.core.graph.DseGraph.g import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.model.{GraphBoundStatement, GraphFluentStatement, GraphStringStatement} +import com.datastax.oss.driver.api.core.CqlSession import io.gatling.commons.validation.{Failure, Success} import io.gatling.core.session.Session import io.gatling.core.session.el.ElCompiler @@ -12,12 +12,12 @@ import org.easymock.EasyMock.reset class DseGraphStatementSpec extends BaseSpec { - val mockDseSession = mock[DseSession] + val mockCqlSession = mock[CqlSession] val validGatlingSession = new Session("name", 1, Map("test" -> "5")) val invalidGatlingSession = new Session("name", 1, Map("buzz" -> Map("test" -> "this"))) before { - reset(mockDseSession) + reset(mockCqlSession) } diff --git a/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala b/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala index 93a1548..7bcc96e 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/BaseCassandraServerSpec.scala @@ -3,14 +3,14 @@ package com.datastax.gatling.plugin.base import java.nio.file.Files import java.util.concurrent.atomic.AtomicBoolean -import com.datastax.dse.driver.api.core.DseSession +import com.datastax.oss.driver.api.core.CqlSession import org.cassandraunit.utils.EmbeddedCassandraServerHelper /** * Used for Specs that require a running Cassandra instance to run */ class BaseCassandraServerSpec extends BaseSpec { - protected val dseSession: DseSession = BaseCassandraServerSpec.dseSession + protected val cqlSession: CqlSession = BaseCassandraServerSpec.dseSession protected def cleanCassandra(keyspace: String = ""): Unit = { if (keyspace.isEmpty) { @@ -21,14 +21,14 @@ class BaseCassandraServerSpec extends BaseSpec { } protected def createKeyspace(keyspace: String): Boolean = { - dseSession.execute( + cqlSession.execute( s"CREATE KEYSPACE IF NOT EXISTS $keyspace WITH replication = " + "{ 'class' : 'SimpleStrategy', 'replication_factor': '1'}") .wasApplied() } protected def createTable(keyspace: String, name: String, columns: String): Boolean = { - dseSession.execute( + cqlSession.execute( s""" CREATE TABLE IF NOT EXISTS $keyspace.$name ( $columns @@ -37,7 +37,7 @@ class BaseCassandraServerSpec extends BaseSpec { protected def createType(keyspace: String, name: String, columns: String): Boolean = { - dseSession.execute( + cqlSession.execute( s""" CREATE TYPE IF NOT EXISTS $keyspace.$name ( $columns @@ -52,5 +52,5 @@ object BaseCassandraServerSpec { Files.createTempDirectory("gatling-dse-plugin.").toString, 30000L) - private val dseSession: DseSession = GatlingDseSession.getSession + private val dseSession: CqlSession = GatlingCqlSession.getSession } diff --git a/src/test/scala/com/datastax/gatling/plugin/base/BaseCqlSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/base/BaseCqlSimulation.scala index bd6b95e..dfe9d9d 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/BaseCqlSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/BaseCqlSimulation.scala @@ -6,7 +6,7 @@ abstract class BaseCqlSimulation extends Simulation { val testKeyspace = "gatling_cql_unittests" - val session = GatlingDseSession.createDseSession() + val session = GatlingCqlSession.createCqlSession() def createTestKeyspace = { session.execute( diff --git a/src/test/scala/com/datastax/gatling/plugin/base/BaseGraphSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/base/BaseGraphSimulation.scala index fd0563d..0891137 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/BaseGraphSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/BaseGraphSimulation.scala @@ -6,7 +6,7 @@ abstract class BaseGraphSimulation extends Simulation { val testKeyspace = "gatling_cql_unittests" - val session = GatlingDseSession.createDseSession("10.10.10.2", 9042) + val session = GatlingCqlSession.createCqlSession("10.10.10.2", 9042) def createTestKeyspace = { session.execute( diff --git a/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala b/src/test/scala/com/datastax/gatling/plugin/base/GatlingCqlSession.scala similarity index 71% rename from src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala rename to src/test/scala/com/datastax/gatling/plugin/base/GatlingCqlSession.scala index fe3b516..a649fab 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/GatlingDseSession.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/GatlingCqlSession.scala @@ -2,12 +2,12 @@ package com.datastax.gatling.plugin.base import java.net.InetSocketAddress -import com.datastax.dse.driver.api.core.DseSession +import com.datastax.oss.driver.api.core.CqlSession import org.cassandraunit.utils.EmbeddedCassandraServerHelper -trait GatlingDseSession { +trait GatlingCqlSession { - private var session: DseSession = _ + private var session: CqlSession = _ /** * Create new Dse Session to either the embedded C* instance or a remote instance @@ -18,7 +18,7 @@ trait GatlingDseSession { * @param cassandraPort Cassandra Port, default will use Embedded Cassandra's port * @return */ - def createDseSession(cassandraHost: String = "127.0.0.1", cassandraPort: Int = -1): DseSession = { + def createCqlSession(cassandraHost: String = "127.0.0.1", cassandraPort: Int = -1): CqlSession = { if (session != null) { return session @@ -31,10 +31,10 @@ trait GatlingDseSession { session = try { - DseSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).withLocalDatacenter("datacenter1").build() + CqlSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).withLocalDatacenter("datacenter1").build() } catch { - case _: Exception => DseSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).build() + case _: Exception => CqlSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).build() } session @@ -46,9 +46,9 @@ trait GatlingDseSession { * * @return */ - def getSession: DseSession = { + def getSession: CqlSession = { if (session == null) { - createDseSession() + createCqlSession() } session } @@ -63,4 +63,4 @@ trait GatlingDseSession { } -object GatlingDseSession extends GatlingDseSession +object GatlingCqlSession extends GatlingCqlSession diff --git a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala index a9028d2..0cff9a8 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala @@ -9,13 +9,12 @@ import akka.testkit.TestKitBase import ch.qos.logback.classic.{Level, Logger} import ch.qos.logback.classic.spi.ILoggingEvent import ch.qos.logback.core.read.ListAppender -import com.datastax.dse.driver.api.core.DseSession import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.metrics.NoopMetricsLogger import com.datastax.gatling.plugin.utils.GatlingTimingSource import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseCqlStatement} -import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.{ConsistencyLevel, CqlSession} import com.datastax.oss.driver.api.core.config.DefaultDriverOption import com.datastax.oss.driver.api.core.cql.{SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} import com.datastax.oss.driver.api.core.metadata.Node @@ -32,7 +31,7 @@ import org.slf4j.LoggerFactory class CqlRequestActionSpec extends BaseSpec with TestKitBase { implicit lazy val system:ActorSystem = ActorSystem() val gatlingTestConfig: GatlingConfiguration = GatlingConfiguration.loadForTest() - val dseSession: DseSession = mock[DseSession] + val cqlSession: CqlSession = mock[CqlSession] val dseCqlStatement: DseCqlStatement[SimpleS,SimpleB] = mock[DseCqlStatement[SimpleS,SimpleB]] val node:Node = mock[Node] val pageSize = 3 @@ -51,7 +50,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { new Exit(system.actorOf(Props[DseRequestActor]), statsEngine), system, statsEngine, - DseProtocol(dseSession), + DseProtocol(cqlSession), dseAttributes, NoopMetricsLogger(), executorServiceForTests(), @@ -61,7 +60,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { private def mockAsyncResultSetFuture(): CompletionStage[AsyncResultSet] = CompletableFuture.completedFuture(mock[AsyncResultSet]) before { - reset(dseCqlStatement, dseSession, pagingState, statsEngine) + reset(dseCqlStatement, cqlSession, pagingState, statsEngine) } override protected def afterAll(): Unit = { @@ -78,10 +77,10 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { expecting { dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleS.builder("select * from test") .success) - dseSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() + cqlSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() } - whenExecuting(dseCqlStatement, dseSession) { + whenExecuting(dseCqlStatement, cqlSession) { getTarget(cqlAttributesWithDefaults).sendQuery(gatlingSession) } @@ -115,10 +114,10 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { expecting { dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleS.builder("select * from test") .success) - dseSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() + cqlSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() } - whenExecuting(dseCqlStatement, dseSession) { + whenExecuting(dseCqlStatement, cqlSession) { getTarget(cqlAttributes).sendQuery(gatlingSession) } @@ -156,7 +155,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { listAppender.start() classLogger.addAppender(listAppender) - whenExecuting(dseCqlStatement, dseSession) { + whenExecuting(dseCqlStatement, cqlSession) { cqlRequestAction.sendQuery(gatlingSession) } diff --git a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala index 2803f9c..3e54a53 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala @@ -6,14 +6,13 @@ import java.util.concurrent.{CompletableFuture, CompletionStage} import akka.actor.{ActorSystem, Props} import akka.testkit.TestKitBase -import com.datastax.dse.driver.api.core.DseSession import com.datastax.dse.driver.api.core.graph.{ScriptGraphStatement => ScriptS, ScriptGraphStatementBuilder => ScriptB, _} import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.metrics.NoopMetricsLogger import com.datastax.gatling.plugin.utils.GatlingTimingSource import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.{DseGraphAttributes, DseGraphStatement} -import com.datastax.oss.driver.api.core.ConsistencyLevel +import com.datastax.oss.driver.api.core.{ConsistencyLevel, CqlSession} import com.datastax.oss.driver.api.core.metadata.Node import io.gatling.commons.validation.SuccessWrapper import io.gatling.core.action.Exit @@ -26,7 +25,7 @@ import org.easymock.EasyMock._ class GraphRequestActionSpec extends BaseSpec with TestKitBase { implicit lazy val system = ActorSystem() val gatlingTestConfig = GatlingConfiguration.loadForTest() - val dseSession = mock[DseSession] + val cqlSession = mock[CqlSession] val dseGraphStatement = mock[DseGraphStatement[ScriptS,ScriptB]] val node:Node = mock[Node] val readConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM @@ -46,7 +45,7 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { new Exit(system.actorOf(Props[DseRequestActor]), statsEngine), system, statsEngine, - DseProtocol(dseSession), + DseProtocol(cqlSession), dseAttributes, NoopMetricsLogger(), executorServiceForTests(), @@ -57,13 +56,13 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { CompletableFuture.completedFuture(mock[AsyncGraphResultSet]) before { - reset(dseGraphStatement, dseSession, pagingState, statsEngine) + reset(dseGraphStatement, cqlSession, pagingState, statsEngine) } override protected def afterAll(): Unit = { shutdown(system) } - + describe("Graph") { val statementCapture = EasyMock.newCapture[ScriptS] it("should enable all the Graph Attributes in DseAttributes") { @@ -82,10 +81,10 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { expecting { dseGraphStatement.buildFromSession(gatlingSession) andReturn(ScriptS.builder("g.V()").success) - dseSession.executeAsync(capture(statementCapture)) andReturn mockAsyncGraphResultSetFuture() + cqlSession.executeAsync(capture(statementCapture)) andReturn mockAsyncGraphResultSetFuture() } - whenExecuting(dseGraphStatement, dseSession) { + whenExecuting(dseGraphStatement, cqlSession) { getTarget(graphAttributes).sendQuery(gatlingSession) } diff --git a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala index a51e35b..88bf83d 100644 --- a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala @@ -118,7 +118,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should return a list of types") { - val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = ?") + val preparedStatement = cqlSession.prepare(s"SELECT * FROM $keyspace.$table where id = ?") val paramList = CqlPreparedStatementUtil.getParamsList(preparedStatement) paramList should contain(DataTypes.INT) @@ -129,7 +129,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should return a map of types") { - val preparedStatement = dseSession.prepare(s"SELECT * FROM $keyspace.$table where id = :id") + val preparedStatement = cqlSession.prepare(s"SELECT * FROM $keyspace.$table where id = :id") val paramsMap = CqlPreparedStatementUtil.getParamsMap(preparedStatement) paramsMap("id") shouldBe DataTypes.INT @@ -775,7 +775,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { createType(keyspace, typeName, "firstname text, lastname text") createTable(keyspace, table, "id int, name frozen, PRIMARY KEY(id)") - val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType(typeName)) + val addressType:Optional[UserDefinedType] = cqlSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType(typeName)) addressType should not be Optional.empty val insertFullName = addressType.get.newValue() @@ -865,7 +865,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { |VALUES |(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""".stripMargin - val boundStatementKeys = dseSession.prepare(preparedStatementInsert).bind() + val boundStatementKeys = cqlSession.prepare(preparedStatementInsert).bind() it("should bind with a UUID") { val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.UUID, "uuid", 0) @@ -1027,7 +1027,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { it("should bind with a udt") { - val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname2")) + val addressType:Optional[UserDefinedType] = cqlSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname2")) addressType should not be Optional.empty val insertFullName = addressType.get.newValue() @@ -1048,7 +1048,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatementInsertCounter = s"""UPDATE $keyspace.$counterTableName SET counter_type = counter_type + ? WHERE uuid_type = ?""" - val boundStatementCounter = dseSession.prepare(preparedStatementInsertCounter).bind() + val boundStatementCounter = cqlSession.prepare(preparedStatementInsertCounter).bind() val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementCounter, DataTypes.COUNTER, "int", 0) result shouldBe a[BoundStatement] @@ -1157,7 +1157,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { |:none_type |)""".stripMargin - val boundStatementNames = dseSession.prepare(preparedStatementInsert).bind() + val boundStatementNames = cqlSession.prepare(preparedStatementInsert).bind() val defaultSessionVars = Map( "uuid_type" -> java.util.UUID.randomUUID(), @@ -1351,7 +1351,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val paramName = "udt_type" - val addressType:Optional[UserDefinedType] = dseSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname2")) + val addressType:Optional[UserDefinedType] = cqlSession.getMetadata.getKeyspace(keyspace).flatMap(_.getUserDefinedType("fullname2")) addressType should not be Optional.empty val insertFullName = addressType.get.newValue() @@ -1371,7 +1371,7 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { val preparedStatementInsertCounter = s"""UPDATE $keyspace.$counterTableName SET counter_type = counter_type + :counter_type WHERE uuid_type = :uuid_type""" - val boundNamedStatementCounter = dseSession.prepare(preparedStatementInsertCounter).bind() + val boundNamedStatementCounter = cqlSession.prepare(preparedStatementInsertCounter).bind() val result = CqlPreparedStatementUtil.bindParamByName(typeSession, boundNamedStatementCounter, DataTypes.COUNTER, paramName) result shouldBe a[BoundStatement] From 74b668cf0914a68b2e029bb8bd65917236b08453 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 28 Jan 2020 16:47:07 -0600 Subject: [PATCH 48/62] Code review feedback --- .../plugin/response/DseResponseHandler.scala | 16 ++++---- .../utils/CqlPreparedStatementUtil.scala | 39 +++++++++++-------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala index de1ac92..4b0e145 100644 --- a/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala +++ b/src/main/scala/com/datastax/gatling/plugin/response/DseResponseHandler.scala @@ -155,24 +155,24 @@ class CqlResponseHandler[T <: Statement[T], B <: StatementBuilder[B,T]](val next val metricsLogger: MetricsLogger) extends DseResponseHandler[T, AsyncResultSet, CqlResponse] { override protected def tag: String = dseAttributes.tag - override protected def queries: Seq[String] = formatStatement(stmt) + override protected def queries: Seq[String] = getQueryStrings(stmt) override protected def specificChecks: List[DseCqlCheck] = dseAttributes.cqlChecks override protected def newResponse(rs: AsyncResultSet): CqlResponse = new CqlResponse(rs, dseAttributes) override protected def coordinator(rs: AsyncResultSet): Node = rs.getExecutionInfo.getCoordinator - def formatSimpleStatement(s:SimpleStatement):String = s.getQuery + def getQueryString(s:SimpleStatement):String = s.getQuery - def formatBoundStatement(s:BoundStatement):String = s.getPreparedStatement.getQuery + def getQueryString(s:BoundStatement):String = s.getPreparedStatement.getQuery - def formatStatement(stmt:Statement[T]):Seq[String] = { + def getQueryStrings(stmt:Statement[T]):Seq[String] = { stmt match { - case s:SimpleStatement => Seq(formatSimpleStatement(s)) - case s:BoundStatement => Seq(formatBoundStatement(s)) + case s:SimpleStatement => Seq(getQueryString(s)) + case s:BoundStatement => Seq(getQueryString(s)) case s:BatchStatement => s.iterator.asScala.map((stmt) => { stmt match { - case s:SimpleStatement => formatSimpleStatement(s) - case s:BoundStatement => formatBoundStatement(s) + case s:SimpleStatement => getQueryString(s) + case s:BoundStatement => getQueryString(s) } }).toSeq } diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index c67690d..29e9bac 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -58,21 +58,25 @@ object SessionCollectionResolver { }) } - def getIterable[T <: Any](session:Session, name:String):Option[lang.Iterable[T]] = { + // Note the Java return type here. This function is used to generate objects which will subsequently + // be passed to the Java Bindable impl which is expecting Java Iterators. + def getIterable[T <: Any](session:Session, name:String):Option[Iterable[T]] = { get(session,name).flatMap((sessionVal) => { sessionVal match { - case rv:Iterable[T]@unchecked => Option(rv.asJava) - case rv:lang.Iterable[T]@unchecked => Option(rv) + case rv:Iterable[T]@unchecked => Option(rv) + case rv:lang.Iterable[T]@unchecked => Option(rv.asScala) case _ => Option.empty } }) } - def getMap[K <: Any, V <: Any](session:Session, name:String):Option[util.Map[K,V]] = { + // Note the Java return type here. This function is used to generate objects which will subsequently + // be passed to the Java Bindable impl which is expecting Java Maps. + def getMap[K <: Any, V <: Any](session:Session, name:String):Option[Map[K,V]] = { get(session,name).flatMap((sessionVal) => { sessionVal match { - case rv:Map[K,V]@unchecked => Option(rv.asJava) - case rv:util.Map[K,V]@unchecked => Option(rv) + case rv:Map[K,V]@unchecked => Option(rv) + case rv:util.Map[K,V]@unchecked => Option(rv.asScala.toMap) case _ => Option.empty } }) @@ -80,10 +84,9 @@ object SessionCollectionResolver { def getIterableClz[T <: Any](session:Session, name:String):Class[_ <: T] = { val sessionOption:Option[Class[T]] = getClz(session, name + "-clz") - if (sessionOption.isDefined) { - sessionOption.get - } else { - val iterableOption:Option[lang.Iterable[T]] = getIterable(session, name) + sessionOption.getOrElse { + + val iterableOption:Option[Iterable[T]] = getIterable(session, name) if (iterableOption.isEmpty) { throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is unavailable, cannot determine list type") } @@ -98,19 +101,21 @@ object SessionCollectionResolver { def getMapClzs[K <: Any, V <: Any](session:Session, name:String):(Class[_ <: K],Class[_ <: V]) = { val sessionKeyOption:Option[Class[K]] = getClz(session, name + "-key-clz") val sessionValOption:Option[Class[V]] = getClz(session, name + "-val-clz") - if (sessionKeyOption.isDefined && sessionValOption.isDefined) { - (sessionKeyOption.get, sessionValOption.get) - } else { - val mapOption:Option[util.Map[K,V]] = getMap(session, name) + sessionKeyOption.flatMap((k) => { + sessionValOption.map((v) => { + (k,v) + }) + }).getOrElse { + val mapOption:Option[Map[K,V]] = getMap(session, name) if (mapOption.isEmpty) { throw new IllegalStateException("Map classes weren't defined in Gatling session and Map is unavailable, cannot determine list type") } - val iterator = mapOption.get.entrySet.iterator + val iterator = mapOption.get.iterator if (!iterator.hasNext) { - throw new IllegalStateException("Map classes wasn't defined in Gatling session and Map is empty, cannot determine list type") + throw new IllegalStateException("Map classes weren't defined in Gatling session and Map is empty, cannot determine list type") } val entry = iterator.next - (entry.getKey.getClass, entry.getValue.getClass) + (entry._1.getClass, entry._2.getClass) } } } From 1658c56c60007c435644133a9cd915a503b5990e Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 28 Jan 2020 17:22:46 -0600 Subject: [PATCH 49/62] Fixing default DC impl + cleaning up handling of memoized Sessions --- .../plugin/base/GatlingCqlSession.scala | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/test/scala/com/datastax/gatling/plugin/base/GatlingCqlSession.scala b/src/test/scala/com/datastax/gatling/plugin/base/GatlingCqlSession.scala index a649fab..93c8c7b 100644 --- a/src/test/scala/com/datastax/gatling/plugin/base/GatlingCqlSession.scala +++ b/src/test/scala/com/datastax/gatling/plugin/base/GatlingCqlSession.scala @@ -1,13 +1,15 @@ package com.datastax.gatling.plugin.base import java.net.InetSocketAddress +import java.util.concurrent.atomic.AtomicReference import com.datastax.oss.driver.api.core.CqlSession import org.cassandraunit.utils.EmbeddedCassandraServerHelper trait GatlingCqlSession { - private var session: CqlSession = _ + // TODO: Probably should eventually be an actor, using AtomicRef for now to cheat + private val session: AtomicReference[CqlSession] = new AtomicReference[CqlSession](null) /** * Create new Dse Session to either the embedded C* instance or a remote instance @@ -18,26 +20,19 @@ trait GatlingCqlSession { * @param cassandraPort Cassandra Port, default will use Embedded Cassandra's port * @return */ - def createCqlSession(cassandraHost: String = "127.0.0.1", cassandraPort: Int = -1): CqlSession = { - - if (session != null) { - return session - } - - var cPort = cassandraPort - if (cPort == -1) { - cPort = EmbeddedCassandraServerHelper.getNativeTransportPort - } - - session = - try { - CqlSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).withLocalDatacenter("datacenter1").build() - } - catch { - case _: Exception => CqlSession.builder().addContactPoint(new InetSocketAddress(cassandraHost, cPort)).build() - } - - session + def createCqlSession(cassandraHost: String = "127.0.0.1", + cassandraPort: Int = EmbeddedCassandraServerHelper.getNativeTransportPort, + localDc:String = "datacenter1"): CqlSession = { + + session.updateAndGet((v) => { + if (v != null) { + v + } + else { + val addr = new InetSocketAddress(cassandraHost, cassandraPort) + CqlSession.builder().addContactPoint(addr).withLocalDatacenter(localDc).build() + } + }) } @@ -47,10 +42,7 @@ trait GatlingCqlSession { * @return */ def getSession: CqlSession = { - if (session == null) { - createCqlSession() - } - session + createCqlSession() } @@ -58,7 +50,7 @@ trait GatlingCqlSession { * Close the current session */ def closeSession(): Unit = { - session.close() + session.getAndSet(null).close() } } From bf767a990dc634430e00569bad2903bfe521014d Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 29 Jan 2020 13:38:46 -0600 Subject: [PATCH 50/62] Fixing exception messages --- .../plugin/utils/CqlPreparedStatementUtil.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index 29e9bac..d32d7a7 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -88,11 +88,11 @@ object SessionCollectionResolver { val iterableOption:Option[Iterable[T]] = getIterable(session, name) if (iterableOption.isEmpty) { - throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is unavailable, cannot determine list type") + throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is unavailable, cannot determine iterable type") } val iterator = iterableOption.get.iterator if (!iterator.hasNext) { - throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is empty, cannot determine list type") + throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is empty, cannot determine iterable type") } iterator.next.getClass } @@ -108,11 +108,13 @@ object SessionCollectionResolver { }).getOrElse { val mapOption:Option[Map[K,V]] = getMap(session, name) if (mapOption.isEmpty) { - throw new IllegalStateException("Map classes weren't defined in Gatling session and Map is unavailable, cannot determine list type") + throw new IllegalStateException( + "Map key/value classes weren't defined in Gatling session and map is unavailable, cannot determine types for map keys or values") } val iterator = mapOption.get.iterator if (!iterator.hasNext) { - throw new IllegalStateException("Map classes weren't defined in Gatling session and Map is empty, cannot determine list type") + throw new IllegalStateException( + "Map key/value classes weren't defined in Gatling session and map is empty, cannot determine types for map keys or values") } val entry = iterator.next (entry._1.getClass, entry._2.getClass) From 41dcc4b93b323299d8e5da526c8108df9f6541d5 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Wed, 29 Jan 2020 14:16:29 -0600 Subject: [PATCH 51/62] Don't bother going to the iterator... just use what Iterable gives us --- .../plugin/utils/CqlPreparedStatementUtil.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index d32d7a7..576d3aa 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -90,11 +90,11 @@ object SessionCollectionResolver { if (iterableOption.isEmpty) { throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is unavailable, cannot determine iterable type") } - val iterator = iterableOption.get.iterator - if (!iterator.hasNext) { + val iterable = iterableOption.get + if (iterable.isEmpty) { throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is empty, cannot determine iterable type") } - iterator.next.getClass + iterable.head.getClass } } @@ -111,12 +111,12 @@ object SessionCollectionResolver { throw new IllegalStateException( "Map key/value classes weren't defined in Gatling session and map is unavailable, cannot determine types for map keys or values") } - val iterator = mapOption.get.iterator - if (!iterator.hasNext) { + val iterable = mapOption.get + if (iterable.isEmpty) { throw new IllegalStateException( "Map key/value classes weren't defined in Gatling session and map is empty, cannot determine types for map keys or values") } - val entry = iterator.next + val entry = iterable.head (entry._1.getClass, entry._2.getClass) } } From 77540177b71a36290950da3654d39640b0fcaa3c Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 30 Jan 2020 15:33:48 -0600 Subject: [PATCH 52/62] Added option to set idempotecy based on an existing boolean val --- .../gatling/plugin/model/DseCqlAttributesBuilder.scala | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index b64ac41..d96f184 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -47,6 +47,14 @@ case class DseCqlAttributesBuilder[T <: Statement[T], B <: StatementBuilder[B,T] def withIdempotency():DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(idempotent = Some(true))) + /** + * Set query to be idempotent i.e. run only once + * + * @return + */ + def withIdempotency(idempotency:Boolean):DseCqlAttributesBuilder[T, B] = + DseCqlAttributesBuilder(attr.copy(idempotent = Some(idempotency))) + /** * Set the node that should handle this query * @param node Node From 803c2c770f789ade51a1e21bf636565b8c8b3d99 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 4 Feb 2020 11:38:45 -0600 Subject: [PATCH 53/62] Addressing PR feedback --- .../plugin/model/DseCqlStatements.scala | 78 +++++++++---------- .../model/CqlStatementBuildersSpec.scala | 8 +- .../plugin/request/CqlRequestActionSpec.scala | 23 +++--- .../request/GraphRequestActionSpec.scala | 20 ++--- 4 files changed, 65 insertions(+), 64 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index 7484a9d..e28e46f 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -8,7 +8,7 @@ package com.datastax.gatling.plugin.model import java.nio.ByteBuffer -import com.datastax.oss.driver.api.core.cql.{BatchStatement => BatchS, BatchStatementBuilder => BatchB, BoundStatement => BoundS, BoundStatementBuilder => BoundB, SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} +import com.datastax.oss.driver.api.core.cql._ import com.datastax.gatling.plugin.exceptions.DseCqlStatementException import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import com.datastax.oss.driver.api.core.`type`.DataType @@ -25,11 +25,11 @@ trait DseCqlStatement[T <: Statement[T], B <: StatementBuilder[B,T]] extends Dse * * @param statement the statement to execute */ -case class DseCqlSimpleStatement(statement: SimpleS) - extends DseCqlStatement[SimpleS, SimpleB] { +case class DseCqlSimpleStatement(statement: SimpleStatement) + extends DseCqlStatement[SimpleStatement, SimpleStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[SimpleB] = { - SimpleS.builder(statement).success + def buildFromSession(gatlingSession: Session): Validation[SimpleStatementBuilder] = { + SimpleStatement.builder(statement).success } } @@ -40,11 +40,11 @@ case class DseCqlSimpleStatement(statement: SimpleS) */ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - builderFn: (BoundS) => BoundB) - extends DseCqlStatement[BoundS, BoundB] { + builderFn: (BoundStatement) => BoundStatementBuilder) + extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[BoundB] = { - val template:BoundS = bindParams( + def buildFromSession(gatlingSession: Session): Validation[BoundStatementBuilder] = { + val template:BoundStatement = bindParams( gatlingSession, preparedStatement.bind(), cqlTypes.getParamsMap(preparedStatement)) @@ -59,8 +59,8 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, * @param queryParams CQL Query Named Params and Types * @return */ - protected def bindParams(gatlingSession: Session, template: BoundS, - queryParams: Map[String, DataType]): BoundS = { + protected def bindParams(gatlingSession: Session, template: BoundStatement, + queryParams: Map[String, DataType]): BoundStatement = { val completedBuilder = queryParams.foldLeft(builderFn(template)) { (builder, kv) => @@ -74,7 +74,7 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, } object DseCqlBoundStatementNamed { - val defaultBuilderFn = (s:BoundS) => new BoundB(s) + val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) def apply(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement):DseCqlBoundStatementNamed = @@ -89,11 +89,11 @@ object DseCqlBoundStatementNamed { */ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - builderFn: (BoundS) => BoundB, + builderFn: (BoundStatement) => BoundStatementBuilder, params: Expression[AnyRef]*) - extends DseCqlStatement[BoundS, BoundB] { + extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[BoundB] = { + def buildFromSession(gatlingSession: Session): Validation[BoundStatementBuilder] = { val parsedParams: Seq[Validation[AnyRef]] = params.map(param => param(gatlingSession)) if (parsedParams.exists(_.isInstanceOf[Failure])) { val firstError = StringBuilder.newBuilder @@ -103,14 +103,14 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt .onFailure(msg => firstError.append(msg)) firstError.toString().failure } else { - val template:BoundS = preparedStatement.bind(parsedParams.map(_.get): _*) + val template:BoundStatement = preparedStatement.bind(parsedParams.map(_.get): _*) builderFn(template).success } } } object DseCqlBoundStatementWithPassedParams { - val defaultBuilderFn = (s:BoundS) => new BoundB(s) + val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) def apply(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, @@ -126,8 +126,8 @@ object DseCqlBoundStatementWithPassedParams { case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, sessionKeys: Seq[String], - builderFn: (BoundS) => BoundB) - extends DseCqlStatement[BoundS, BoundB] { + builderFn: (BoundStatement) => BoundStatementBuilder) + extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { /** * Apply the Gatling session params to the Prepared statement @@ -135,8 +135,8 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param gatlingSession current Gatling session * @return */ - def buildFromSession(gatlingSession: Session): Validation[BoundB] = { - val template:BoundS = bindParams(gatlingSession, preparedStatement.bind(), sessionKeys) + def buildFromSession(gatlingSession: Session): Validation[BoundStatementBuilder] = { + val template:BoundStatement = bindParams(gatlingSession, preparedStatement.bind(), sessionKeys) builderFn(template).success } @@ -148,8 +148,8 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, * @param sessionKeys List of session params to apply, put in order of query ?'s * @return */ - protected def bindParams(gatlingSession: Session, template: BoundS, - sessionKeys: Seq[String]): BoundS = { + protected def bindParams(gatlingSession: Session, template: BoundStatement, + sessionKeys: Seq[String]): BoundStatement = { val params = cqlTypes.getParamsList(preparedStatement) val completedBuilder = sessionKeys.zip(Iterable.range(0,sessionKeys.size)).foldLeft(builderFn(template)) { @@ -163,7 +163,7 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, } object DseCqlBoundStatementWithParamList { - val defaultBuilderFn = (s:BoundS) => new BoundB(s) + val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) def apply(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, @@ -178,11 +178,11 @@ object DseCqlBoundStatementWithParamList { */ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, statements: Seq[PreparedStatement], - builderFn: (BoundS) => BoundB) - extends DseCqlStatement[BatchS, BatchB] { + builderFn: (BoundStatement) => BoundStatementBuilder) + extends DseCqlStatement[BatchStatement, BatchStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[BatchB] = { - val builder:BatchB = BatchS.builder(DefaultBatchType.LOGGED) + def buildFromSession(gatlingSession: Session): Validation[BatchStatementBuilder] = { + val builder:BatchStatementBuilder = BatchStatement.builder(DefaultBatchType.LOGGED) val batchables = statements.map(bindParams(gatlingSession)) builder.addStatements(batchables:_*).success } @@ -194,9 +194,9 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, * @param statement CQL Prepared Statement * @return */ - def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundS = { + def bindParams(gatlingSession: Session)(statement: PreparedStatement): BoundStatement = { val queryParams: Map[String, DataType] = cqlTypes.getParamsMap(statement) - val initBuilder:BoundB = builderFn(statement.bind()) + val initBuilder:BoundStatementBuilder = builderFn(statement.bind()) val completedBuilder = queryParams.foldLeft(initBuilder) { (builder, kv) => @@ -210,7 +210,7 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, } object DseCqlBoundBatchStatement { - val defaultBuilderFn = (s:BoundS) => new BoundB(s) + val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) def apply(cqlTypes: CqlPreparedStatementUtil, statements: Seq[PreparedStatement]):DseCqlBoundBatchStatement = @@ -223,10 +223,10 @@ object DseCqlBoundBatchStatement { * @param statement SimpleStaten * @param payloadRef session variable for custom payload */ -case class DseCqlCustomPayloadStatement(statement: SimpleS, payloadRef: String) - extends DseCqlStatement[SimpleS, SimpleB] { +case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: String) + extends DseCqlStatement[SimpleStatement, SimpleStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[SimpleB] = { + def buildFromSession(gatlingSession: Session): Validation[SimpleStatementBuilder] = { if (!gatlingSession.contains(payloadRef)) { throw new DseCqlStatementException(s"Passed sessionKey: {$payloadRef} does not exist in Session.") } @@ -235,7 +235,7 @@ case class DseCqlCustomPayloadStatement(statement: SimpleS, payloadRef: String) val payload = gatlingSession(payloadRef).as[Map[String, ByteBuffer]].asJava statement.setCustomPayload(payload) } match { - case TrySuccess(stmt) => SimpleS.builder(stmt).success + case TrySuccess(stmt) => SimpleStatement.builder(stmt).success case TryFailure(error) => error.getMessage.failure } } @@ -249,10 +249,10 @@ case class DseCqlCustomPayloadStatement(statement: SimpleS, payloadRef: String) */ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, sessionKey: String, - builderFn: (BoundS) => BoundB) - extends DseCqlStatement[BoundS, BoundB] { + builderFn: (BoundStatement) => BoundStatementBuilder) + extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[BoundB] = { + def buildFromSession(gatlingSession: Session): Validation[BoundStatementBuilder] = { if (!gatlingSession.contains(sessionKey)) { throw new DseCqlStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } @@ -262,7 +262,7 @@ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUt } object DseCqlBoundStatementNamedFromSession { - val defaultBuilderFn = (s:BoundS) => new BoundB(s) + val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) def apply(cqlTypes: CqlPreparedStatementUtil, sessionKey: String):DseCqlBoundStatementNamedFromSession = diff --git a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala index dcf09cf..90ba4d8 100644 --- a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala @@ -6,7 +6,7 @@ import java.time.Duration import com.datastax.gatling.plugin.DsePredef._ import com.datastax.gatling.plugin.checks.CqlChecks import com.datastax.oss.driver.api.core.ConsistencyLevel.{EACH_QUORUM, THREE} -import com.datastax.oss.driver.api.core.cql.{SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} +import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, SimpleStatement, SimpleStatementBuilder} import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.api.core.metadata.token.Token import io.gatling.core.session.{ExpressionSuccessWrapper, Session} @@ -18,7 +18,7 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar it should "build statements from a CQL String" in { - val statementAttributes: DseCqlAttributes[SimpleS,SimpleB] = cql("the-tag") + val statementAttributes: DseCqlAttributes[SimpleStatement,SimpleStatementBuilder] = cql("the-tag") .executeCql("SELECT foo FROM bar.baz LIMIT 1") .build() .dseAttributes @@ -73,8 +73,8 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar } it should "build statements from a SimpleStatement" in { - val statementAttributes: DseCqlAttributes[SimpleS,SimpleB] = cql("the-tag") - .executeStatement(SimpleS.newInstance("Some CQL")) + val statementAttributes: DseCqlAttributes[SimpleStatement,SimpleStatementBuilder] = cql("the-tag") + .executeStatement(SimpleStatement.newInstance("Some CQL")) .build() .dseAttributes val statement = statementAttributes.statement diff --git a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala index 0cff9a8..73a7e74 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/CqlRequestActionSpec.scala @@ -2,7 +2,7 @@ package com.datastax.gatling.plugin.request import java.nio.ByteBuffer import java.time.Duration -import java.util.concurrent.{CompletableFuture, CompletionStage, Executor, TimeUnit} +import java.util.concurrent.{CompletableFuture, CompletionStage} import akka.actor.{ActorSystem, Props} import akka.testkit.TestKitBase @@ -15,8 +15,7 @@ import com.datastax.gatling.plugin.utils.GatlingTimingSource import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.{DseCqlAttributes, DseCqlStatement} import com.datastax.oss.driver.api.core.{ConsistencyLevel, CqlSession} -import com.datastax.oss.driver.api.core.config.DefaultDriverOption -import com.datastax.oss.driver.api.core.cql.{SimpleStatement => SimpleS, SimpleStatementBuilder => SimpleB, _} +import com.datastax.oss.driver.api.core.cql.{AsyncResultSet, SimpleStatement, SimpleStatementBuilder} import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.api.core.metadata.token.Token import io.gatling.commons.validation.SuccessWrapper @@ -32,7 +31,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { implicit lazy val system:ActorSystem = ActorSystem() val gatlingTestConfig: GatlingConfiguration = GatlingConfiguration.loadForTest() val cqlSession: CqlSession = mock[CqlSession] - val dseCqlStatement: DseCqlStatement[SimpleS,SimpleB] = mock[DseCqlStatement[SimpleS,SimpleB]] + val dseCqlStatement: DseCqlStatement[SimpleStatement,SimpleStatementBuilder] = mock[DseCqlStatement[SimpleStatement,SimpleStatementBuilder]] val node:Node = mock[Node] val pageSize = 3 val pagingState: ByteBuffer = mock[ByteBuffer] @@ -44,7 +43,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { val statsEngine: StatsEngine = mock[StatsEngine] val gatlingSession = Session("scenario", 1) - def getTarget(dseAttributes: DseCqlAttributes[SimpleS,SimpleB]): CqlRequestAction[SimpleS,SimpleB] = { + def getTarget(dseAttributes: DseCqlAttributes[SimpleStatement,SimpleStatementBuilder]): CqlRequestAction[SimpleStatement,SimpleStatementBuilder] = { new CqlRequestAction( "sample-dse-request", new Exit(system.actorOf(Props[DseRequestActor]), statsEngine), @@ -68,14 +67,14 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { } describe("CQL") { - val statementCapture = EasyMock.newCapture[SimpleS] + val statementCapture = EasyMock.newCapture[SimpleStatement] it("should have default CQL attributes set if nothing passed") { val cqlAttributesWithDefaults = DseCqlAttributes( "test", dseCqlStatement) expecting { - dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleS.builder("select * from test") + dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleStatement.builder("select * from test") .success) cqlSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() } @@ -85,7 +84,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { } val capturedStatement = statementCapture.getValue - capturedStatement shouldBe a[SimpleS] + capturedStatement shouldBe a[SimpleStatement] capturedStatement.getConsistencyLevel shouldBe null capturedStatement.getSerialConsistencyLevel shouldBe null capturedStatement.getPageSize should be <= 0 @@ -95,7 +94,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { } it("should enable all the CQL Attributes in DseAttributes") { - val cqlAttributes = new DseCqlAttributes[SimpleS,SimpleB]( + val cqlAttributes = new DseCqlAttributes[SimpleStatement,SimpleStatementBuilder]( "test", dseCqlStatement, cl = Some(ConsistencyLevel.ANY), @@ -112,7 +111,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { timeout = Some(timeout)) expecting { - dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleS.builder("select * from test") + dseCqlStatement.buildFromSession(gatlingSession) andReturn(SimpleStatement.builder("select * from test") .success) cqlSession.executeAsync(capture(statementCapture)) andReturn mockAsyncResultSetFuture() } @@ -122,7 +121,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { } val capturedStatement = statementCapture.getValue - capturedStatement shouldBe a[SimpleS] + capturedStatement shouldBe a[SimpleStatement] capturedStatement.getConsistencyLevel shouldBe ConsistencyLevel.ANY capturedStatement.isIdempotent shouldBe true capturedStatement.getNode shouldBe node @@ -150,7 +149,7 @@ class CqlRequestActionSpec extends BaseSpec with TestKitBase { val cqlRequestAction = getTarget(cqlAttributesWithDefaults) - val classLogger = LoggerFactory.getLogger(classOf[CqlRequestAction[SimpleS,SimpleB]]).asInstanceOf[Logger] + val classLogger = LoggerFactory.getLogger(classOf[CqlRequestAction[SimpleStatement,SimpleStatementBuilder]]).asInstanceOf[Logger] val listAppender: ListAppender[ILoggingEvent] = new ListAppender[ILoggingEvent] listAppender.start() classLogger.addAppender(listAppender) diff --git a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala index 3e54a53..5d02568 100644 --- a/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/request/GraphRequestActionSpec.scala @@ -6,13 +6,14 @@ import java.util.concurrent.{CompletableFuture, CompletionStage} import akka.actor.{ActorSystem, Props} import akka.testkit.TestKitBase -import com.datastax.dse.driver.api.core.graph.{ScriptGraphStatement => ScriptS, ScriptGraphStatementBuilder => ScriptB, _} +import com.datastax.dse.driver.api.core.DseSession +import com.datastax.dse.driver.api.core.graph.{AsyncGraphResultSet, ScriptGraphStatement, ScriptGraphStatementBuilder} +import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.base.BaseSpec import com.datastax.gatling.plugin.metrics.NoopMetricsLogger import com.datastax.gatling.plugin.utils.GatlingTimingSource -import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.model.{DseGraphAttributes, DseGraphStatement} -import com.datastax.oss.driver.api.core.{ConsistencyLevel, CqlSession} +import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.metadata.Node import io.gatling.commons.validation.SuccessWrapper import io.gatling.core.action.Exit @@ -25,8 +26,8 @@ import org.easymock.EasyMock._ class GraphRequestActionSpec extends BaseSpec with TestKitBase { implicit lazy val system = ActorSystem() val gatlingTestConfig = GatlingConfiguration.loadForTest() - val cqlSession = mock[CqlSession] - val dseGraphStatement = mock[DseGraphStatement[ScriptS,ScriptB]] + val cqlSession = mock[DseSession] + val dseGraphStatement = mock[DseGraphStatement[ScriptGraphStatement,ScriptGraphStatementBuilder]] val node:Node = mock[Node] val readConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM val subProtocol = "graph-binary-3.0" @@ -39,7 +40,8 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { val statsEngine: StatsEngine = mock[StatsEngine] val gatlingSession = Session("scenario", 1) - def getTarget(dseAttributes: DseGraphAttributes[ScriptS,ScriptB]): GraphRequestAction[ScriptS,ScriptB] = { + def getTarget(dseAttributes: DseGraphAttributes[ScriptGraphStatement,ScriptGraphStatementBuilder]): + GraphRequestAction[ScriptGraphStatement,ScriptGraphStatementBuilder] = { new GraphRequestAction( "sample-dse-request", new Exit(system.actorOf(Props[DseRequestActor]), statsEngine), @@ -64,7 +66,7 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { } describe("Graph") { - val statementCapture = EasyMock.newCapture[ScriptS] + val statementCapture = EasyMock.newCapture[ScriptGraphStatement] it("should enable all the Graph Attributes in DseAttributes") { val graphAttributes = new DseGraphAttributes("test", dseGraphStatement, cl = Some(ConsistencyLevel.ANY), @@ -80,7 +82,7 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { ) expecting { - dseGraphStatement.buildFromSession(gatlingSession) andReturn(ScriptS.builder("g.V()").success) + dseGraphStatement.buildFromSession(gatlingSession) andReturn(ScriptGraphStatement.builder("g.V()").success) cqlSession.executeAsync(capture(statementCapture)) andReturn mockAsyncGraphResultSetFuture() } @@ -89,7 +91,7 @@ class GraphRequestActionSpec extends BaseSpec with TestKitBase { } val capturedStatement = statementCapture.getValue - capturedStatement shouldBe a[ScriptS] + capturedStatement shouldBe a[ScriptGraphStatement] capturedStatement.getConsistencyLevel shouldBe ConsistencyLevel.ANY capturedStatement.isIdempotent shouldBe true capturedStatement.getNode shouldBe node From 568c3a39fa9bda87ea14680bb8162ad29e6474fe Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 4 Feb 2020 12:01:46 -0600 Subject: [PATCH 54/62] More review feedback --- .../model/DseCqlStatementBuilders.scala | 32 ++++++--------- .../model/DseGraphStatementBuilders.scala | 41 +++++++++---------- .../plugin/model/DseGraphStatements.scala | 41 ++++++++----------- 3 files changed, 49 insertions(+), 65 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index eeb16a8..6479181 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -6,15 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.oss.driver.api.core.cql.{ - BatchStatement => BatchS, - BatchStatementBuilder => BatchB, - BoundStatement => BoundS, - BoundStatementBuilder => BoundB, - SimpleStatement => SimpleS, - SimpleStatementBuilder => SimpleB, - _ -} +import com.datastax.oss.driver.api.core.cql._ import com.datastax.gatling.plugin._ import com.datastax.gatling.plugin.utils.CqlPreparedStatementUtil import io.gatling.core.session.Expression @@ -37,7 +29,7 @@ case class DseCqlStatementBuilder(tag: String) { * @return */ @deprecated("Replaced by executeStatement(String)") - def executeCql(query: String): DseCqlAttributesBuilder[SimpleS, SimpleB] = + def executeCql(query: String): DseCqlAttributesBuilder[SimpleStatement, SimpleStatementBuilder] = executeStatement(query) /** @@ -46,8 +38,8 @@ case class DseCqlStatementBuilder(tag: String) { * @param query Simple string query * @return */ - def executeStatement(query: String): DseCqlAttributesBuilder[SimpleS, SimpleB] = - executeStatement(new SimpleB(query).build) + def executeStatement(query: String): DseCqlAttributesBuilder[SimpleStatement, SimpleStatementBuilder] = + executeStatement(new SimpleStatementBuilder(query).build) /** * Execute a Simple Statement @@ -55,7 +47,7 @@ case class DseCqlStatementBuilder(tag: String) { * @param statement SimpleStatement * @return */ - def executeStatement(statement: SimpleS): DseCqlAttributesBuilder[SimpleS, SimpleB] = + def executeStatement(statement: SimpleStatement): DseCqlAttributesBuilder[SimpleStatement, SimpleStatementBuilder] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -98,7 +90,7 @@ case class DseCqlStatementBuilder(tag: String) { * * @param preparedStatement CQL Prepared statement with named parameters */ - def executeNamed(preparedStatement: PreparedStatement): DseCqlAttributesBuilder[BoundS, BoundB] = + def executeNamed(preparedStatement: PreparedStatement): DseCqlAttributesBuilder[BoundStatement, BoundStatementBuilder] = DsePreparedCqlStatementBuilder(tag, preparedStatement).withSessionParams() /** @@ -106,7 +98,7 @@ case class DseCqlStatementBuilder(tag: String) { * * @param preparedStatements Array of prepared statements */ - def executePreparedBatch(preparedStatements: Array[PreparedStatement]): DseCqlAttributesBuilder[BatchS, BatchB] = + def executePreparedBatch(preparedStatements: Array[PreparedStatement]): DseCqlAttributesBuilder[BatchStatement, BatchStatementBuilder] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -122,14 +114,14 @@ case class DseCqlStatementBuilder(tag: String) { * @param payloadSessionKey Session key of the payload from session/feed * @return */ - def executeCustomPayload(statement: SimpleS, payloadSessionKey: String): DseCqlAttributesBuilder[SimpleS, SimpleB] = + def executeCustomPayload(statement: SimpleStatement, payloadSessionKey: String): DseCqlAttributesBuilder[SimpleStatement, SimpleStatementBuilder] = DseCqlAttributesBuilder( DseCqlAttributes( tag, DseCqlCustomPayloadStatement(statement, payloadSessionKey), cqlStatements = Seq(statement.getQuery))) - def executePreparedFromSession(key: String): DseCqlAttributesBuilder[BoundS, BoundB] = + def executePreparedFromSession(key: String): DseCqlAttributesBuilder[BoundStatement, BoundStatementBuilder] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -149,7 +141,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * * @return */ - def withSessionParams(): DseCqlAttributesBuilder[BoundS, BoundB] = + def withSessionParams(): DseCqlAttributesBuilder[BoundStatement, BoundStatementBuilder] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -162,7 +154,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * @param params Gatling Session variables * @return */ - def withParams(params: Expression[AnyRef]*): DseCqlAttributesBuilder[BoundS, BoundB] = + def withParams(params: Expression[AnyRef]*): DseCqlAttributesBuilder[BoundStatement, BoundStatementBuilder] = DseCqlAttributesBuilder( DseCqlAttributes( tag, @@ -176,7 +168,7 @@ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStateme * @param sessionKeys Gatling Session Keys * @return */ - def withParams(sessionKeys: List[String]): DseCqlAttributesBuilder[BoundS, BoundB] = + def withParams(sessionKeys: List[String]): DseCqlAttributesBuilder[BoundStatement, BoundStatementBuilder] = DseCqlAttributesBuilder( DseCqlAttributes( tag, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala index 1959675..ce365f5 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatementBuilders.scala @@ -6,11 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{ - FluentGraphStatement => FluentS, - FluentGraphStatementBuilder => FluentB, - ScriptGraphStatement => ScriptS, - ScriptGraphStatementBuilder => ScriptB} +import com.datastax.dse.driver.api.core.graph.{FluentGraphStatement, FluentGraphStatementBuilder, ScriptGraphStatement, ScriptGraphStatementBuilder} import io.gatling.core.session.{Expression, Session} /** @@ -26,7 +22,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param strStatement Graph Query String * @return */ - def executeGraph(strStatement: Expression[String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = { + def executeGraph(strStatement: Expression[String]): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -40,8 +36,8 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Simple Graph Statement * @return */ - @deprecated("Replaced by executeGraph(ScriptS)") - def executeGraphStatement(gStatement: ScriptS): DseGraphParametrizedStatementBuilder = + @deprecated("Replaced by executeGraph(ScriptGraphStatement)") + def executeGraphStatement(gStatement: ScriptGraphStatement): DseGraphParametrizedStatementBuilder = executeGraph(gStatement) /** @@ -51,8 +47,8 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Simple Graph Statement * @return */ - def executeGraph(gStatement: ScriptS):DseGraphParametrizedStatementBuilder = { - DseGraphParametrizedStatementBuilder(tag, new ScriptB(gStatement)) + def executeGraph(gStatement: ScriptGraphStatement):DseGraphParametrizedStatementBuilder = { + DseGraphParametrizedStatementBuilder(tag, new ScriptGraphStatementBuilder(gStatement)) } /** @@ -61,7 +57,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param gStatement Graph Statement from a Fluent API builder * @return */ - def executeGraphFluent(gStatement: FluentS): DseGraphAttributesBuilder[FluentS, FluentB] = { + def executeGraphFluent(gStatement: FluentGraphStatement): DseGraphAttributesBuilder[FluentGraphStatement, FluentGraphStatementBuilder] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -81,7 +77,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param gLambda The lambda * @return */ - def executeGraphFluent(gLambda: Session => FluentS): DseGraphAttributesBuilder[FluentS, FluentB] = { + def executeGraphFluent(gLambda: Session => FluentGraphStatement): DseGraphAttributesBuilder[FluentGraphStatement, FluentGraphStatementBuilder] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -95,7 +91,7 @@ case class DseGraphStatementBuilder(tag: String) { * @return */ @deprecated("Replaced by executeGraphFluent{session => session(feederKey)}") - def executeGraphFeederTraversal(feederKey: String): DseGraphAttributesBuilder[FluentS, FluentB] = { + def executeGraphFeederTraversal(feederKey: String): DseGraphAttributesBuilder[FluentGraphStatement, FluentGraphStatementBuilder] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -109,7 +105,7 @@ case class DseGraphStatementBuilder(tag: String) { * @param tag Query tag * @param builder Simple Graph Staetment */ -case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { +case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptGraphStatementBuilder) { /** * Included for compatibility @@ -118,7 +114,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { * @return */ @deprecated("Replaced by withParams") - def withSetParams(paramNames: Array[String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = + def withSetParams(paramNames: Array[String]): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = withParams(paramNames.toList) /** @@ -127,7 +123,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { * @param paramNames List of strings to use * @return */ - def withParams(paramNames: String*): DseGraphAttributesBuilder[ScriptS, ScriptB] = + def withParams(paramNames: String*): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = withParams(paramNames.toList) /** @@ -136,7 +132,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { * @param paramNames List of strings to use * @return */ - def withParams(paramNames: List[String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = + def withParams(paramNames: List[String]): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -152,7 +148,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { * @return */ @deprecated("Replaced with withParams") - def withSetParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = + def withSetParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = withParams(paramNamesAndOverrides) @@ -164,7 +160,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { * @return */ @deprecated("Replaced with withParams") - def withParamOverrides(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = + def withParamOverrides(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = withParams(paramNamesAndOverrides) /** @@ -174,7 +170,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { * @param paramNamesAndOverrides a Map of Session parameter names to their GraphStatement parameter names * @return */ - def withParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = { + def withParams(paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = { DseGraphAttributesBuilder( DseGraphAttributes( tag, @@ -191,7 +187,7 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { */ @deprecated("Replaced by withRepeatedParams") def withRepeatedSetParams(batchSize: Int, - paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = + paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = withRepeatedParams(batchSize, paramNamesAndOverrides) /** @@ -202,7 +198,8 @@ case class DseGraphParametrizedStatementBuilder(tag: String, builder: ScriptB) { * @param paramNamesAndOverrides a Map of Session parameter names to their GraphStatement parameter names * @return */ - def withRepeatedParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): DseGraphAttributesBuilder[ScriptS, ScriptB] = { + def withRepeatedParams(batchSize: Int, paramNamesAndOverrides: Map[String, String]): + DseGraphAttributesBuilder[ScriptGraphStatement, ScriptGraphStatementBuilder] = { def repeatParameters(params: Map[String, String]): Map[String, String] = batchSize match { // Gatling has a weird behavior when feeding multiple values // Feeding 1 value gives non-suffixed variables whereas feeding more gives suffixed variables starting by the diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala index 19db3e5..d007af3 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphStatements.scala @@ -6,12 +6,7 @@ package com.datastax.gatling.plugin.model -import com.datastax.dse.driver.api.core.graph.{ - FluentGraphStatement => FluentS, - FluentGraphStatementBuilder => FluentB, - ScriptGraphStatement => ScriptS, - ScriptGraphStatementBuilder => ScriptB, - _} +import com.datastax.dse.driver.api.core.graph._ import com.datastax.gatling.plugin.exceptions.DseGraphStatementException import io.gatling.commons.validation._ import io.gatling.core.session.{Expression, Session} @@ -27,10 +22,10 @@ trait DseGraphStatement[T <: GraphStatement[T], B <: GraphStatementBuilderBase[B * @param statement the Gremlin String to execute */ case class GraphStringStatement(statement: Expression[String]) - extends DseGraphStatement[ScriptS, ScriptB] { + extends DseGraphStatement[ScriptGraphStatement, ScriptGraphStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[ScriptB] = { - statement(gatlingSession).flatMap(stmt => ScriptS.builder(stmt).success) + def buildFromSession(gatlingSession: Session): Validation[ScriptGraphStatementBuilder] = { + statement(gatlingSession).flatMap(stmt => ScriptGraphStatement.builder(stmt).success) } } @@ -39,11 +34,11 @@ case class GraphStringStatement(statement: Expression[String]) * * @param statement the Fluent Statement */ -case class GraphFluentStatement(statement: FluentS) - extends DseGraphStatement[FluentS, FluentB] { +case class GraphFluentStatement(statement: FluentGraphStatement) + extends DseGraphStatement[FluentGraphStatement, FluentGraphStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[FluentB] = { - FluentS.builder(statement).success + def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatementBuilder] = { + FluentGraphStatement.builder(statement).success } } @@ -54,11 +49,11 @@ case class GraphFluentStatement(statement: FluentS) * @param lambda Scala lambda that takes a Gatling User Session (from which it can retrieve parameters) * and returns a fluent Graph Statement */ -case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentS) - extends DseGraphStatement[FluentS, FluentB] { +case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentGraphStatement) + extends DseGraphStatement[FluentGraphStatement, FluentGraphStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[FluentB] = { - FluentS.builder(lambda(gatlingSession)).success + def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatementBuilder] = { + FluentGraphStatement.builder(lambda(gatlingSession)).success } } @@ -69,16 +64,16 @@ case class GraphFluentStatementFromScalaLambda(lambda: Session => FluentS) * @param sessionKey Place a GraphTraversal in your session with this key name */ case class GraphFluentSessionKey(sessionKey: String) - extends DseGraphStatement[FluentS, FluentB] { + extends DseGraphStatement[FluentGraphStatement, FluentGraphStatementBuilder] { - def buildFromSession(gatlingSession: Session): Validation[FluentB] = { + def buildFromSession(gatlingSession: Session): Validation[FluentGraphStatementBuilder] = { if (!gatlingSession.contains(sessionKey)) { throw new DseGraphStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } Try { - FluentS.builder(gatlingSession(sessionKey).as[GraphTraversal[_, _]]) + FluentGraphStatement.builder(gatlingSession(sessionKey).as[GraphTraversal[_, _]]) } match { case TrySuccess(builder) => builder.success case TryFailure(error) => error.getMessage.failure @@ -92,8 +87,8 @@ case class GraphFluentSessionKey(sessionKey: String) * @param builder SimpleGraphStatementBuilder * @param sessionKeys Gatling session param keys mapped to their bind name, to allow name override */ -case class GraphBoundStatement(builder: ScriptB, sessionKeys: Map[String, String]) - extends DseGraphStatement[ScriptS, ScriptB] { +case class GraphBoundStatement(builder: ScriptGraphStatementBuilder, sessionKeys: Map[String, String]) + extends DseGraphStatement[ScriptGraphStatement, ScriptGraphStatementBuilder] { /** * Apply the Gatling session params passed to the GraphStatement @@ -102,7 +97,7 @@ case class GraphBoundStatement(builder: ScriptB, sessionKeys: Map[String, String * @return */ - def buildFromSession(gatlingSession: Session): Validation[ScriptB] = { + def buildFromSession(gatlingSession: Session): Validation[ScriptGraphStatementBuilder] = { Try { sessionKeys foreach { k => k match { From 2991fdd0b7f23aedd37e17520e38c7149f3612d0 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 10 Feb 2020 12:02:35 -0600 Subject: [PATCH 55/62] Code review feedback --- .../gatling/plugin/model/DseCqlAttributes.scala | 3 +++ .../plugin/model/DseCqlAttributesBuilder.scala | 15 +++++++++++++++ .../plugin/model/CqlStatementBuildersSpec.scala | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index 5f7383b..9e61b9d 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -14,6 +14,7 @@ import com.datastax.oss.driver.api.core.ConsistencyLevel import com.datastax.oss.driver.api.core.cql.{Statement, StatementBuilder} import com.datastax.oss.driver.api.core.metadata.Node import com.datastax.oss.driver.api.core.metadata.token.Token +import com.datastax.oss.driver.api.core.time.TimestampGenerator /** * CQL Query Attributes to be applied to the current query @@ -30,6 +31,8 @@ import com.datastax.oss.driver.api.core.metadata.token.Token * @param enableTrace Whether tracing should be enabled * @param pageSize Set pageSize (formerly known as fetchSize) * @param pagingState Set paging State wanted + * @param queryTimestamp Set a timestamp to use for this query. If equal to Some(Long.MIN_VALUE) a timestamp + * will be generated by the configured [[TimestampGenerator]] * @param routingKey Sets the key for token-aware routing * @param routingKeyspace Sets the keyspace for token-aware routing * @param routingToken Sets the token to use for token-aware routing diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index d96f184..122aaf7 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -39,6 +39,21 @@ case class DseCqlAttributesBuilder[T <: Statement[T], B <: StatementBuilder[B,T] def withConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(cl = Some(level))) + /** + * Set custom payload + * + * @param k the key for this custom payload + * @param v the value for this custom payload + * @return + */ + def addCustomPayload(k:String, v:ByteBuffer):DseCqlAttributesBuilder[T, B] = { + val newVal = + attr.customPayload + .orElse(Some(Map[String, ByteBuffer]())) + .map(m => m + (k -> v)) + DseCqlAttributesBuilder(attr.copy(customPayload = newVal)) + } + /** * Set query to be idempotent i.e. run only once * diff --git a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala index 90ba4d8..b4ab03d 100644 --- a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala @@ -31,6 +31,8 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar it should "forward all attributs to DseCqlAttributes" in { val node = mock[Node] + val customPayloadKey = "key" + val customPayloadVal = mock[ByteBuffer] val pagingState = mock[ByteBuffer] val queryTimestamp = 123L val routingKey = mock[ByteBuffer] @@ -41,6 +43,7 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar val statementAttributes: DseCqlAttributes[_,_] = cql("the-session-tag") .executeCql("FOO") .withConsistencyLevel(EACH_QUORUM) + .addCustomPayload(customPayloadKey, customPayloadVal) .withIdempotency() .withNode(node) .withTracingEnabled() @@ -58,6 +61,7 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar statementAttributes.tag should be("the-session-tag") statementAttributes.cl should be(Some(EACH_QUORUM)) statementAttributes.cqlChecks should contain only cqlCheck + statementAttributes.customPayload should be(Some(Map(customPayloadKey -> customPayloadVal))) statementAttributes.idempotent should be(Some(true)) statementAttributes.node should be(Some(node)) statementAttributes.enableTrace should be(Some(true)) From 5929a6de813ad954862174e7d7cf82fb4980499d Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 10 Feb 2020 12:04:46 -0600 Subject: [PATCH 56/62] More code review feedback --- .../model/DseCqlAttributesBuilder.scala | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 122aaf7..956c463 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -158,27 +158,6 @@ case class DseCqlAttributesBuilder[T <: Statement[T], B <: StatementBuilder[B,T] def withTimeout(timeout: Duration):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(timeout = Some(timeout))) - /** - * For backwards compatibility - * - * @param level - * @return - */ - @deprecated("Replaced by withSerialConsistencyLevel") - def serialConsistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T, B] = - withSerialConsistencyLevel(level) - - /** - * Backwards compatibility to set consistencyLevel - * - * @see [[DseCqlAttributesBuilder.withConsistencyLevel]] - * @param level Consistency Level to use - * @return - */ - @deprecated("Replaced by withConsistencyLevel") - def consistencyLevel(level: ConsistencyLevel):DseCqlAttributesBuilder[T, B] = - withConsistencyLevel(level) - def check(check: DseCqlCheck):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(cqlChecks = (attr.cqlChecks :+ check))) } From 0b5172eb26367e31bdf269cb94a2919896eff86e Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 10 Feb 2020 15:42:19 -0600 Subject: [PATCH 57/62] Shifting away from companion objects and towards implicit vals --- .../model/DseCqlStatementBuilders.scala | 4 ++ .../plugin/model/DseCqlStatements.scala | 62 +++---------------- .../gatling/plugin/DseCqlStatementSpec.scala | 14 ++--- 3 files changed, 21 insertions(+), 59 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala index 6479181..fa1aa1c 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatementBuilders.scala @@ -22,6 +22,8 @@ import io.gatling.core.session.Expression */ case class DseCqlStatementBuilder(tag: String) { + implicit val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) + /** * Execute a simple Statement built from a CQL string. * @@ -136,6 +138,8 @@ case class DseCqlStatementBuilder(tag: String) { */ case class DsePreparedCqlStatementBuilder(tag: String, prepared: PreparedStatement) { + implicit val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) + /** * Alias for the behavior of executeNamed function * diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala index e28e46f..9fddc5f 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlStatements.scala @@ -39,8 +39,8 @@ case class DseCqlSimpleStatement(statement: SimpleStatement) * @param preparedStatement the prepared statement on which to bind parameters */ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, - preparedStatement: PreparedStatement, - builderFn: (BoundStatement) => BoundStatementBuilder) + preparedStatement: PreparedStatement) + (implicit builderFn: (BoundStatement) => BoundStatementBuilder) extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { def buildFromSession(gatlingSession: Session): Validation[BoundStatementBuilder] = { @@ -73,14 +73,6 @@ case class DseCqlBoundStatementNamed(cqlTypes: CqlPreparedStatementUtil, } } -object DseCqlBoundStatementNamed { - val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) - - def apply(cqlTypes: CqlPreparedStatementUtil, - preparedStatement: PreparedStatement):DseCqlBoundStatementNamed = - new DseCqlBoundStatementNamed(cqlTypes, preparedStatement, defaultBuilderFn) -} - /** * Bind Gatling session values to the CQL Prepared Statement * @@ -89,8 +81,8 @@ object DseCqlBoundStatementNamed { */ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - builderFn: (BoundStatement) => BoundStatementBuilder, params: Expression[AnyRef]*) + (implicit builderFn: (BoundStatement) => BoundStatementBuilder) extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { def buildFromSession(gatlingSession: Session): Validation[BoundStatementBuilder] = { @@ -109,15 +101,6 @@ case class DseCqlBoundStatementWithPassedParams(cqlTypes: CqlPreparedStatementUt } } -object DseCqlBoundStatementWithPassedParams { - val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) - - def apply(cqlTypes: CqlPreparedStatementUtil, - preparedStatement: PreparedStatement, - params: Expression[AnyRef]*):DseCqlBoundStatementWithPassedParams = - new DseCqlBoundStatementWithPassedParams(cqlTypes, preparedStatement, defaultBuilderFn, params:_*) -} - /** * Bind Gatling session params to the CQL Prepared Statement * @@ -125,8 +108,8 @@ object DseCqlBoundStatementWithPassedParams { */ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, preparedStatement: PreparedStatement, - sessionKeys: Seq[String], - builderFn: (BoundStatement) => BoundStatementBuilder) + sessionKeys: Seq[String]) + (implicit builderFn: (BoundStatement) => BoundStatementBuilder) extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { /** @@ -162,23 +145,14 @@ case class DseCqlBoundStatementWithParamList(cqlTypes: CqlPreparedStatementUtil, } } -object DseCqlBoundStatementWithParamList { - val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) - - def apply(cqlTypes: CqlPreparedStatementUtil, - preparedStatement: PreparedStatement, - sessionKeys: Seq[String]):DseCqlBoundStatementWithParamList = - new DseCqlBoundStatementWithParamList(cqlTypes, preparedStatement, sessionKeys, defaultBuilderFn) -} - /** * Bound CQL Prepared Statement from Named Params * * @param statements CQL Prepared Statements */ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, - statements: Seq[PreparedStatement], - builderFn: (BoundStatement) => BoundStatementBuilder) + statements: Seq[PreparedStatement]) + (implicit builderFn: (BoundStatement) => BoundStatementBuilder) extends DseCqlStatement[BatchStatement, BatchStatementBuilder] { def buildFromSession(gatlingSession: Session): Validation[BatchStatementBuilder] = { @@ -209,14 +183,6 @@ case class DseCqlBoundBatchStatement(cqlTypes: CqlPreparedStatementUtil, } } -object DseCqlBoundBatchStatement { - val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) - - def apply(cqlTypes: CqlPreparedStatementUtil, - statements: Seq[PreparedStatement]):DseCqlBoundBatchStatement = - new DseCqlBoundBatchStatement(cqlTypes, statements, defaultBuilderFn) -} - /** * Set a custom payload on the statement * @@ -248,8 +214,8 @@ case class DseCqlCustomPayloadStatement(statement: SimpleStatement, payloadRef: * @param sessionKey the session key which is associated to a PreparedStatement */ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUtil, - sessionKey: String, - builderFn: (BoundStatement) => BoundStatementBuilder) + sessionKey: String) + (implicit builderFn: (BoundStatement) => BoundStatementBuilder) extends DseCqlStatement[BoundStatement, BoundStatementBuilder] { def buildFromSession(gatlingSession: Session): Validation[BoundStatementBuilder] = { @@ -257,14 +223,6 @@ case class DseCqlBoundStatementNamedFromSession(cqlTypes: CqlPreparedStatementUt throw new DseCqlStatementException(s"Passed sessionKey: {$sessionKey} does not exist in Session.") } val preparedStatement = gatlingSession(sessionKey).as[PreparedStatement] - DseCqlBoundStatementNamed(cqlTypes, preparedStatement, builderFn).buildFromSession(gatlingSession) + DseCqlBoundStatementNamed(cqlTypes, preparedStatement)(builderFn).buildFromSession(gatlingSession) } } - -object DseCqlBoundStatementNamedFromSession { - val defaultBuilderFn = (s:BoundStatement) => new BoundStatementBuilder(s) - - def apply(cqlTypes: CqlPreparedStatementUtil, - sessionKey: String):DseCqlBoundStatementNamedFromSession = - new DseCqlBoundStatementNamedFromSession(cqlTypes, sessionKey, defaultBuilderFn) -} \ No newline at end of file diff --git a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala index 51954a0..9b58156 100644 --- a/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/DseCqlStatementSpec.scala @@ -65,7 +65,7 @@ class DseCqlStatementSpec extends BaseSpec { } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementWithPassedParams(mockCqlTypes, prepared, (_) => mockBuilder, e1, e2) + DseCqlBoundStatementWithPassedParams(mockCqlTypes, prepared, e1, e2)((_) => mockBuilder) .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } @@ -77,7 +77,7 @@ class DseCqlStatementSpec extends BaseSpec { } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - val r = DseCqlBoundStatementWithPassedParams(mockCqlTypes, prepared, e1, e2) + val r = DseCqlBoundStatementWithPassedParams(mockCqlTypes, prepared, e1, e2)((_) => mockBuilder) .buildFromSession(invalidGatlingSession) r shouldBe a[Failure] r shouldBe "No attribute named 'foo' is defined".failure @@ -105,7 +105,7 @@ class DseCqlStatementSpec extends BaseSpec { } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementWithParamList(mockCqlTypes, prepared, validParamList, (_) => mockBuilder) + DseCqlBoundStatementWithParamList(mockCqlTypes, prepared, validParamList)((_) => mockBuilder) .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } @@ -126,7 +126,7 @@ class DseCqlStatementSpec extends BaseSpec { } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementNamed(mockCqlTypes, prepared, (_) => mockBuilder) + DseCqlBoundStatementNamed(mockCqlTypes, prepared)((_) => mockBuilder) .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } @@ -147,7 +147,7 @@ class DseCqlStatementSpec extends BaseSpec { } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { - DseCqlBoundStatementNamedFromSession(mockCqlTypes, "statementKey", (_) => mockBuilder) + DseCqlBoundStatementNamedFromSession(mockCqlTypes, "statementKey")((_) => mockBuilder) .buildFromSession(sessionWithStatement) shouldBe a[Success[_]] } } @@ -157,7 +157,7 @@ class DseCqlStatementSpec extends BaseSpec { } whenExecuting(prepared, mockCqlTypes, mockBoundStatement) { val thrown = intercept[DseCqlStatementException] { - DseCqlBoundStatementNamedFromSession(mockCqlTypes, "statementKey") + DseCqlBoundStatementNamedFromSession(mockCqlTypes, "statementKey")((_) => mockBuilder) .buildFromSession(validGatlingSession) shouldBe a[Failure] } thrown.getMessage shouldBe "Passed sessionKey: {statementKey} does not exist in Session." @@ -180,7 +180,7 @@ class DseCqlStatementSpec extends BaseSpec { } whenExecuting(prepared, mockCqlTypes, mockBoundStatement, mockBuilder) { - DseCqlBoundBatchStatement(mockCqlTypes, Seq(prepared), (_) => mockBuilder) + DseCqlBoundBatchStatement(mockCqlTypes, Seq(prepared))((_) => mockBuilder) .buildFromSession(validGatlingSession) shouldBe a[Success[_]] } } From 3adbda5bd5323e0052df884a2b9edbf2698dc414 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Mon, 10 Feb 2020 16:42:04 -0600 Subject: [PATCH 58/62] Adding docs about the new check API --- .../plugin/checks/DseCheckSupport.scala | 68 ++++++++++++++++++- .../cql/BoundCqlTypesSimulation.scala | 7 +- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala index 6f67438..bef0fb6 100644 --- a/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala +++ b/src/main/scala/com/datastax/gatling/plugin/checks/DseCheckSupport.scala @@ -6,9 +6,75 @@ package com.datastax.gatling.plugin.checks +import com.datastax.dse.driver.api.core.graph.AsyncGraphResultSet +import com.datastax.oss.driver.api.core.cql.AsyncResultSet +import com.datastax.gatling.plugin.utils.ResultSetUtils + +/** + * Make both CQL and Graph checks available to the DSL. + * + * Note that as of 1.3.5 (and the upgrade to the unified OSS driver it brings along) the API here has changed. + * The old check API exposed a rich set of checks for various operations including row counts and validating + * data in individual rows. Several (most?) of these checks were built on the idea that all rows were immediately + * available in memory. This design has changed in 1.3.5, so maintaining the old API would've proven quite difficult + * (if not impossible). Additionally, the rich API shields the user from the intricacies of the driver API at the + * cost of limited flexibility; implementing new functionality requires modifications to the plugin itself (or at + * least an awareness of it's innards). + * + * With 1.3.5 this relationship has been inverted. The check API has been reduced to a single check which makes the + * underlying [[AsyncResultSet]] or [[AsyncGraphResultSet]] available. Simulations can then use transform() to + * extract values and evaluate them as necessary. So, for instance, something like this: + * + * {{{ + * .check(columnValue("counter_type") is 2) + * }}} + * + * now becomes: + * + * {{{ + * .check(resultSet.transform(rs => rs.one().getLong("counter_type")) is 2L) + * }}} + * + * Note that these transforms are now managed as Scala code within the simulations so they can be abstracted and + * built into libraries which can be re-used across simulations. Also note that this abstraction can be implemented + * without modifying the plugin itself. + * + * A similar pattern applies to checks based on metadata. So this: + * + * {{{ + * .check(exhausted is true) + * }}} + * + * now becomes: + * + * {{{ + * .check(resultSet.transform(_.hasMorePages) is false) + * .check(resultSet.transform(_.remaining) is 0) + * }}} + * + * At this point we should also note that checks are now explicitly executed in the order in which hey are declared + * in the simulation. This matters because iterating through rows will impact methods such as remaining(). So, for + * example, if you want to validate that a single row was returned and it contained a specific value you should do + * something like: + * + * {{{ + * .check(resultSet.transform(_.remaining) is 1) + * .check(resultSet.transform(rs => rs.one().getLong("counter_type")) is 2L) + * }}} + * + * and not: + * + * {{{ + * .check(resultSet.transform(rs => rs.one().getLong("counter_type")) is 2L) + * .check(resultSet.transform(_.remaining) is 1) + * }}} + * + * Finally, in general the expectation is that you won't need to realize all rows in a result set, but if for some + * reason you find this necessary this functionality is supplied in [[ResultSetUtils]]. This class also serves as + * an example of the kind of abstraction over common extraction operations discussed above. + */ trait DseCheckSupport { lazy val resultSet = CqlChecks.resultSet lazy val graphResultSet = GraphChecks.resultSet } - diff --git a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala index 4df0ca5..c742a38 100644 --- a/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala +++ b/src/test/scala/com/datastax/gatling/plugin/simulations/cql/BoundCqlTypesSimulation.scala @@ -120,11 +120,6 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { private def preparedCqlPredicate(row:Row):Boolean = row.getBoolean("boolean_type") && row.isNull("null_type") - // In most cases we can simply extract a value from the row and compare that extracted value to an expected value - // via the Gatling API - private def counterCqlExtract(row:Row):Long = - row.getLong("counter_type") - val scn = scenario("BoundCqlStatement") .feed(preparedFeed) @@ -152,7 +147,7 @@ class BoundCqlTypesSimulation extends BaseCqlSimulation { .exec(selectCounterPreparedCql .withParams(List("uuid_type")) .check(resultSet.transform(_.remaining) is 1) - .check(resultSet.transform(rs => counterCqlExtract(rs.one)) is 2L) + .check(resultSet.transform(rs => rs.one().getLong("counter_type")) is 2L) ) .pause(100.millis) From cca2ef9ed1f581f041a9f20694c456baa1265aec Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 11 Feb 2020 11:30:22 -0600 Subject: [PATCH 59/62] Re-adding support for per-request proxy auth --- .../plugin/model/DseCqlAttributes.scala | 2 ++ .../model/DseCqlAttributesBuilder.scala | 8 +++++ .../plugin/model/DseGraphAttributes.scala | 2 ++ .../model/DseGraphAttributesBuilder.scala | 35 +++++++++---------- .../plugin/request/CqlRequestAction.scala | 13 ++++--- .../plugin/request/GraphRequestAction.scala | 13 ++++--- .../model/CqlStatementBuildersSpec.scala | 7 ++-- 7 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala index 9e61b9d..d523c75 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributes.scala @@ -27,6 +27,7 @@ import com.datastax.oss.driver.api.core.time.TimestampGenerator * @param cqlChecks Data-level checks to be run after response is returned * @param idempotent Set request to be idempotent i.e. whether it can be applied multiple times * @param node Set the node that should handle this query + * @param userOrRole Set the user/role for this query if proxy authentication is used * @param customPayload Custom payload for this request * @param enableTrace Whether tracing should be enabled * @param pageSize Set pageSize (formerly known as fetchSize) @@ -50,6 +51,7 @@ case class DseCqlAttributes[T <: Statement[T], B <: StatementBuilder[B,T]] cl: Option[ConsistencyLevel] = None, idempotent: Option[Boolean] = None, node: Option[Node] = None, + userOrRole: Option[String] = None, /* CQL-specific attributes */ customPayload: Option[Map[String, ByteBuffer]] = None, enableTrace: Option[Boolean] = None, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala index 956c463..b9231a4 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseCqlAttributesBuilder.scala @@ -78,6 +78,14 @@ case class DseCqlAttributesBuilder[T <: Statement[T], B <: StatementBuilder[B,T] def withNode(node: Node):DseCqlAttributesBuilder[T, B] = DseCqlAttributesBuilder(attr.copy(node = Some(node))) + /** + * Set the user or role to use for proxy auth + * @param userOrRole String + * @return + */ + def executeAs(userOrRole: String):DseCqlAttributesBuilder[T, B] = + DseCqlAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) + /** * Enable CQL Tracing on the query * diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala index 3000689..4afbe1d 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributes.scala @@ -24,6 +24,7 @@ import com.datastax.oss.driver.api.core.metadata.Node * @param graphChecks Data-level checks to be run after response is returned * @param idempotent Set request to be idempotent i.e. whether it can be applied multiple times * @param node Set the node that should handle this query + * @param userOrRole Set the user/role for this query if proxy authentication is used * @param graphName Name of the graph to use if different from the one used when connecting * @param readCL Consistency level to use for the read part of the query * @param subProtocol Name of the graph protocol to use for encoding/decoding @@ -40,6 +41,7 @@ case class DseGraphAttributes[T <: GraphStatement[T], B <: GraphStatementBuilder cl: Option[ConsistencyLevel] = None, idempotent: Option[Boolean] = None, node: Option[Node] = None, + userOrRole: Option[String] = None, /* Graph-specific attributes */ graphName: Option[String] = None, readCL: Option[ConsistencyLevel] = None, diff --git a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala index 7264756..e13f698 100644 --- a/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala +++ b/src/main/scala/com/datastax/gatling/plugin/model/DseGraphAttributesBuilder.scala @@ -44,6 +44,23 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T], B <: GraphStatement def withIdempotency():DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(idempotent = Some(true))) + /** + * Set the node that should handle this query + * @param node Node + * @return + */ + def withNode(node: Node):DseGraphAttributesBuilder[T, B] = + DseGraphAttributesBuilder(attr.copy(node = Some(node))) + + /** + * Set the user or role to use for proxy auth + * @param userOrRole String + * @return + */ + def executeAs(userOrRole: String):DseGraphAttributesBuilder[T, B] = + DseGraphAttributesBuilder(attr.copy(userOrRole = Some(userOrRole))) + + /** * Sets the graph name to use * @@ -53,14 +70,6 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T], B <: GraphStatement def withName(name: String):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(graphName = Some(name))) - /** - * Set the node that should handle this query - * @param node Node - * @return - */ - def withNode(node: Node):DseGraphAttributesBuilder[T, B] = - DseGraphAttributesBuilder(attr.copy(node = Some(node))) - /** * Define [[ConsistencyLevel]] to be used for read queries * @@ -115,16 +124,6 @@ case class DseGraphAttributesBuilder[T <: GraphStatement[T], B <: GraphStatement def withWriteConsistency(writeCL: ConsistencyLevel):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(writeCL = Some(writeCL))) - /** - * Backwards compatibility to set consistencyLevel - * - * @see [[DseGraphAttributesBuilder.withConsistencyLevel]] - * @param level Consistency Level to use - * @return - */ - @deprecated("use withConsistencyLevel() instead, will be removed in future version") - def consistencyLevel(level: ConsistencyLevel):DseGraphAttributesBuilder[T, B] = withConsistencyLevel(level) - def check(check: DseGraphCheck):DseGraphAttributesBuilder[T, B] = DseGraphAttributesBuilder(attr.copy(graphChecks = check :: attr.graphChecks)) } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala index 8c13c03..fe98e93 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/CqlRequestAction.scala @@ -12,6 +12,7 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem +import com.datastax.dse.driver.api.core.auth.ProxyAuthentication import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.metrics.MetricsLogger import com.datastax.gatling.plugin.model.DseCqlAttributes @@ -91,7 +92,11 @@ class CqlRequestAction[T <: Statement[T], B <: StatementBuilder[B,T]](val name: private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:B): Unit = { - val stmt:T = buildStatement(builder) + val baseStmt:T = buildStatement(builder) + val stmt:T = + dseAttributes.userOrRole + .map(ProxyAuthentication.executeAs(_,baseStmt)) + .getOrElse(baseStmt) val responseHandler = new CqlResponseHandler[T, B]( next, @@ -129,8 +134,8 @@ class CqlRequestAction[T <: Statement[T], B <: StatementBuilder[B,T]](val name: ThroughputVerifier.checkForGatlingOverloading(session, gatlingTimingSource) GatlingResponseTime.startedByGatling(session, gatlingTimingSource) } - val stmt = safely()(dseAttributes.statement.buildFromSession(session)) - stmt.onFailure(handleFailure(session,responseTimeBuilder)) - stmt.onSuccess(handleSuccess(session,responseTimeBuilder)) + val stmtBuilder = safely()(dseAttributes.statement.buildFromSession(session)) + stmtBuilder.onFailure(handleFailure(session,responseTimeBuilder)) + stmtBuilder.onSuccess(handleSuccess(session,responseTimeBuilder)) } } diff --git a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala index 6f606ea..1bfca0e 100644 --- a/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala +++ b/src/main/scala/com/datastax/gatling/plugin/request/GraphRequestAction.scala @@ -12,6 +12,7 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit.MICROSECONDS import akka.actor.ActorSystem +import com.datastax.dse.driver.api.core.auth.ProxyAuthentication import com.datastax.dse.driver.api.core.graph.{GraphStatement, GraphStatementBuilderBase} import com.datastax.gatling.plugin.DseProtocol import com.datastax.gatling.plugin.metrics.MetricsLogger @@ -82,7 +83,11 @@ class GraphRequestAction[T <: GraphStatement[T], B <: GraphStatementBuilderBase[ private def handleSuccess(session: Session, responseTimeBuilder: ResponseTimeBuilder)(builder:B): Unit = { - val stmt:T = buildStatement(builder) + val baseStmt:T = buildStatement(builder) + val stmt:T = + dseAttributes.userOrRole + .map(ProxyAuthentication.executeAs(_,baseStmt)) + .getOrElse(baseStmt) val responseHandler = new GraphResponseHandler[T, B]( next, @@ -121,8 +126,8 @@ class GraphRequestAction[T <: GraphStatement[T], B <: GraphStatementBuilderBase[ ThroughputVerifier.checkForGatlingOverloading(session, gatlingTimingSource) GatlingResponseTime.startedByGatling(session, gatlingTimingSource) } - val stmt = dseAttributes.statement.buildFromSession(session) - stmt.onFailure(handleFailure(session, responseTimeBuilder)) - stmt.onSuccess(handleSuccess(session, responseTimeBuilder)) + val stmtBuilder = dseAttributes.statement.buildFromSession(session) + stmtBuilder.onFailure(handleFailure(session, responseTimeBuilder)) + stmtBuilder.onSuccess(handleSuccess(session, responseTimeBuilder)) } } diff --git a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala index b4ab03d..b3b6189 100644 --- a/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/model/CqlStatementBuildersSpec.scala @@ -19,7 +19,7 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar it should "build statements from a CQL String" in { val statementAttributes: DseCqlAttributes[SimpleStatement,SimpleStatementBuilder] = cql("the-tag") - .executeCql("SELECT foo FROM bar.baz LIMIT 1") + .executeStatement("SELECT foo FROM bar.baz LIMIT 1") .build() .dseAttributes val statement = statementAttributes.statement @@ -31,6 +31,7 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar it should "forward all attributs to DseCqlAttributes" in { val node = mock[Node] + val userOrRole = "userOrRole" val customPayloadKey = "key" val customPayloadVal = mock[ByteBuffer] val pagingState = mock[ByteBuffer] @@ -41,11 +42,12 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar val timeout = Duration.ofHours(1) val cqlCheck = CqlChecks.resultSet.find.is(mock[AsyncResultSet].expressionSuccess).build val statementAttributes: DseCqlAttributes[_,_] = cql("the-session-tag") - .executeCql("FOO") + .executeStatement("FOO") .withConsistencyLevel(EACH_QUORUM) .addCustomPayload(customPayloadKey, customPayloadVal) .withIdempotency() .withNode(node) + .executeAs(userOrRole) .withTracingEnabled() .withPageSize(3) .withPagingState(pagingState) @@ -64,6 +66,7 @@ class CqlStatementBuildersSpec extends FlatSpec with Matchers with EasyMockSugar statementAttributes.customPayload should be(Some(Map(customPayloadKey -> customPayloadVal))) statementAttributes.idempotent should be(Some(true)) statementAttributes.node should be(Some(node)) + statementAttributes.userOrRole should be(Some(userOrRole)) statementAttributes.enableTrace should be(Some(true)) statementAttributes.pageSize should be(Some(3)) statementAttributes.pagingState should be(Some(pagingState)) From 1c69582154ecd29f29fc522c2f9c7ed0746375cb Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Thu, 13 Feb 2020 22:21:47 -0600 Subject: [PATCH 60/62] Some more code review feedback --- .../gatling/plugin/utils/CqlPreparedStatementUtil.scala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index 576d3aa..8773a42 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -58,8 +58,6 @@ object SessionCollectionResolver { }) } - // Note the Java return type here. This function is used to generate objects which will subsequently - // be passed to the Java Bindable impl which is expecting Java Iterators. def getIterable[T <: Any](session:Session, name:String):Option[Iterable[T]] = { get(session,name).flatMap((sessionVal) => { sessionVal match { @@ -70,8 +68,6 @@ object SessionCollectionResolver { }) } - // Note the Java return type here. This function is used to generate objects which will subsequently - // be passed to the Java Bindable impl which is expecting Java Maps. def getMap[K <: Any, V <: Any](session:Session, name:String):Option[Map[K,V]] = { get(session,name).flatMap((sessionVal) => { sessionVal match { From 228a4e8e302f2b294c06900e30605214f35d3ddb Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 10 Mar 2020 11:17:20 -0500 Subject: [PATCH 61/62] Removing support for explicit specification of collection classes in the Gatling session from prepared statement support. Olivier pointed out that the prepared statement itself can serve as a source of truth for type info here. --- .../utils/CqlPreparedStatementUtil.scala | 179 ++++++++---------- .../utils/CqlPreparedStatementUtilSpec.scala | 25 --- 2 files changed, 74 insertions(+), 130 deletions(-) diff --git a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala index 8773a42..6000ccf 100644 --- a/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala +++ b/src/main/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtil.scala @@ -10,7 +10,6 @@ import java.math.BigInteger import java.net.InetAddress import java.nio.ByteBuffer import java.time.{Duration, Instant, LocalDate, LocalTime} -import java.lang import java.util import com.datastax.dse.driver.api.core.data.geometry._ @@ -46,78 +45,6 @@ trait CqlPreparedStatementUtil { def getParamsList(preparedStatement: PreparedStatement): List[DataType] } -object SessionCollectionResolver { - def get(session:Session, name:String):Option[Any] = session.attributes.get(name) - - def getClz[T <: Any](session:Session, name:String):Option[Class[T]] = { - get(session,name).flatMap((sessionVal) => { - sessionVal match { - case clz:Class[T]@unchecked => Option(clz) - case _ => Option.empty - } - }) - } - - def getIterable[T <: Any](session:Session, name:String):Option[Iterable[T]] = { - get(session,name).flatMap((sessionVal) => { - sessionVal match { - case rv:Iterable[T]@unchecked => Option(rv) - case rv:lang.Iterable[T]@unchecked => Option(rv.asScala) - case _ => Option.empty - } - }) - } - - def getMap[K <: Any, V <: Any](session:Session, name:String):Option[Map[K,V]] = { - get(session,name).flatMap((sessionVal) => { - sessionVal match { - case rv:Map[K,V]@unchecked => Option(rv) - case rv:util.Map[K,V]@unchecked => Option(rv.asScala.toMap) - case _ => Option.empty - } - }) - } - - def getIterableClz[T <: Any](session:Session, name:String):Class[_ <: T] = { - val sessionOption:Option[Class[T]] = getClz(session, name + "-clz") - sessionOption.getOrElse { - - val iterableOption:Option[Iterable[T]] = getIterable(session, name) - if (iterableOption.isEmpty) { - throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is unavailable, cannot determine iterable type") - } - val iterable = iterableOption.get - if (iterable.isEmpty) { - throw new IllegalStateException("Iterable element class wasn't defined in Gatling session and Iterable is empty, cannot determine iterable type") - } - iterable.head.getClass - } - } - - def getMapClzs[K <: Any, V <: Any](session:Session, name:String):(Class[_ <: K],Class[_ <: V]) = { - val sessionKeyOption:Option[Class[K]] = getClz(session, name + "-key-clz") - val sessionValOption:Option[Class[V]] = getClz(session, name + "-val-clz") - sessionKeyOption.flatMap((k) => { - sessionValOption.map((v) => { - (k,v) - }) - }).getOrElse { - val mapOption:Option[Map[K,V]] = getMap(session, name) - if (mapOption.isEmpty) { - throw new IllegalStateException( - "Map key/value classes weren't defined in Gatling session and map is unavailable, cannot determine types for map keys or values") - } - val iterable = mapOption.get - if (iterable.isEmpty) { - throw new IllegalStateException( - "Map key/value classes weren't defined in Gatling session and map is empty, cannot determine types for map keys or values") - } - val entry = iterable.head - (entry._1.getClass, entry._2.getClass) - } - } -} - /** * Utilities for CQL Statement building */ @@ -127,18 +54,20 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * Bind CQL Prepared statement params by key order * * @param gatlingSession Gatling Session - * @param bindable CQL Bindable impl + * @param bindable CQL Bindable impl * @param paramType Type of param ie String, int, boolean * @param paramName Gatling Session Attribute Name * @param key Key/Order of param */ def bindParamByOrder[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: DataType, - paramName: String, key: Int): T = { + paramName: String, key: Int): T = { if (!gatlingSession.attributes.contains(paramName)) { return if (bindable.isSet(paramName)) { bindable.unset(paramName) - } else { bindable } + } else { + bindable + } } gatlingSession.attributes.get(paramName) match { @@ -147,7 +76,9 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { case Some(None) => if (bindable.isSet(paramName)) { bindable.unset(paramName) - } else { bindable } + } else { + bindable + } case _ => paramType.getProtocolCode match { case (VARCHAR | ASCII) => @@ -177,16 +108,32 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { case VARINT => bindable.setBigInteger(key, asVarInt(gatlingSession, paramName)) case LIST => - val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) - bindable.setList(key, asList(gatlingSession, paramName, clz), clz) + val dataType = bindable.getType(key) + dataType match { + case l: ListType => { + val memberClz = clzFromCodec(bindable, l.getElementType) + bindable.setList(key, asList(gatlingSession, paramName, memberClz), memberClz) + } + case _ => throw new IllegalStateException("Observed something other than ListType for a LIST param") + } case SET => - val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) - bindable.setSet(key, asSet(gatlingSession, paramName, clz), clz) + val dataType = bindable.getType(key) + dataType match { + case s: SetType => { + val memberClz = clzFromCodec(bindable, s.getElementType) + bindable.setSet(key, asSet(gatlingSession, paramName, memberClz), memberClz) + } + case _ => throw new IllegalStateException("Observed something other than SetType for a SET param") + } case MAP => - val clzs = SessionCollectionResolver.getMapClzs(gatlingSession, paramName) - clzs match { - case (keyClz, valClz) => bindable.setMap(key, asMap(gatlingSession, paramName, keyClz, valClz), keyClz, valClz) - case _ => throw new IllegalStateException("Unexpected value observed when computing map classes") + val dataType = bindable.getType(key) + dataType match { + case m: MapType => { + val keyClz = clzFromCodec(bindable, m.getKeyType) + val valClz = clzFromCodec(bindable, m.getValueType) + bindable.setMap(key, asMap(gatlingSession, paramName, keyClz, valClz), keyClz, valClz) + } + case _ => throw new IllegalStateException("Observed something other than MapType for a MAP param") } case UDT => bindable.setUdtValue(key, asUdt(gatlingSession, paramName)) @@ -221,28 +168,30 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * Bind CQL Prepared statement params by anem * * @param gatlingSession Gatling Session - * @param bindable CQL Bindable impl + * @param bindable CQL Bindable impl * @param paramType Type of param ie String, int, boolean * @param paramName Gatling Session Attribute Value */ def bindParamByName[T <: Bindable[T]](gatlingSession: Session, bindable: T, paramType: DataType, - paramName: String): T = { + paramName: String): T = { if (!gatlingSession.attributes.contains(paramName)) { return if (bindable.isSet(paramName)) { bindable.unset(paramName) - } else { bindable } + } else { + bindable + } } - val stringClz = classOf[String] - gatlingSession.attributes.get(paramName) match { case Some(null) => bindable.setToNull(paramName) case Some(None) => if (bindable.isSet(paramName)) { bindable.unset(paramName) - } else { bindable } + } else { + bindable + } case _ => paramType.getProtocolCode match { case (VARCHAR | ASCII) => @@ -272,16 +221,32 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { case VARINT => bindable.setBigInteger(paramName, asVarInt(gatlingSession, paramName)) case LIST => - val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) - bindable.setList(paramName, asList(gatlingSession, paramName, clz), clz) + val dataType = bindable.getType(paramName) + dataType match { + case l: ListType => { + val memberClz = clzFromCodec(bindable, l.getElementType) + bindable.setList(paramName, asList(gatlingSession, paramName, memberClz), memberClz) + } + case _ => throw new IllegalStateException("Observed something other than ListType for a LIST param") + } case SET => - val clz = SessionCollectionResolver.getIterableClz(gatlingSession, paramName) - bindable.setSet(paramName, asSet(gatlingSession, paramName, clz), clz) + val dataType = bindable.getType(paramName) + dataType match { + case s: SetType => { + val memberClz = clzFromCodec(bindable, s.getElementType) + bindable.setSet(paramName, asSet(gatlingSession, paramName, memberClz), memberClz) + } + case _ => throw new IllegalStateException("Observed something other than SetType for a SET param") + } case MAP => - val clzs = SessionCollectionResolver.getMapClzs(gatlingSession, paramName) - clzs match { - case (keyClz, valClz) => bindable.setMap(paramName, asMap(gatlingSession, paramName, keyClz, valClz), keyClz, valClz) - case _ => throw new IllegalStateException("Unexpected value observed when computing map classes") + val dataType = bindable.getType(paramName) + dataType match { + case m: MapType => { + val keyClz = bindable.codecRegistry().codecFor(m.getKeyType).getJavaType.getRawType.asInstanceOf[Class[Any]] + val valClz = bindable.codecRegistry().codecFor(m.getValueType).getJavaType.getRawType.asInstanceOf[Class[Any]] + bindable.setMap(paramName, asMap(gatlingSession, paramName, keyClz, valClz), keyClz, valClz) + } + case _ => throw new IllegalStateException("Observed something other than MapType for a MAP param") } case UDT => bindable.setUdtValue(paramName, asUdt(gatlingSession, paramName)) @@ -636,11 +601,11 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { * @param paramName CQL prepared statement parameter name * @return */ - def asMap[K,V](gatlingSession: Session, paramName: String, keyType: Class[K], valType: Class[V]): util.Map[K,V] = { + def asMap[K, V](gatlingSession: Session, paramName: String, keyType: Class[K], valType: Class[V]): util.Map[K, V] = { gatlingSession.attributes.get(paramName).flatMap(Option(_)) match { - case Some(m: Map[K,V]@unchecked) => + case Some(m: Map[K, V]@unchecked) => m.asJava - case Some(mj: util.Map[K,V]@unchecked) => + case Some(mj: util.Map[K, V]@unchecked) => mj case _ => throw new CqlTypeException(s"$paramName expected to be type of Set") @@ -678,7 +643,7 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { throw new CqlTypeException(s"$paramName expected to be type of LineString") } } - + /** * Returns CQL compatible Polygon type * @@ -938,9 +903,13 @@ object CqlPreparedStatementUtil extends CqlPreparedStatementUtil { } } - def toLocalDate(epochMillis:Long):LocalDate = { + def toLocalDate(epochMillis: Long): LocalDate = { val end = Instant.ofEpochMilli(epochMillis) - val d = Duration.between(Instant.EPOCH,end) + val d = Duration.between(Instant.EPOCH, end) LocalDate.ofEpochDay(d.toDays) } + + def clzFromCodec(bindable: Bindable[_], genType: DataType): Class[Any] = { + bindable.codecRegistry().codecFor(genType).getJavaType.getRawType.asInstanceOf[Class[Any]] + } } diff --git a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala index 88bf83d..23435c9 100644 --- a/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala +++ b/src/test/scala/com/datastax/gatling/plugin/utils/CqlPreparedStatementUtilSpec.scala @@ -53,21 +53,14 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { "stringDate" -> "2016-10-05", "set" -> Set(1), - "set-clz" -> classOf[Integer], "setString" -> Set("test"), "setJava" -> Set(1).asJava, - "anotherSet" -> Set(1), "list" -> List(1), - "list-clz" -> classOf[Integer], "listJava" -> List(1).asJava, - "anotherList" -> List(1), "map" -> Map(1 -> 1), - "map-key-clz" -> classOf[Integer], - "map-val-clz" -> classOf[Integer], "mapJava" -> Map(1 -> 1).asJava, - "anotherMap" -> Map(1 -> 1), "seq" -> Seq(1), "seqString" -> Seq("test"), @@ -957,36 +950,18 @@ class CqlPreparedStatementUtilSpec extends BaseCassandraServerSpec { result.isSet(14) shouldBe true } - it("should bind with a list when inferring types") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.listOf(DataTypes.INT), "anotherList", 14) - result shouldBe a[BoundStatement] - result.isSet(14) shouldBe true - } - it("should bind with a set") { val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.setOf(DataTypes.INT), "set", 15) result shouldBe a[BoundStatement] result.isSet(15) shouldBe true } - it("should bind with a set when inferring types") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.setOf(DataTypes.INT), "anotherSet", 15) - result shouldBe a[BoundStatement] - result.isSet(15) shouldBe true - } - it("should bind with a map") { val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.mapOf(DataTypes.INT, DataTypes.INT), "map", 16) result shouldBe a[BoundStatement] result.isSet(16) shouldBe true } - it("should bind with a map when inferring types") { - val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.mapOf(DataTypes.INT, DataTypes.INT), "anotherMap", 16) - result shouldBe a[BoundStatement] - result.isSet(16) shouldBe true - } - it("should bind with a date") { val result = CqlPreparedStatementUtil.bindParamByOrder(defaultGatlingSession, boundStatementKeys, DataTypes.DATE, "epoch", 17) result shouldBe a[BoundStatement] From 7d9396a49b66bf93ea457f606dfaf62b64eaac46 Mon Sep 17 00:00:00 2001 From: Bret McGuire Date: Tue, 10 Mar 2020 11:27:03 -0500 Subject: [PATCH 62/62] Driver version bump to 4.5.0 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 0d6e9e9..724b868 100644 --- a/build.sbt +++ b/build.sbt @@ -4,7 +4,7 @@ val gatlingVersion = "2.3.0" scalacOptions += "-target:jvm-1.8" -libraryDependencies += "com.datastax.oss" % "java-driver-core" % "4.4.0" +libraryDependencies += "com.datastax.oss" % "java-driver-core" % "4.5.0" libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "2.18.0" libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.1" libraryDependencies += "org.hdrhistogram" % "HdrHistogram" % "2.1.10"