Skip to content

Commit

Permalink
lib/scheduler/calls: rewrite Roles() option for Revive/Suppress calls
Browse files Browse the repository at this point in the history
  • Loading branch information
James DeFelice committed Sep 14, 2017
1 parent 5a646fb commit d4f22c6
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 111 deletions.
64 changes: 23 additions & 41 deletions api/v1/lib/scheduler/calls/calls.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,57 +200,39 @@ func OpDestroy(rs ...mesos.Resource) mesos.Offer_Operation {
}
}

// Roles decorates Revive and Suppress calls; panics for any other call type.
func Roles(roles ...string) scheduler.CallOpt {
return func(c *scheduler.Call) {
if c == nil {
return
}
switch c.Type {
case scheduler.Call_REVIVE:
if c.Revive == nil {
if len(roles) == 0 {
return
}
c.Revive = new(scheduler.Call_Revive)
}
if len(roles) == 0 {
c.Revive.Roles = nil
} else {
c.Revive.Roles = roles
}
case scheduler.Call_SUPPRESS:
if c.Suppress == nil {
if len(roles) == 0 {
return
}
c.Suppress = new(scheduler.Call_Suppress)
}
if len(roles) == 0 {
c.Suppress.Roles = nil
} else {
c.Suppress.Roles = roles
}
default:
panic("Roles doesn't support call type " + c.Type.String())
}
}
// OfferFlowControl is a marker interface for Call subtypes that adjust offer throttling.
type OfferFlowControl interface {
SetRoles(roles ...string)
}

// OfferFlowOpt configures OfferFlowControl.
type OfferFlowOpt func(OfferFlowControl)

// Roles configures the roles for an OfferFlowControl.
func Roles(roles ...string) OfferFlowOpt { return func(ofc OfferFlowControl) { ofc.SetRoles(roles...) } }

// Revive returns a revive call.
// Callers are expected to fill in the FrameworkID.
func Revive() *scheduler.Call {
return &scheduler.Call{
Type: scheduler.Call_REVIVE,
func Revive(opts ...OfferFlowOpt) (c *scheduler.Call) {
c = &scheduler.Call{Type: scheduler.Call_REVIVE, Revive: &scheduler.Call_Revive{}}
for _, f := range opts {
if f != nil {
f(c.Revive)
}
}
return
}

// Suppress returns a suppress call.
// Callers are expected to fill in the FrameworkID.
func Suppress() *scheduler.Call {
return &scheduler.Call{
Type: scheduler.Call_SUPPRESS,
func Suppress(opts ...OfferFlowOpt) (c *scheduler.Call) {
c = &scheduler.Call{Type: scheduler.Call_SUPPRESS, Suppress: &scheduler.Call_Suppress{}}
for _, f := range opts {
if f != nil {
f(c.Suppress)
}
}
return
}

// Decline returns a decline call with the given parameters.
Expand Down
93 changes: 23 additions & 70 deletions api/v1/lib/scheduler/calls/calls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,91 +5,44 @@ import (
"reflect"
"testing"

"github.com/gogo/protobuf/proto"
"github.com/mesos/mesos-go/api/v1/lib/scheduler"
"github.com/mesos/mesos-go/api/v1/lib/scheduler/calls"
)

func TestRole(t *testing.T) {
type outcome int
const (
outcomeChanged = outcome(iota)
outcomePanic
outcomeUnchanged
)
var (
rolesNone []string
roleX = []string{"x"}
roleY = []string{"y"}
)
for ti, tc := range []struct {
call *scheduler.Call
roles []string
outcome outcome
call *scheduler.Call
roles []string
}{
{nil, rolesNone, outcomeUnchanged},
{nil, roleX, outcomeUnchanged},
{&scheduler.Call{}, rolesNone, outcomePanic},
{&scheduler.Call{}, roleX, outcomePanic},
{&scheduler.Call{Type: scheduler.Call_SUBSCRIBE}, rolesNone, outcomePanic},
{&scheduler.Call{Type: scheduler.Call_SUBSCRIBE}, roleX, outcomePanic},

{&scheduler.Call{Type: scheduler.Call_REVIVE}, rolesNone, outcomeUnchanged},
{&scheduler.Call{Type: scheduler.Call_REVIVE, Revive: &scheduler.Call_Revive{}}, rolesNone, outcomeUnchanged},
{&scheduler.Call{Type: scheduler.Call_SUPPRESS}, rolesNone, outcomeUnchanged},
{&scheduler.Call{Type: scheduler.Call_SUPPRESS, Suppress: &scheduler.Call_Suppress{}}, rolesNone, outcomeUnchanged},

{&scheduler.Call{Type: scheduler.Call_REVIVE}, roleX, outcomeChanged},
{&scheduler.Call{Type: scheduler.Call_REVIVE, Revive: &scheduler.Call_Revive{}}, roleX, outcomeChanged},
{&scheduler.Call{Type: scheduler.Call_SUPPRESS}, roleX, outcomeChanged},
{&scheduler.Call{Type: scheduler.Call_SUPPRESS, Suppress: &scheduler.Call_Suppress{}}, roleX, outcomeChanged},
{calls.Revive(calls.Roles()), rolesNone},
{calls.Suppress(calls.Roles()), rolesNone},

{&scheduler.Call{Type: scheduler.Call_REVIVE, Revive: &scheduler.Call_Revive{Roles: roleY}}, roleX, outcomeChanged},
{&scheduler.Call{Type: scheduler.Call_SUPPRESS, Suppress: &scheduler.Call_Suppress{Roles: roleY}}, roleX, outcomeChanged},

{&scheduler.Call{Type: scheduler.Call_REVIVE, Revive: &scheduler.Call_Revive{Roles: roleY}}, rolesNone, outcomeChanged},
{&scheduler.Call{Type: scheduler.Call_SUPPRESS, Suppress: &scheduler.Call_Suppress{Roles: roleY}}, rolesNone, outcomeChanged},
{calls.Revive(calls.Roles(roleX...)), roleX},
{calls.Suppress(calls.Roles(roleX...)), roleX},
} {
var (
caught interface{}
before = proto.Clone(tc.call).(*scheduler.Call)
)
func() {
defer func() {
caught = recover()
}()
_ = tc.call.With(calls.Roles(tc.roles...))
}()
switch tc.outcome {
case outcomePanic:
if caught == nil {
t.Errorf("test case %d failed: expected panic", ti)
roles, hasRole := func() ([]string, bool) {
switch tc.call.Type {
case scheduler.Call_SUPPRESS:
return tc.call.Suppress.GetRoles(), len(tc.call.Suppress.Roles) > 0
case scheduler.Call_REVIVE:
return tc.call.Revive.GetRoles(), len(tc.call.Revive.Roles) > 0
default:
panic(fmt.Sprintf("test case %d failed: unsupported call type: %v", ti, tc.call.Type))
}
case outcomeUnchanged:
if !reflect.DeepEqual(before, tc.call) {
t.Errorf("test case %d failed: expected unchanged call instead of: %#v ", ti, tc.call)
}
case outcomeChanged:
roles, hasRole := func() ([]string, bool) {
switch tc.call.Type {
case scheduler.Call_SUPPRESS:
return tc.call.Suppress.GetRoles(), len(tc.call.Suppress.Roles) > 0
case scheduler.Call_REVIVE:
return tc.call.Revive.GetRoles(), len(tc.call.Revive.Roles) > 0
default:
panic(fmt.Sprintf("test case %d failed: unsupported call type: %v", ti, tc.call.Type))
}
}()
if hasRole != (len(tc.roles) > 0) {
if hasRole {
t.Errorf("test case %d failed: expected no role instead of %q", ti, roles)
} else {
t.Errorf("test case %d failed: expected role %q instead of no role", ti, tc.roles)
}
}
if hasRole && !reflect.DeepEqual(tc.roles, roles) {
t.Errorf("test case %d failed: expected role %q instead of %q", ti, tc.roles, roles)
}()
if hasRole != (len(tc.roles) > 0) {
if hasRole {
t.Errorf("test case %d failed: expected no role instead of %q", ti, roles)
} else {
t.Errorf("test case %d failed: expected role %q instead of no role", ti, tc.roles)
}
}
if hasRole && !reflect.DeepEqual(tc.roles, roles) {
t.Errorf("test case %d failed: expected role %q instead of %q", ti, tc.roles, roles)
}
}
}
14 changes: 14 additions & 0 deletions api/v1/lib/scheduler/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,17 @@ func (co CallOptions) Copy() CallOptions {
copy(x, co)
return x
}

// SetRoles implements calls.OfferFlowControl
func (c *Call_Revive) SetRoles(roles ...string) {
if c != nil {
c.Roles = roles
}
}

// SetRoles implements calls.OfferFlowControl
func (c *Call_Suppress) SetRoles(roles ...string) {
if c != nil {
c.Roles = roles
}
}

0 comments on commit d4f22c6

Please sign in to comment.