Skip to content

Commit

Permalink
Proper handling of cloud settings
Browse files Browse the repository at this point in the history
- Name figured out based on options object or filename
- Cloud project can be selected in options object
- Duration send to cloud takes -D parameter into consideration
  • Loading branch information
martinfijal authored and robingustafsson committed May 10, 2017
1 parent af32c77 commit 1e23b14
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 27 deletions.
2 changes: 1 addition & 1 deletion run.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func makeCollector(s string, src *lib.SourceData, opts lib.Options) (lib.Collect
case "json":
return json.New(p, afero.NewOsFs(), opts)
case "cloud":
return cloud.New(p, opts)
return cloud.New(p, src, opts)
default:
return nil, errors.New("Unknown output type: " + t)
}
Expand Down
10 changes: 4 additions & 6 deletions stats/cloud/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ func (c *Client) Do(req *http.Request, v interface{}) error {
}

type TestRun struct {
Name string `json:"name"`
ProjectID int `json:"project_id,omitempty"`
Threasholds map[string][]string `json:"thresholds"`
Name string `json:"name"`
ProjectID int `json:"project_id,omitempty"`
Thresholds map[string][]string `json:"thresholds"`
// Duration of test in seconds. -1 for unknown length, 0 for continuous running.
Duration int64 `json:"duration"`
}
Expand All @@ -98,9 +98,7 @@ type CreateTestRunResponse struct {
ReferenceID string `json:"reference_id"`
}

func (c *Client) CreateTestRun(name string, thresholds map[string][]string, duration int64) *CreateTestRunResponse {
testRun := TestRun{Name: name, Threasholds: thresholds, Duration: duration}

func (c *Client) CreateTestRun(testRun *TestRun) *CreateTestRunResponse {
url := fmt.Sprintf("%s/tests", c.baseURL)
req, err := c.NewRequest("POST", url, testRun)
if err != nil {
Expand Down
115 changes: 95 additions & 20 deletions stats/cloud/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,47 @@ import (
"context"
"fmt"
"os"
"strconv"
"time"

"path/filepath"

log "github.com/Sirupsen/logrus"
"github.com/loadimpact/k6/lib"
"github.com/loadimpact/k6/stats"

"github.com/mitchellh/mapstructure"
)

type loadimpactConfig struct {
ProjectId int `mapstructure:"project_id"`
Name string `mapstructure:"name"`
}

// Collector sends results data to the Load Impact cloud service.
type Collector struct {
referenceID string

name string
project_id int

duration int64
thresholds map[string][]string
client *Client
}

func New(fname string, opts lib.Options) (*Collector, error) {
referenceID := os.Getenv("K6CLOUD_REFERENCEID")
// New creates a new cloud collector
func New(fname string, src *lib.SourceData, opts lib.Options) (*Collector, error) {
token := os.Getenv("K6CLOUD_TOKEN")

var extConfig loadimpactConfig
if val, ok := opts.External["loadimpact"]; ok == true {
err := mapstructure.Decode(val, &extConfig)
if err != nil {
// For now we ignore if loadimpact section is malformed
}
}

thresholds := make(map[string][]string)

for name, t := range opts.Thresholds {
Expand All @@ -36,46 +57,64 @@ func New(fname string, opts lib.Options) (*Collector, error) {
var duration int64 = -1
if len(opts.Stages) > 0 {
duration = sumStages(opts.Stages)
} else if opts.Duration.Valid {
// Parse duration if no stages found
dur, err := time.ParseDuration(opts.Duration.String)
// ignore error and keep default -1 value
if err == nil {
duration = int64(dur.Seconds())
}
}

return &Collector{
referenceID: referenceID,
thresholds: thresholds,
client: NewClient(token),
duration: duration,
name: getName(src, extConfig),
project_id: getProjectId(extConfig),
thresholds: thresholds,
client: NewClient(token),
duration: duration,
}, nil
}

func (c *Collector) Init() {
name := os.Getenv("K6CLOUD_NAME")
if name == "" {
name = "k6 test"
testRun := &TestRun{
Name: c.name,
Thresholds: c.thresholds,
Duration: c.duration,
ProjectID: c.project_id,
}

// TODO fix this and add proper error handling
if c.referenceID == "" {
response := c.client.CreateTestRun(name, c.thresholds, c.duration)
if response != nil {
c.referenceID = response.ReferenceID
}
response := c.client.CreateTestRun(testRun)
if response != nil {
c.referenceID = response.ReferenceID
} else {
log.Warn("Failed to create test in Load Impact cloud")
}

log.WithFields(log.Fields{
"name": c.name,
"projectId": c.project_id,
"duration": c.duration,
"referenceId": c.referenceID,
}).Debug("Cloud collector init")
}

func (c *Collector) String() string {
return fmt.Sprintf("Load Impact (https://app.staging.loadimpact.com/k6/runs/%s)", c.referenceID)
}

func (c *Collector) Run(ctx context.Context) {
t := time.Now()
<-ctx.Done()
s := time.Now()

c.client.TestFinished(c.referenceID)

log.Debug(fmt.Sprintf("http://localhost:5000/v1/metrics/%s/%d000/%d000\n", c.referenceID, t.Unix(), s.Unix()))
if c.referenceID != "" {
c.client.TestFinished(c.referenceID)
}
}

func (c *Collector) Collect(samples []stats.Sample) {
if c.referenceID == "" {
return
}

var cloudSamples []*Sample
for _, sample := range samples {
Expand All @@ -92,7 +131,7 @@ func (c *Collector) Collect(samples []stats.Sample) {
cloudSamples = append(cloudSamples, sampleJSON)
}

if len(cloudSamples) > 0 && c.referenceID != "" {
if len(cloudSamples) > 0 {
c.client.PushMetric(c.referenceID, cloudSamples)
}
}
Expand All @@ -105,3 +144,39 @@ func sumStages(stages []lib.Stage) int64 {

return int64(total.Seconds())
}

func getProjectId(extConfig loadimpactConfig) int {
env := os.Getenv("K6CLOUD_PROJECTID")
if env != "" {
id, err := strconv.Atoi(env)
if err == nil && id > 0 {
return id
}
}

if extConfig.ProjectId > 0 {
return extConfig.ProjectId
}

return 0
}

func getName(src *lib.SourceData, extConfig loadimpactConfig) string {
envName := os.Getenv("K6CLOUD_NAME")
if envName != "" {
return envName
}

if extConfig.Name != "" {
return extConfig.Name
}

if src.Filename != "" {
name := filepath.Base(src.Filename)
if name != "" || name != "." {
return name
}
}

return "k6 test"
}

0 comments on commit 1e23b14

Please sign in to comment.