-
Notifications
You must be signed in to change notification settings - Fork 6
adding support for custom templates #22
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,9 +11,9 @@ import ( | |
"strings" | ||
"syscall" | ||
|
||
"github.com/markbates/pkger" | ||
flag "github.com/spf13/pflag" | ||
|
||
"github.com/intuit/replay-zero/templates" | ||
"github.com/ztrue/shutdown" | ||
) | ||
|
||
|
@@ -31,7 +31,8 @@ var ( | |
listenPort int | ||
defaultTargetPort int | ||
batchSize int | ||
output string | ||
template string | ||
extension string | ||
debug bool | ||
streamRoleArn string | ||
streamName string | ||
|
@@ -81,10 +82,11 @@ func readFlags() { | |
} | ||
flag.BoolVarP(&flags.version, "version", "V", false, "Print version info and exit") | ||
flag.IntVarP(&flags.listenPort, "listen-port", "l", 9000, "The port the Replay Zero proxy will listen on") | ||
flag.IntVarP(&flags.defaultTargetPort, "target-port", "t", 8080, "The port the Replay Zero proxy will forward to on localhost") | ||
flag.IntVarP(&flags.defaultTargetPort, "target-port", "p", 8080, "The port the Replay Zero proxy will forward to on localhost") | ||
flag.BoolVar(&flags.debug, "debug", false, "Set logging to also print debug messages") | ||
flag.IntVarP(&flags.batchSize, "batch-size", "b", 1, "Buffer events before writing out to a file") | ||
flag.StringVarP(&flags.output, "output", "o", "karate", "Either [karate] or [gatling]") | ||
flag.StringVarP(&flags.template, "template", "t", "karate", "Either [karate] or [gatling] or [path/to/custom/template]") | ||
flag.StringVarP(&flags.extension, "extension", "e", "", "For custom output template") | ||
Comment on lines
+88
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will update documentation and add details about them after change is finalised There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See latest review comment for more on docs |
||
flag.StringVarP(&flags.streamName, "stream-name", "s", "", "AWS Kinesis Stream name (streaming mode only)") | ||
flag.StringVarP(&flags.streamRoleArn, "stream-role-arn", "r", "", "AWS Kinesis Stream ARN (streaming mode only)") | ||
flag.Parse() | ||
|
@@ -100,25 +102,61 @@ func readFlags() { | |
} else if flags.batchSize > 1 { | ||
log.Printf("Using fixed batch size of %d\n", flags.batchSize) | ||
} | ||
|
||
// check if template exist at the provided path | ||
// TODO: add validation for correctness of template | ||
if !(flags.template == "karate" || flags.template == "gatling") { | ||
_, err := ioutil.ReadFile(flags.template) | ||
if err != nil { | ||
log.Printf("Failed to load template") | ||
panic(err) | ||
} | ||
if flags.extension == "" { | ||
log.Fatal("For custom template, output extension is expected to be passed using --extension or -e flag.") | ||
os.Exit(0) | ||
} | ||
} | ||
} | ||
|
||
// get embeded template file content | ||
func getPkgTemplate(filePath string) string { | ||
f, err := pkger.Open(filePath) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer f.Close() | ||
info, err := f.Stat() | ||
if err != nil { | ||
panic(err) | ||
} | ||
b := make([]byte, info.Size()) | ||
content, err := f.Read(b) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return string(b[:content]) | ||
} | ||
|
||
func getFormat(output string) outputFormat { | ||
switch output { | ||
func getFormat(template string, extension string) outputFormat { | ||
switch template { | ||
case "karate": | ||
return outputFormat{ | ||
template: templates.KarateBase, | ||
template: getPkgTemplate("/templates/karate_default.template"), | ||
extension: "feature", | ||
} | ||
case "gatling": | ||
return outputFormat{ | ||
template: templates.GatlingBase, | ||
template: getPkgTemplate("/templates/gatling_default.template"), | ||
extension: "scala", | ||
} | ||
default: | ||
log.Printf("Unknown output '%s', defaulting to karate", output) | ||
dat, err := ioutil.ReadFile(template) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return outputFormat{ | ||
template: templates.KarateBase, | ||
extension: "feature", | ||
template: string(dat), | ||
extension: extension, | ||
} | ||
} | ||
} | ||
|
@@ -207,8 +245,8 @@ func main() { | |
log.Println("Running ONLINE, sending recorded events to Kinesis") | ||
h = getOnlineHandler(flags.streamName, flags.streamRoleArn) | ||
} else { | ||
log.Printf("Running OFFLINE, writing out events to %s files\n", flags.output) | ||
h = getOfflineHandler(flags.output) | ||
log.Printf("Running OFFLINE, writing out events to %s files\n", flags.template) | ||
h = getOfflineHandler(flags.template, flags.extension) | ||
} | ||
|
||
shutdown.Add(func() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package com.yourcompany.perf.yourservice | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @wtait1 Do we want to continue to ship with the gatling template? We already have it, so may as well keep it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Celeo My suggestion to this is, that we should stop shipping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @shubhamarora yes I think moving to For packaging the default templates into the binary, there are several tools that do this. I've never personally worked with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @shubhamarora done |
||
|
||
// Generated by Replay Zero at {{ now }} | ||
|
||
import io.gatling.core.Predef._ | ||
import io.gatling.core.structure.ScenarioBuilder | ||
import io.gatling.http.Predef._ | ||
import io.gatling.http.protocol.HttpProtocolBuilder | ||
|
||
class YourServiceBaseline extends Simulation { | ||
|
||
val TP99_RESPONSE_TIME = 1600 | ||
val TP90_RESPONSE_TIME = 800 | ||
val TP50_RESPONSE_TIME = 600 | ||
val AVAILABILITY_RATE = 99 | ||
|
||
val testDuration: Integer = java.lang.Integer.getInteger("duration", 10) | ||
val rampDuration: Integer = java.lang.Integer.getInteger("ramp", 2) | ||
require(rampDuration > 0, "Ramp duration must be a natural number!") | ||
|
||
val steadyStateDuration: Integer = testDuration.intValue() - rampDuration.intValue() | ||
require(steadyStateDuration > 0, "Total test duration must be greater than ramp duration!") | ||
|
||
val initialTps: Int = java.lang.Integer.getInteger("initial", 5) | ||
val steadyStateTps: Int = java.lang.Integer.getInteger("steady", 100) | ||
val host: String = System.getProperty("host", "TODO: put your service's base URL here") | ||
val httpProtocol: HttpProtocolBuilder = http.baseURL(host) | ||
|
||
{{ range $index, $event := . -}} | ||
val scenario_{{$index}}: ScenarioBuilder = scenario("scenario_{{$index}}") | ||
.exec(http("http_{{$index}}")) | ||
.{{lower $event.HTTPMethod}}("{{$event.Endpoint}}") | ||
{{- if gt (len $event.ReqHeaders) 0}} | ||
.headers( | ||
{{- range $h_index, $header := $event.ReqHeaders}} | ||
{{- if $h_index -}},{{end}} | ||
"{{$header.Name}}" = "{{$header.Value}}" | ||
{{- end}} | ||
) | ||
{{- end}} | ||
{{- if $event.ReqBody}} | ||
.body(StringBody( | ||
""" | ||
{{ $event.ReqBody }} | ||
""" | ||
)){{- end }} | ||
|
||
{{ end -}} | ||
{{- println -}} | ||
setUp( | ||
{{- $toSkip := sub (len .) 1}} | ||
{{- range $index, $event := . }} | ||
scenario_{{$index}}.inject(rampUsersPerSec(initialTps) to steadyStateTps during (rampDuration minutes), | ||
constantUsersPerSec(steadyStateTps) during (steadyStateDuration minutes)){{if ne $index $toSkip }},{{end}} | ||
{{- end }} | ||
) | ||
.protocols(httpProtocol) | ||
.assertions( | ||
{{- range $index, $event := . -}} | ||
{{- range $k, $v := dict "1" "99" "2" "90" "3" "50"}} | ||
details("http_{{$index}}").responseTime.percentile{{$k}}.lessThan(TP{{$v}}_RESPONSE_TIME), | ||
{{- end}} | ||
{{- end}} | ||
global.failedRequests.percent.lessThan(100 - AVAILABILITY_RATE) | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Generated by Replay Zero at {{ now }} | ||
Feature: | ||
|
||
Background: | ||
* url 'http://localhost:8080' | ||
{{ range $index, $event := . }} | ||
Scenario: test scenario {{.PairID}} | ||
Given path '{{ $event.Endpoint }}' | ||
{{/* add request headers if present */ -}} | ||
{{ range $header := $event.ReqHeaders -}} | ||
And header {{$header.Name}} = '{{$header.Value}}' | ||
{{end }} | ||
{{- /* add request body if present */ -}} | ||
{{ if $event.ReqBody -}} | ||
And request | ||
""" | ||
{{ $event.ReqBody }} | ||
""" | ||
{{- end }} | ||
|
||
When method {{ $event.HTTPMethod }} | ||
Then status {{ $event.ResponseCode }} | ||
{{/* assert on response headers if present */ -}} | ||
{{ range $header := $event.RespHeaders -}} | ||
And match header {{$header.Name}} == '{{$header.Value}}' | ||
{{end }} | ||
{{- /* assert on response body if present */ -}} | ||
{{ if $event.RespBody -}} | ||
And match response == | ||
""" | ||
{{ $event.RespBody }} | ||
""" | ||
{{- end }} | ||
{{ end }} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to update doc about this, if this is mentioned somewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See latest review comment for more on docs