Skip to content

Commit

Permalink
Make request paths configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
colmsnowplow committed Aug 18, 2023
1 parent f5517fb commit 46cccc4
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,27 @@ final case class Api(vendor: String, version: String) {
}

object Api {
private val GenI = Gen.const(Api("i", ""))
private val GenIce = Gen.const(Api("ice", ".png"))
val GenI = Gen.const(Api("i", ""))
val GenIce = Gen.const(Api("ice", ".png"))

def fixedApis: Gen[Api] = Gen.oneOf(GenI, GenIce)

def genApi(nEvents: Int): Gen[Api] =
(nEvents match {
def genApi(apiType: Int): Gen[Api] =
(apiType match {
case 0 => (genVendor, genVersion)
case 1 => (Gen.const("com.snowplowanalytics.snowplow"), Gen.oneOf("tp1", "tp2"))
case _ => (Gen.const("com.snowplowanalytics.snowplow"), Gen.const("tp2"))
case 1 => (Gen.const("com.snowplowanalytics.snowplow"), Gen.const("tp1"))
case 2 => (Gen.const("com.snowplowanalytics.snowplow"), Gen.const("tp2"))
}).mapN(Api.apply)

private def genVendor =
def genVendor =
for {
venPartsN <- Gen.chooseNum(1, 5)
venNs <- Gen.listOfN(venPartsN, Gen.chooseNum(1, 10))
vendorParts <- Gen.sequence[List[String], String](venNs.map(Gen.stringOfN(_, Gen.alphaNumChar)))
sep <- Gen.oneOf("-", ".", "_", "~")
} yield vendorParts.mkString(sep)

private def genVersion =
def genVersion =
for {
verN <- Gen.chooseNum(1, 10)
version <- Gen.stringOfN(verN, Gen.alphaNumChar)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,44 +33,94 @@ object HttpRequest {
}

case class MethodFrequencies(
get: Int,
post: Int,
head: Int
)
get: Int,
post: Int,
head: Int
)

case class PathFrequencies(
i: Int,
ice: Int,
tp1: Int,
tp2: Int,
random: Int,
providedPath: Option[ProvidedPathFrequency]
)

case class ProvidedPathFrequency(
vendor: String,
version: String,
frequency: Int
)

object Method {
final case class Post(path: Api) extends Method
final case class Get(path: Api) extends Method
final case class Head(path: Api) extends Method

def gen(freq: MethodFrequencies): Gen[Method] = {
def gen(methodFreq: MethodFrequencies, pathFreq: PathFrequencies): Gen[Method] = {
Gen.frequency(
(freq.post, genPost),
(freq.get, genGet),
(freq.head, genHead)
(methodFreq.post, genPost(pathFreq)),
(methodFreq.get, genGet(pathFreq)),
(methodFreq.head, genHead(pathFreq))
)
}

private def genPost: Gen[Method.Post] = Gen.oneOf(genApi(0), genApi(200)).map(Method.Post)
private def genGet: Gen[Method.Get] = Gen.oneOf(fixedApis, genApi(0), genApi(1)).map(Method.Get)
private def genHead: Gen[Method.Head] = Gen.oneOf(fixedApis, genApi(0), genApi(1)).map(Method.Head)
private def genPost(pathFreq: PathFrequencies): Gen[Method.Post] =
Gen.frequency(
pathFreq.providedPath match {
case Some(provided) => (provided.frequency, Api(provided.vendor, provided.version))
case None => (0, Api("", ""))
},
(pathFreq.random, genApi(0)),
(pathFreq.tp2, genApi(2)),
).map(Method.Post)

private def genGet(pathFreq: PathFrequencies): Gen[Method.Get] =
Gen.frequency(
pathFreq.providedPath match {
case Some(provided) => (provided.frequency, Api(provided.vendor, provided.version))
case None => (0, Api("", ""))
},
(pathFreq.i, Api.GenI), // /i
(pathFreq.ice, Api.GenIce), // /ice.png
(pathFreq.random, genApi(0)), // randomly generated path
(pathFreq.tp1, genApi(1)), // /com.snowplowanalytics.snowplow/tp1
(pathFreq.tp2, genApi(2)) // /com.snowplowanalytics.snowplow/tp2
).map(Method.Get)

private def genHead(pathFreq: PathFrequencies): Gen[Method.Head] =
Gen.frequency(
pathFreq.providedPath match {
case Some(provided) => (provided.frequency, Api(provided.vendor, provided.version))
case None => (0, Api("", ""))
},
(pathFreq.i, Api.GenI),
(pathFreq.ice, Api.GenIce),
(pathFreq.random, genApi(0)),
(pathFreq.tp1, genApi(1)),
(pathFreq.tp2, genApi(2))
).map(Method.Head)
}

def gen(
eventPerPayloadMin: Int,
eventPerPayloadMax: Int,
now: Instant,
frequencies: EventFrequencies,
methodFrequencies: Option[MethodFrequencies]
methodFrequencies: Option[MethodFrequencies],
pathFrequencies: Option[PathFrequencies]
): Gen[HttpRequest] = {
// MethodFrequencies is an option here, at the entrypoint in order not to force a breaking change where this is a lib.
// MethodFrequencies and pathFrequencies are options here, at the entrypoint in order not to force a breaking change where this is a lib.
// If it's not provided, we give equal distribution to each to achieve behaviour parity
// From here in it's not an option, just to make the code a bit cleaner
val methodFreq = methodFrequencies.getOrElse(new MethodFrequencies(1, 1, 1))
val pathFreq = pathFrequencies.getOrElse(new PathFrequencies(1,1,1,1,1, None))
genWithParts(
HttpRequestQuerystring.gen(now, frequencies),
HttpRequestBody.gen(eventPerPayloadMin, eventPerPayloadMax, now, frequencies),
methodFreq
methodFreq,
pathFreq
)
}

Expand All @@ -83,25 +133,28 @@ object HttpRequest {
eventPerPayloadMax: Int,
now: Instant,
frequencies: EventFrequencies,
methodFrequencies: Option[MethodFrequencies]
methodFrequencies: Option[MethodFrequencies],
pathFrequencies: Option[PathFrequencies]
): Gen[HttpRequest] = {
// MethodFrequencies is an option here, at the entrypoint in order not to force a breaking change where this is a lib.
// MethodFrequencies and pathFrequencies are options here, at the entrypoint in order not to force a breaking change where this is a lib.
// If it's not provided, we give equal distribution to each to achieve behaviour parity
// From here in it's not an option, just to make the code a bit cleaner
val methodFreq = methodFrequencies.getOrElse(new MethodFrequencies(1, 1, 1))
val pathFreq = pathFrequencies.getOrElse(new PathFrequencies(1,1,1,1,1, None))
genWithParts(
// qs doesn't do duplicates?
HttpRequestQuerystring.gen(now, frequencies),
HttpRequestBody
.genDup(natProb, synProb, natTotal, synTotal, eventPerPayloadMin, eventPerPayloadMax, now, frequencies),
methodFreq
methodFreq,
pathFreq
)
}


private def genWithParts(qsGen: Gen[HttpRequestQuerystring], bodyGen: Gen[HttpRequestBody], methodFreq: MethodFrequencies) =
private def genWithParts(qsGen: Gen[HttpRequestQuerystring], bodyGen: Gen[HttpRequestBody], methodFreq: MethodFrequencies, pathFreq: PathFrequencies) =
for {
method <- Method.gen(methodFreq)
method <- Method.gen(methodFreq, pathFreq)
qs <- Gen.option(qsGen)
body <- method match {
case Method.Head(_) => Gen.const(None) // HEAD requests can't have a message body
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import io.circe.generic.extras.semiauto._

import com.snowplowanalytics.snowplow.eventgen.protocol.event.EventFrequencies
import com.snowplowanalytics.snowplow.eventgen.protocol.event.UnstructEventFrequencies
import com.snowplowanalytics.snowplow.eventgen.tracker.HttpRequest.MethodFrequencies
import com.snowplowanalytics.snowplow.eventgen.tracker.HttpRequest.{MethodFrequencies, PathFrequencies, ProvidedPathFrequency}

final case class Config(
payloadsTotal: Int,
Expand All @@ -43,6 +43,7 @@ final case class Config(
timestamps: Config.Timestamps,
eventFrequencies: EventFrequencies,
methodFrequencies: Option[MethodFrequencies],
pathFrequencies: Option[PathFrequencies],
output: Config.Output
)

Expand Down Expand Up @@ -94,6 +95,12 @@ object Config {
implicit val methodFrequenciesDecoder: Decoder[MethodFrequencies] =
deriveConfiguredDecoder [MethodFrequencies]

implicit val providedPathFrequencyDecoder: Decoder[ProvidedPathFrequency] =
deriveConfiguredDecoder [ProvidedPathFrequency]

implicit val pathFrequenciesDecoder: Decoder[PathFrequencies] =
deriveConfiguredDecoder [PathFrequencies]

implicit val unstructEventFrequenciesDecoder: Decoder[UnstructEventFrequencies] =
deriveConfiguredDecoder[UnstructEventFrequencies]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ object Main extends IOApp {
config.eventPerPayloadMax,
time,
config.eventFrequencies,
config.methodFrequencies
config.methodFrequencies,
config.pathFrequencies
),
rng
)
Expand All @@ -128,7 +129,7 @@ object Main extends IOApp {
),
runGen(
HttpRequest
.gen(config.eventPerPayloadMin, config.eventPerPayloadMax, time, config.eventFrequencies, config.methodFrequencies),
.gen(config.eventPerPayloadMin, config.eventPerPayloadMax, time, config.eventFrequencies, config.methodFrequencies, config.pathFrequencies),
rng
)
)
Expand Down

0 comments on commit 46cccc4

Please sign in to comment.