diff --git a/commands/builds_helper.go b/commands/builds_helper.go index b030724c1c2fed8630910a989f8df92aec1d51eb..e5b9cdf0c93dd7997c97046810398a61f9c74c0f 100644 --- a/commands/builds_helper.go +++ b/commands/builds_helper.go @@ -94,4 +94,4 @@ func (b *buildsHelper) removeBuild(deleteBuild *common.Build) bool { func (b *buildsHelper) buildsCount() int { return len(b.builds) -} \ No newline at end of file +} diff --git a/commands/multi.go b/commands/multi.go index 80a3e27b73e6944489e95c88336b3b1ae3da463f..b02c670f8a63aba3b815658eab0592feca651a56 100644 --- a/commands/multi.go +++ b/commands/multi.go @@ -57,6 +57,9 @@ type RunCommand struct { // runFinished is used to notify that Run() did finish runFinished chan bool + + // statsServingStarted is used to notify that HTTP Statistics Server started serving statistics + statsServingStarted chan bool } func (mr *RunCommand) log() *log.Entry { @@ -240,6 +243,7 @@ func (mr *RunCommand) Start(s service.Service) error { mr.runSignal = make(chan os.Signal, 1) mr.reloadSignal = make(chan os.Signal, 1) mr.runFinished = make(chan bool, 1) + mr.statsServingStarted = make(chan bool, 1) mr.stopSignals = make(chan os.Signal) mr.startedAt = time.Now() mr.log().Println("Starting multi-runner from", mr.ConfigFile, "...") @@ -323,7 +327,7 @@ func (mr *RunCommand) Run() { signal.Notify(mr.stopSignals, syscall.SIGQUIT, syscall.SIGTERM, os.Interrupt, os.Kill) signal.Notify(mr.reloadSignal, syscall.SIGHUP) - statsServer := stats_server.NewStatsServer(mr.statsServerAddress(), mr, mr.runFinished) + statsServer := stats_server.NewStatsServer(mr.statsServerAddress(), mr, mr.runFinished, mr.statsServingStarted) go statsServer.Start() startWorker := make(chan int) diff --git a/helpers/stats_server/stats_server.go b/helpers/stats_server/stats_server.go index 1d55f1d4e3a7c4c2e94b9c4b8f6147c7d6e9f7a3..e730a18ae254225bd0cdad7d6a336e23fe0ee13d 100644 --- a/helpers/stats_server/stats_server.go +++ b/helpers/stats_server/stats_server.go @@ -67,9 +67,10 @@ func (h *StatsHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } type StatsServer struct { - address string - command RunCommand - runFinished chan bool + address string + command RunCommand + runFinished chan bool + servingStarted chan bool } type StatsServerNotEnabledError struct { @@ -113,6 +114,8 @@ func (server *StatsServer) Start() { log.WithField("socket", listener.Addr()).Infoln("Starting StatsServer...") go srv.Serve(listener) + server.servingStarted <- true + <-server.runFinished log.Infoln("Stopping StatsServer...") server.runFinished <- true @@ -144,10 +147,11 @@ func (server *StatsServer) parseAddress() (net, address string, err error) { return } -func NewStatsServer(address string, runCommand RunCommand, runFinished chan bool) *StatsServer { +func NewStatsServer(address string, runCommand RunCommand, runFinished chan bool, servingStarted chan bool) *StatsServer { return &StatsServer{ - address: address, - command: runCommand, - runFinished: runFinished, + address: address, + command: runCommand, + runFinished: runFinished, + servingStarted: servingStarted, } } diff --git a/helpers/stats_server/stats_server_test.go b/helpers/stats_server/stats_server_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5418a912d8f8d2f1114cd316eceb15ae22581a9b --- /dev/null +++ b/helpers/stats_server/stats_server_test.go @@ -0,0 +1,127 @@ +package stats_server + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "testing" + "time" + + log "github.com/Sirupsen/logrus" + + "gitlab.com/gitlab-org/gitlab-ci-multi-runner/common" +) + +func TestStatsDataJSONEncoding(t *testing.T) { + startedAt, _ := time.Parse(time.RFC3339, "2016-07-02T00:01:44+02:00") + configReloadedAt, _ := time.Parse(time.RFC3339, "2016-07-02T00:01:44+02:00") + buildAt, _ := time.Parse(time.RFC3339, "2016-07-02T00:01:28+02:00") + + data := StatsData{ + StartedAt: startedAt, + ConfigReloadedAt: configReloadedAt, + BuildsCount: 5, + RunnersBuildsCounts: map[string]int{ + "abc1234": 3, + "def5678": 2, + }, + Uptime: 0.1234, + VersionInfo: common.AppVersionInfo{ + Name: "gitlab-ci-multi-runner", + Version: "1.3.0~beta.26.gbdcb5e6", + Revision: "bdcb5e6", + Branch: "feature/stats-server", + GOVersion: "go1.6.2", + BuiltAt: buildAt, + OS: "linux", + Architecture: "amd64", + }, + } + + encodedData, _ := json.Marshal(data) + expectedData := []byte("{\"started_at\":\"2016-07-02T00:01:44+02:00\",\"config_reloaded_at\":\"2016-07-02T00:01:44+02:00\",\"builds_count\":5,\"runners_builds_counts\":{\"abc1234\":3,\"def5678\":2},\"uptime\":0.1234,\"version_info\":{\"name\":\"gitlab-ci-multi-runner\",\"version\":\"1.3.0~beta.26.gbdcb5e6\",\"revision\":\"bdcb5e6\",\"branch\":\"feature/stats-server\",\"go_version\":\"go1.6.2\",\"built_at\":\"2016-07-02T00:01:28+02:00\",\"os\":\"linux\",\"architecture\":\"amd64\"}}") + + equal := true + for i := range encodedData { + if encodedData[i] != expectedData[i] { + equal = false + break + } + } + + if !equal { + t.Error("JSON encoding invalid.\nexpected:\n\t", string(expectedData), "\ngot:\n\t", string(encodedData)) + } +} + +var STARTED_AT = "2016-07-02T00:01:44+02:00" +var CONFIG_RELOADED_AT = "2016-07-02T00:01:44+02:00" + +type TestRunCommand struct{} + +func (t *TestRunCommand) StatsData() StatsData { + startedAt, _ := time.Parse(time.RFC3339, STARTED_AT) + configReloadedAt, _ := time.Parse(time.RFC3339, CONFIG_RELOADED_AT) + + return StatsData{ + StartedAt: startedAt, + ConfigReloadedAt: configReloadedAt, + BuildsCount: 5, + RunnersBuildsCounts: map[string]int{ + "abc1234": 3, + "def5678": 2, + }, + } +} + +func TestStatsHandlerPrepare(t *testing.T) { + handler := StatsHandler{ + command: &TestRunCommand{}, + } + statsData := handler.data() + + if statsData.Uptime <= 0 { + t.Error("Uptime should not greather than 0") + } + + if statsData.VersionInfo != common.AppVersion { + t.Error("Version info is invalid\nexpected:\n\t", common.AppVersion, "\ngot:\n\t", statsData.VersionInfo) + } + +} + +func StartServer() (finished, servingStarted chan bool) { + finished = make(chan bool, 1) + servingStarted = make(chan bool, 1) + + server := NewStatsServer("tcp://127.0.0.1:64000", &TestRunCommand{}, finished, servingStarted) + go server.Start() + + return +} + +func TestHTTPServer(t *testing.T) { + finished, servingStarted := StartServer() + + <-servingStarted + log.Errorln("test") + + res, err := http.Get("http://127.0.0.1:64000") + if err != nil { + t.Error(err) + } + + body, err := ioutil.ReadAll(res.Body) + res.Body.Close() + if err != nil { + t.Error(err) + } + + data := &StatsData{} + err = json.Unmarshal(body, data) + if err != nil { + t.Error(err) + } + + finished <- true +}