Skip to content
This repository has been archived by the owner on Oct 17, 2018. It is now read-only.

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
xichen2020 committed Apr 6, 2017
1 parent 4a4959b commit 82b5b6c
Show file tree
Hide file tree
Showing 11 changed files with 1,877 additions and 303 deletions.
2 changes: 1 addition & 1 deletion generated/proto/rule.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ message Namespace {

message Namespaces {
repeated Namespace namespaces = 1;
}
}
28 changes: 13 additions & 15 deletions rules/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ package rules

import (
"errors"
"time"

"github.com/m3db/m3metrics/filters"
"github.com/m3db/m3metrics/generated/proto/schema"
Expand All @@ -46,7 +45,7 @@ type mappingRuleSnapshot struct {

func newMappingRuleSnapshot(
r *schema.MappingRuleSnapshot,
iterfn filters.NewSortedTagIteratorFn,
iterFn filters.NewSortedTagIteratorFn,
) (*mappingRuleSnapshot, error) {
if r == nil {
return nil, errNilMappingRuleSnapshotSchema
Expand All @@ -55,7 +54,7 @@ func newMappingRuleSnapshot(
if err != nil {
return nil, err
}
filter, err := filters.NewTagsFilter(r.TagFilters, iterfn, filters.Conjunction)
filter, err := filters.NewTagsFilter(r.TagFilters, iterFn, filters.Conjunction)
if err != nil {
return nil, err
}
Expand All @@ -76,14 +75,14 @@ type mappingRule struct {

func newMappingRule(
mc *schema.MappingRule,
iterfn filters.NewSortedTagIteratorFn,
iterFn filters.NewSortedTagIteratorFn,
) (*mappingRule, error) {
if mc == nil {
return nil, errNilMappingRuleSchema
}
snapshots := make([]*mappingRuleSnapshot, 0, len(mc.Snapshots))
for i := 0; i < len(mc.Snapshots); i++ {
mr, err := newMappingRuleSnapshot(mc.Snapshots[i], iterfn)
mr, err := newMappingRuleSnapshot(mc.Snapshots[i], iterFn)
if err != nil {
return nil, err
}
Expand All @@ -96,19 +95,19 @@ func newMappingRule(
}

// ActiveSnapshot returns the latest snapshot whose cutover time is earlier than or
// equal to t, or nil if not found.
func (mc *mappingRule) ActiveSnapshot(t time.Time) *mappingRuleSnapshot {
idx := mc.activeIndex(t)
// equal to timeNs, or nil if not found.
func (mc *mappingRule) ActiveSnapshot(timeNs int64) *mappingRuleSnapshot {
idx := mc.activeIndex(timeNs)
if idx < 0 {
return nil
}
return mc.snapshots[idx]
}

// ActiveRule returns the rule containing snapshots that's in effect at time t and
// all future snapshots after time t.
func (mc *mappingRule) ActiveRule(t time.Time) *mappingRule {
idx := mc.activeIndex(t)
// ActiveRule returns the rule containing snapshots that's in effect at time timeNs
// and all future snapshots after time timeNs.
func (mc *mappingRule) ActiveRule(timeNs int64) *mappingRule {
idx := mc.activeIndex(timeNs)
// If there are no snapshots that are currently in effect, it means either all
// snapshots are in the future, or there are no snapshots.
if idx < 0 {
Expand All @@ -117,10 +116,9 @@ func (mc *mappingRule) ActiveRule(t time.Time) *mappingRule {
return &mappingRule{uuid: mc.uuid, snapshots: mc.snapshots[idx:]}
}

func (mc *mappingRule) activeIndex(t time.Time) int {
target := t.UnixNano()
func (mc *mappingRule) activeIndex(timeNs int64) int {
idx := 0
for idx < len(mc.snapshots) && mc.snapshots[idx].cutoverNs <= target {
for idx < len(mc.snapshots) && mc.snapshots[idx].cutoverNs <= timeNs {
idx++
}
idx--
Expand Down
142 changes: 142 additions & 0 deletions rules/mapping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,145 @@
// THE SOFTWARE.

package rules

import (
"testing"
"time"

"github.com/m3db/m3metrics/generated/proto/schema"
"github.com/m3db/m3metrics/policy"
"github.com/m3db/m3x/time"

"github.com/stretchr/testify/require"
)

var (
testMappingRuleSchema = &schema.MappingRule{
Uuid: "12669817-13ae-40e6-ba2f-33087b262c68",
Snapshots: []*schema.MappingRuleSnapshot{
&schema.MappingRuleSnapshot{
Name: "foo",
Tombstoned: false,
CutoverTime: 12345,
TagFilters: map[string]string{
"tag1": "value1",
"tag2": "value2",
},
Policies: []*schema.Policy{
&schema.Policy{
Resolution: &schema.Resolution{
WindowSize: int64(10 * time.Second),
Precision: int64(time.Second),
},
Retention: &schema.Retention{
Period: int64(24 * time.Hour),
},
},
},
},
&schema.MappingRuleSnapshot{
Name: "bar",
Tombstoned: true,
CutoverTime: 67890,
TagFilters: map[string]string{
"tag3": "value3",
"tag4": "value4",
},
Policies: []*schema.Policy{
&schema.Policy{
Resolution: &schema.Resolution{
WindowSize: int64(time.Minute),
Precision: int64(time.Minute),
},
Retention: &schema.Retention{
Period: int64(24 * time.Hour),
},
},
&schema.Policy{
Resolution: &schema.Resolution{
WindowSize: int64(5 * time.Minute),
Precision: int64(time.Minute),
},
Retention: &schema.Retention{
Period: int64(48 * time.Hour),
},
},
},
},
},
}
)

func TestMappingRuleSnapshotNilSchema(t *testing.T) {
_, err := newMappingRuleSnapshot(nil, nil)
require.Equal(t, err, errNilMappingRuleSnapshotSchema)
}

func TestNewMappingRuleNilSchema(t *testing.T) {
_, err := newMappingRule(nil, nil)
require.Equal(t, err, errNilMappingRuleSchema)
}

func TestNewMappingRule(t *testing.T) {
mr, err := newMappingRule(testMappingRuleSchema, nil)
require.NoError(t, err)
require.Equal(t, "12669817-13ae-40e6-ba2f-33087b262c68", mr.uuid)
expectedSnapshots := []struct {
name string
tombstoned bool
cutoverNs int64
policies []policy.Policy
}{
{
name: "foo",
tombstoned: false,
cutoverNs: 12345,
policies: []policy.Policy{
policy.NewPolicy(10*time.Second, xtime.Second, 24*time.Hour),
},
},
{
name: "bar",
tombstoned: true,
cutoverNs: 67890,
policies: []policy.Policy{
policy.NewPolicy(time.Minute, xtime.Minute, 24*time.Hour),
policy.NewPolicy(5*time.Minute, xtime.Minute, 48*time.Hour),
},
},
}
for i, snapshot := range expectedSnapshots {
require.Equal(t, snapshot.name, mr.snapshots[i].name)
require.Equal(t, snapshot.tombstoned, mr.snapshots[i].tombstoned)
require.Equal(t, snapshot.cutoverNs, mr.snapshots[i].cutoverNs)
require.Equal(t, snapshot.policies, mr.snapshots[i].policies)
}
}

func TestMappingRuleActiveSnapshotNotFound(t *testing.T) {
mr, err := newMappingRule(testMappingRuleSchema, nil)
require.NoError(t, err)
require.Nil(t, mr.ActiveSnapshot(0))
}

func TestMappingRuleActiveSnapshotFound(t *testing.T) {
mr, err := newMappingRule(testMappingRuleSchema, nil)
require.NoError(t, err)
require.Equal(t, mr.snapshots[1], mr.ActiveSnapshot(100000))
}

func TestMappingRuleActiveRuleNotFound(t *testing.T) {
mr, err := newMappingRule(testMappingRuleSchema, nil)
require.NoError(t, err)
require.Equal(t, mr, mr.ActiveRule(0))
}

func TestMappingRuleActiveRuleFound(t *testing.T) {
mr, err := newMappingRule(testMappingRuleSchema, nil)
require.NoError(t, err)
expected := &mappingRule{
uuid: mr.uuid,
snapshots: mr.snapshots[1:],
}
require.Equal(t, expected, mr.ActiveRule(100000))
}
12 changes: 6 additions & 6 deletions rules/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var (

// Namespace is a logical isolation unit for which rules are defined.
type Namespace struct {
name string
name []byte
tombstoned bool
expireAtNs int64
}
Expand All @@ -47,14 +47,14 @@ func newNameSpace(namespace *schema.Namespace) (Namespace, error) {
return emptyNamespace, errNilNamespaceSchema
}
return Namespace{
name: namespace.Name,
name: []byte(namespace.Name),
tombstoned: namespace.Tombstoned,
expireAtNs: namespace.ExpireAt,
}, nil
}

// Name is the name of the namespace.
func (n *Namespace) Name() string { return n.name }
func (n *Namespace) Name() []byte { return n.name }

// Tombstoned determines whether the namespace has been tombstoned.
func (n *Namespace) Tombstoned() bool { return n.tombstoned }
Expand Down Expand Up @@ -87,8 +87,8 @@ func NewNamespaces(version int, namespaces *schema.Namespaces) (Namespaces, erro
}, nil
}

// Namespaces returns the list of namespaces.
func (nss Namespaces) Namespaces() []Namespace { return nss.namespaces }

// Version returns the namespaces version.
func (nss Namespaces) Version() int { return nss.version }

// Namespaces returns the list of namespaces.
func (nss Namespaces) Namespaces() []Namespace { return nss.namespaces }
83 changes: 83 additions & 0 deletions rules/namespace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package rules

import (
"testing"

"github.com/m3db/m3metrics/generated/proto/schema"

"github.com/stretchr/testify/require"
)

func TestNewNamespaceNilSchema(t *testing.T) {
_, err := newNameSpace(nil)
require.Equal(t, err, errNilNamespaceSchema)
}

func TestNewNamespaceValidSchema(t *testing.T) {
ns, err := newNameSpace(&schema.Namespace{
Name: "foo",
Tombstoned: false,
ExpireAt: 12345,
})
require.NoError(t, err)
require.Equal(t, []byte("foo"), ns.Name())
require.Equal(t, false, ns.Tombstoned())
require.Equal(t, int64(12345), ns.ExpireAtNs())
}

func TestNewNamespacesNilSchema(t *testing.T) {
_, err := NewNamespaces(1, nil)
require.Equal(t, errNilNamespacesSchema, err)
}

func TestNewNamespacesValidSchema(t *testing.T) {
ns, err := NewNamespaces(1, &schema.Namespaces{
Namespaces: []*schema.Namespace{
&schema.Namespace{
Name: "foo",
Tombstoned: false,
ExpireAt: 12345,
},
&schema.Namespace{
Name: "bar",
Tombstoned: true,
ExpireAt: 67890,
},
},
})
require.NoError(t, err)
require.Equal(t, 1, ns.Version())
expected := []Namespace{
{
name: b("foo"),
tombstoned: false,
expireAtNs: 12345,
},
{
name: b("bar"),
tombstoned: true,
expireAtNs: 67890,
},
}
require.Equal(t, expected, ns.Namespaces())
}
2 changes: 1 addition & 1 deletion rules/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func newMatchResult(
}

// HasExpired returns whether the match result has expired for a given time.
func (r *MatchResult) HasExpired(t time.Time) bool { return r.expireAtNs >= t.UnixNano() }
func (r *MatchResult) HasExpired(t time.Time) bool { return r.expireAtNs <= t.UnixNano() }

// NumRollups returns the number of rollup result associated with the given id.
func (r *MatchResult) NumRollups() int { return len(r.rollups) }
Expand Down

0 comments on commit 82b5b6c

Please sign in to comment.