Skip to content

Commit

Permalink
Adjust timestamp in metrics post requests to account for endpoint's c…
Browse files Browse the repository at this point in the history
…lock offset (CMC-1356) (#78)
  • Loading branch information
itzg committed Feb 6, 2017
1 parent 65c08b1 commit 5e20f1c
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 13 deletions.
7 changes: 4 additions & 3 deletions check/checkresult_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ import (
)

// NewMetricsPostRequest function sets up a request with provided
// check results set data
func NewMetricsPostRequest(crs *ResultSet) *protocol.MetricsPostRequest {
// check results set data. The timestamp within the request will be adjusted for the far-end's clock
// offset given as clockOffset, in milliseconds.
func NewMetricsPostRequest(crs *ResultSet, clockOffset int64) *protocol.MetricsPostRequest {
req := &protocol.MetricsPostRequest{}
req.Version = "1"
req.Method = "check_metrics.post_multi"
Expand All @@ -35,7 +36,7 @@ func NewMetricsPostRequest(crs *ResultSet) *protocol.MetricsPostRequest {
req.Params.MinCheckPeriod = crs.Check.GetPeriod() * 1000
req.Params.State = crs.State
req.Params.Status = crs.Status
req.Params.Timestamp = utils.NowTimestampMillis()
req.Params.Timestamp = utils.NowTimestampMillis() + clockOffset
if crs.Length() == 0 {
req.Params.Metrics = nil
} else {
Expand Down
58 changes: 58 additions & 0 deletions check/checkresult_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// Copyright 2017 Rackspace
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package check_test

import (
"context"
"github.com/racker/rackspace-monitoring-poller/check"
"github.com/racker/rackspace-monitoring-poller/protocol/metric"
"github.com/racker/rackspace-monitoring-poller/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)

func TestNewMetricsPostRequest(t *testing.T) {
checkData := `{
"id":"chTestTCP_TLSRunSuccess",
"zone_id":"pzA",
"entity_id":"enAAAAIPV4",
"details":{"port":443,"ssl":true},
"type":"remote.tcp",
"timeout":15,
"period":30,
"ip_addresses":{"default":"127.0.0.1"},
"target_alias":"default",
"target_hostname":"",
"target_resolver":"",
"disabled":false
}`
ch, err := check.NewCheck(context.Background(), []byte(checkData))
require.NoError(t, err)

cr := check.NewResult(metric.NewMetric("tt_connect", "", metric.MetricNumber, 500, metric.UnitMilliseconds))
crs := check.NewResultSet(ch, cr)

origTimeStamper := utils.InstallAlternateTimestampFunc(func() int64 {
return 5000
})
defer utils.InstallAlternateTimestampFunc(origTimeStamper)

req := check.NewMetricsPostRequest(crs, 200)

assert.Equal(t, int64(5200), req.Params.Timestamp)
}
4 changes: 3 additions & 1 deletion hostinfo/hostinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ func TestHostInfoMemory_PopulateResult(t *testing.T) {
hostInfoMemory := hostinfo.NewHostInfoMemory(hinfo)
result, err := hostInfoMemory.Run()
sourceFrame := &protocol.FrameMsg{}
utils.NowTimestampMillis = func() int64 { return 100 }

origTs := utils.InstallAlternateTimestampFunc(func() int64 { return 100 })
defer utils.InstallAlternateTimestampFunc(origTs)
response := hostinfo.NewHostInfoResponse(result, sourceFrame)
encoded, err := response.Encode()
assert.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion poller/connection_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (cs *EleConnectionStream) SendMetrics(crs *check.ResultSet) error {
}

if conn := cs.conns.ChooseBest(); conn != nil {
conn.GetSession().Send(check.NewMetricsPostRequest(crs))
conn.GetSession().Send(check.NewMetricsPostRequest(crs, conn.GetClockOffset()))
}

return nil
Expand Down
1 change: 1 addition & 0 deletions poller/connection_stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func TestEleConnectionStream_SendMetrics_Normal(t *testing.T) {

c2 := poller.NewMockConnection(ctrl)
c2.EXPECT().GetLatency().AnyTimes().Return(int64(10))
c2.EXPECT().GetClockOffset().AnyTimes().Return(int64(0))
c2.EXPECT().GetSession().Return(mockSession)

c3 := poller.NewMockConnection(ctrl)
Expand Down
1 change: 1 addition & 0 deletions poller/connection_stream_whitebox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ func TestConnectionStream_SendMetrics(t *testing.T) {
defer mockCtrl.Finish()
mockSession := NewMockSession(mockCtrl)
mockSession.EXPECT().GetLatency().AnyTimes().Return(int64(0))
mockSession.EXPECT().GetClockOffset().AnyTimes().Return(int64(0))
ctx := context.Background()

basicCheck, err := check.NewCheck(ctx, []byte(`{
Expand Down
14 changes: 6 additions & 8 deletions poller/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,13 @@ func (fm frameMatcher) String() string {
}

func installDeterministicTimestamper(startingTimestamp, timestampInc int64) utils.NowTimestampMillisFunc {
origTimestamper := utils.NowTimestampMillis
mockTimestamp := startingTimestamp
utils.NowTimestampMillis = func() int64 {

return utils.InstallAlternateTimestampFunc(func() int64 {
ts := mockTimestamp
mockTimestamp += timestampInc
return ts
}

return origTimestamper
})
}

func prepareHandshakeResponse(heartbeatInterval uint64, readsHere io.Writer) {
Expand Down Expand Up @@ -126,7 +124,7 @@ func TestEleSession_HeartbeatSending(t *testing.T) {
defer readsHere.Close()

origTimestamper := installDeterministicTimestamper(1000, 2000)
defer func() { utils.NowTimestampMillis = origTimestamper }()
defer utils.InstallAlternateTimestampFunc(origTimestamper)

const heartbeatInterval = 10 // ms

Expand Down Expand Up @@ -168,7 +166,7 @@ func TestEleSession_HeartbeatConsumption(t *testing.T) {
defer readsHere.Close()

origTimestamper := installDeterministicTimestamper(1000, 2000)
defer func() { utils.NowTimestampMillis = origTimestamper }()
defer utils.InstallAlternateTimestampFunc(origTimestamper)

const heartbeatInterval = 10 // ms

Expand Down Expand Up @@ -409,7 +407,7 @@ func TestEleSession_PollerPrepare(t *testing.T) {
defer readsHere.Close()

origTimestamper := installDeterministicTimestamper(1000, 2000)
defer func() { utils.NowTimestampMillis = origTimestamper }()
defer utils.InstallAlternateTimestampFunc(origTimestamper)

es := poller.NewSession(context.Background(), eleConn, reconciler, &config.Config{})
defer es.Close()
Expand Down
8 changes: 8 additions & 0 deletions utils/timestamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ var NowTimestampMillis NowTimestampMillisFunc = func() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}

// InstallAlternateTimestampFunc is intended for unit testing where a deterministic timestamp needs to be
// temporarily enabled. Be sure to defer re-invoke this function to re-install the prior one.
func InstallAlternateTimestampFunc(newFunc NowTimestampMillisFunc) (priorFunc NowTimestampMillisFunc) {
priorFunc = NowTimestampMillis
NowTimestampMillis = newFunc
return
}

// ScaleFractionalDuration is primarily useful when scaling durations that are "sub second", but more generally
// it's when duration is smaller than targetUnits. In that case, a fractional value is much more meangingful than
// a 0, which is what would happen with plain duration (i.e. integer) division. targetUnits should really be
Expand Down

0 comments on commit 5e20f1c

Please sign in to comment.