mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 12:18:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			729 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			729 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// +build linux
 | 
						|
 | 
						|
/*
 | 
						|
Copyright 2015 The Kubernetes Authors.
 | 
						|
 | 
						|
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 bandwidth
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"reflect"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						|
	"k8s.io/utils/exec"
 | 
						|
	fakeexec "k8s.io/utils/exec/testing"
 | 
						|
)
 | 
						|
 | 
						|
var tcClassOutput = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
`
 | 
						|
 | 
						|
var tcClassOutput2 = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
class htb 1:5 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b 
 | 
						|
`
 | 
						|
 | 
						|
func TestNextClassID(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		output    string
 | 
						|
		expectErr bool
 | 
						|
		expected  int
 | 
						|
		err       error
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			output:   tcClassOutput,
 | 
						|
			expected: 5,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			output:   "\n",
 | 
						|
			expected: 1,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			expected:  -1,
 | 
						|
			expectErr: true,
 | 
						|
			err:       errors.New("test error"),
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, test := range tests {
 | 
						|
		fcmd := fakeexec.FakeCmd{
 | 
						|
			CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
				func() ([]byte, []byte, error) { return []byte(test.output), nil, test.err },
 | 
						|
			},
 | 
						|
		}
 | 
						|
		fexec := fakeexec.FakeExec{
 | 
						|
			CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
				func(cmd string, args ...string) exec.Cmd {
 | 
						|
					return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}
 | 
						|
		shaper := &tcShaper{e: &fexec}
 | 
						|
		class, err := shaper.nextClassID()
 | 
						|
		if test.expectErr {
 | 
						|
			if err == nil {
 | 
						|
				t.Errorf("unexpected non-error")
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if err != nil {
 | 
						|
				t.Errorf("unexpected error: %v", err)
 | 
						|
			}
 | 
						|
			if class != test.expected {
 | 
						|
				t.Errorf("expected: %d, found %d", test.expected, class)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestHexCIDR(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name      string
 | 
						|
		input     string
 | 
						|
		output    string
 | 
						|
		expectErr bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:   "IPv4 masked",
 | 
						|
			input:  "1.2.3.4/16",
 | 
						|
			output: "01020000/ffff0000",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "IPv4 host",
 | 
						|
			input:  "172.17.0.2/32",
 | 
						|
			output: "ac110002/ffffffff",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "IPv6 masked",
 | 
						|
			input:  "2001:dead:beef::cafe/64",
 | 
						|
			output: "2001deadbeef00000000000000000000/ffffffffffffffff0000000000000000",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "IPv6 host",
 | 
						|
			input:  "2001::5/128",
 | 
						|
			output: "20010000000000000000000000000005/ffffffffffffffffffffffffffffffff",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:      "invalid CIDR",
 | 
						|
			input:     "foo",
 | 
						|
			expectErr: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, test := range tests {
 | 
						|
		output, err := hexCIDR(test.input)
 | 
						|
		if test.expectErr {
 | 
						|
			if err == nil {
 | 
						|
				t.Errorf("case %s: unexpected non-error", test.name)
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if err != nil {
 | 
						|
				t.Errorf("case %s: unexpected error: %v", test.name, err)
 | 
						|
			}
 | 
						|
			if output != test.output {
 | 
						|
				t.Errorf("case %s: expected: %s, saw: %s",
 | 
						|
					test.name, test.output, output)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestAsciiCIDR(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name      string
 | 
						|
		input     string
 | 
						|
		output    string
 | 
						|
		expectErr bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:   "IPv4",
 | 
						|
			input:  "01020000/ffff0000",
 | 
						|
			output: "1.2.0.0/16",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "IPv4 host",
 | 
						|
			input:  "ac110002/ffffffff",
 | 
						|
			output: "172.17.0.2/32",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "IPv6",
 | 
						|
			input:  "2001deadbeef00000000000000000000/ffffffffffffffff0000000000000000",
 | 
						|
			output: "2001:dead:beef::/64",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "IPv6 host",
 | 
						|
			input:  "20010000000000000000000000000005/ffffffffffffffffffffffffffffffff",
 | 
						|
			output: "2001::5/128",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:      "invalid CIDR",
 | 
						|
			input:     "malformed",
 | 
						|
			expectErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:      "non-hex IP",
 | 
						|
			input:     "nonhex/32",
 | 
						|
			expectErr: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:      "non-hex mask",
 | 
						|
			input:     "01020000/badmask",
 | 
						|
			expectErr: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, test := range tests {
 | 
						|
		output, err := asciiCIDR(test.input)
 | 
						|
		if test.expectErr {
 | 
						|
			if err == nil {
 | 
						|
				t.Errorf("case %s: unexpected non-error", test.name)
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if err != nil {
 | 
						|
				t.Errorf("case %s: unexpected error: %v", test.name, err)
 | 
						|
			}
 | 
						|
			if output != test.output {
 | 
						|
				t.Errorf("case %s: expected: %s, saw: %s",
 | 
						|
					test.name, test.output, output)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
var tcFilterOutput = `filter parent 1: protocol ip pref 1 u32 
 | 
						|
filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1 
 | 
						|
filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 
 | 
						|
  match ac110002/ffffffff at 16
 | 
						|
filter parent 1: protocol ip pref 1 u32 fh 800::801 order 2049 key ht 800 bkt 0 flowid 1:2 
 | 
						|
  match 01020000/ffff0000 at 16
 | 
						|
`
 | 
						|
var tcFilterOutputNewVersion = `filter parent 1: protocol ip pref 1 u32
 | 
						|
filter parent 1: protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1
 | 
						|
filter parent 1: protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 not_in_hw
 | 
						|
  match ac110002/ffffffff at 16
 | 
						|
filter parent 1: protocol ip pref 1 u32 chain 0 fh 800::801 order 2049 key ht 800 bkt 0 flowid 1:2 not_in_hw
 | 
						|
  match 01020000/ffff0000 at 16
 | 
						|
`
 | 
						|
 | 
						|
func TestFindCIDRClass(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		cidr           string
 | 
						|
		output         string
 | 
						|
		expectErr      bool
 | 
						|
		expectNotFound bool
 | 
						|
		expectedClass  string
 | 
						|
		expectedHandle string
 | 
						|
		err            error
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			cidr:           "172.17.0.2/32",
 | 
						|
			output:         tcFilterOutput,
 | 
						|
			expectedClass:  "1:1",
 | 
						|
			expectedHandle: "800::800",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:           "1.2.3.4/16",
 | 
						|
			output:         tcFilterOutput,
 | 
						|
			expectedClass:  "1:2",
 | 
						|
			expectedHandle: "800::801",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:           "2.2.3.4/16",
 | 
						|
			output:         tcFilterOutput,
 | 
						|
			expectNotFound: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:           "172.17.0.2/32",
 | 
						|
			output:         tcFilterOutputNewVersion,
 | 
						|
			expectedClass:  "1:1",
 | 
						|
			expectedHandle: "800::800",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:           "1.2.3.4/16",
 | 
						|
			output:         tcFilterOutputNewVersion,
 | 
						|
			expectedClass:  "1:2",
 | 
						|
			expectedHandle: "800::801",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:           "2.2.3.4/16",
 | 
						|
			output:         tcFilterOutputNewVersion,
 | 
						|
			expectNotFound: true,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			err:       errors.New("test error"),
 | 
						|
			expectErr: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, test := range tests {
 | 
						|
		fcmd := fakeexec.FakeCmd{
 | 
						|
			CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
				func() ([]byte, []byte, error) { return []byte(test.output), nil, test.err },
 | 
						|
			},
 | 
						|
		}
 | 
						|
		fexec := fakeexec.FakeExec{
 | 
						|
			CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
				func(cmd string, args ...string) exec.Cmd {
 | 
						|
					return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}
 | 
						|
		shaper := &tcShaper{e: &fexec}
 | 
						|
		classAndHandle, found, err := shaper.findCIDRClass(test.cidr)
 | 
						|
		if test.expectErr {
 | 
						|
			if err == nil {
 | 
						|
				t.Errorf("unexpected non-error")
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if err != nil {
 | 
						|
				t.Errorf("unexpected error: %v", err)
 | 
						|
			}
 | 
						|
			if test.expectNotFound {
 | 
						|
				if found {
 | 
						|
					t.Errorf("unexpectedly found an interface: %s", classAndHandle)
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				if classAndHandle[0][0] != test.expectedClass {
 | 
						|
					t.Errorf("expected class: %s, found %s", test.expectedClass, classAndHandle)
 | 
						|
				}
 | 
						|
				if classAndHandle[0][1] != test.expectedHandle {
 | 
						|
					t.Errorf("expected handle: %s, found %s", test.expectedHandle, classAndHandle)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestGetCIDRs(t *testing.T) {
 | 
						|
	fcmd := fakeexec.FakeCmd{
 | 
						|
		CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
			func() ([]byte, []byte, error) { return []byte(tcFilterOutput), nil, nil },
 | 
						|
		},
 | 
						|
	}
 | 
						|
	fexec := fakeexec.FakeExec{
 | 
						|
		CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
			func(cmd string, args ...string) exec.Cmd {
 | 
						|
				return fakeexec.InitFakeCmd(&fcmd, cmd, args...)
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	shaper := &tcShaper{e: &fexec}
 | 
						|
	cidrs, err := shaper.GetCIDRs()
 | 
						|
	if err != nil {
 | 
						|
		t.Errorf("unexpected error: %v", err)
 | 
						|
	}
 | 
						|
	expectedCidrs := []string{"172.17.0.2/32", "1.2.0.0/16"}
 | 
						|
	if !reflect.DeepEqual(cidrs, expectedCidrs) {
 | 
						|
		t.Errorf("expected: %v, saw: %v", expectedCidrs, cidrs)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestLimit(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		cidr          string
 | 
						|
		ingress       *resource.Quantity
 | 
						|
		egress        *resource.Quantity
 | 
						|
		expectErr     bool
 | 
						|
		expectedCalls int
 | 
						|
		err           error
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			cidr:          "1.2.3.4/32",
 | 
						|
			ingress:       resource.NewQuantity(10, resource.DecimalSI),
 | 
						|
			egress:        resource.NewQuantity(20, resource.DecimalSI),
 | 
						|
			expectedCalls: 6,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:          "1.2.3.4/32",
 | 
						|
			ingress:       resource.NewQuantity(10, resource.DecimalSI),
 | 
						|
			egress:        nil,
 | 
						|
			expectedCalls: 3,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:          "1.2.3.4/32",
 | 
						|
			ingress:       nil,
 | 
						|
			egress:        resource.NewQuantity(20, resource.DecimalSI),
 | 
						|
			expectedCalls: 3,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:          "1.2.3.4/32",
 | 
						|
			ingress:       nil,
 | 
						|
			egress:        nil,
 | 
						|
			expectedCalls: 0,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			err:       errors.New("test error"),
 | 
						|
			ingress:   resource.NewQuantity(10, resource.DecimalSI),
 | 
						|
			egress:    resource.NewQuantity(20, resource.DecimalSI),
 | 
						|
			expectErr: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		fcmd := fakeexec.FakeCmd{
 | 
						|
			CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
				func() ([]byte, []byte, error) { return []byte(tcClassOutput), nil, test.err },
 | 
						|
				func() ([]byte, []byte, error) { return []byte{}, nil, test.err },
 | 
						|
				func() ([]byte, []byte, error) { return []byte{}, nil, test.err },
 | 
						|
				func() ([]byte, []byte, error) { return []byte(tcClassOutput2), nil, test.err },
 | 
						|
				func() ([]byte, []byte, error) { return []byte{}, nil, test.err },
 | 
						|
				func() ([]byte, []byte, error) { return []byte{}, nil, test.err },
 | 
						|
			},
 | 
						|
		}
 | 
						|
 | 
						|
		fexec := fakeexec.FakeExec{
 | 
						|
			CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
			},
 | 
						|
		}
 | 
						|
		iface := "cbr0"
 | 
						|
		shaper := &tcShaper{e: &fexec, iface: iface}
 | 
						|
		if err := shaper.Limit(test.cidr, test.ingress, test.egress); err != nil && !test.expectErr {
 | 
						|
			t.Errorf("unexpected error: %v", err)
 | 
						|
			return
 | 
						|
		} else if err == nil && test.expectErr {
 | 
						|
			t.Error("unexpected non-error")
 | 
						|
			return
 | 
						|
		}
 | 
						|
		// No more testing in the error case
 | 
						|
		if test.expectErr {
 | 
						|
			if fcmd.CombinedOutputCalls != 1 {
 | 
						|
				t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
 | 
						|
			}
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		if fcmd.CombinedOutputCalls != test.expectedCalls {
 | 
						|
			t.Errorf("unexpected number of calls: %d, expected: %d", fcmd.CombinedOutputCalls, test.expectedCalls)
 | 
						|
		}
 | 
						|
 | 
						|
		for ix := range fcmd.CombinedOutputLog {
 | 
						|
			output := fcmd.CombinedOutputLog[ix]
 | 
						|
			if output[0] != "tc" {
 | 
						|
				t.Errorf("unexpected command: %s, expected tc", output[0])
 | 
						|
			}
 | 
						|
			if output[4] != iface {
 | 
						|
				t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
 | 
						|
			}
 | 
						|
			if ix == 1 {
 | 
						|
				var expectedRate string
 | 
						|
				if test.ingress != nil {
 | 
						|
					expectedRate = makeKBitString(test.ingress)
 | 
						|
				} else {
 | 
						|
					expectedRate = makeKBitString(test.egress)
 | 
						|
				}
 | 
						|
				if output[11] != expectedRate {
 | 
						|
					t.Errorf("unexpected ingress: %s, expected: %s", output[11], expectedRate)
 | 
						|
				}
 | 
						|
				if output[8] != "1:5" {
 | 
						|
					t.Errorf("unexpected class: %s, expected: %s", output[8], "1:5")
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if ix == 2 {
 | 
						|
				if output[15] != test.cidr {
 | 
						|
					t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
 | 
						|
				}
 | 
						|
				if output[17] != "1:5" {
 | 
						|
					t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if ix == 4 {
 | 
						|
				if output[11] != makeKBitString(test.egress) {
 | 
						|
					t.Errorf("unexpected egress: %s, expected: %s", output[11], makeKBitString(test.egress))
 | 
						|
				}
 | 
						|
				if output[8] != "1:6" {
 | 
						|
					t.Errorf("unexpected class: %s, expected: %s", output[8], "1:6")
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if ix == 5 {
 | 
						|
				if output[15] != test.cidr {
 | 
						|
					t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
 | 
						|
				}
 | 
						|
				if output[17] != "1:6" {
 | 
						|
					t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestReset(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		cidr           string
 | 
						|
		err            error
 | 
						|
		expectErr      bool
 | 
						|
		expectedHandle string
 | 
						|
		expectedClass  string
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			cidr:           "1.2.3.4/16",
 | 
						|
			expectedHandle: "800::801",
 | 
						|
			expectedClass:  "1:2",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			cidr:           "172.17.0.2/32",
 | 
						|
			expectedHandle: "800::800",
 | 
						|
			expectedClass:  "1:1",
 | 
						|
		},
 | 
						|
		{
 | 
						|
			err:       errors.New("test error"),
 | 
						|
			expectErr: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, test := range tests {
 | 
						|
		fcmd := fakeexec.FakeCmd{
 | 
						|
			CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
				func() ([]byte, []byte, error) { return []byte(tcFilterOutput), nil, test.err },
 | 
						|
				func() ([]byte, []byte, error) { return []byte{}, nil, test.err },
 | 
						|
				func() ([]byte, []byte, error) { return []byte{}, nil, test.err },
 | 
						|
			},
 | 
						|
		}
 | 
						|
 | 
						|
		fexec := fakeexec.FakeExec{
 | 
						|
			CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
			},
 | 
						|
		}
 | 
						|
		iface := "cbr0"
 | 
						|
		shaper := &tcShaper{e: &fexec, iface: iface}
 | 
						|
 | 
						|
		if err := shaper.Reset(test.cidr); err != nil && !test.expectErr {
 | 
						|
			t.Errorf("unexpected error: %v", err)
 | 
						|
			return
 | 
						|
		} else if test.expectErr && err == nil {
 | 
						|
			t.Error("unexpected non-error")
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// No more testing in the error case
 | 
						|
		if test.expectErr {
 | 
						|
			if fcmd.CombinedOutputCalls != 1 {
 | 
						|
				t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
 | 
						|
			}
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		if fcmd.CombinedOutputCalls != 3 {
 | 
						|
			t.Errorf("unexpected number of calls: %d, expected: 3", fcmd.CombinedOutputCalls)
 | 
						|
		}
 | 
						|
 | 
						|
		for ix := range fcmd.CombinedOutputLog {
 | 
						|
			output := fcmd.CombinedOutputLog[ix]
 | 
						|
			if output[0] != "tc" {
 | 
						|
				t.Errorf("unexpected command: %s, expected tc", output[0])
 | 
						|
			}
 | 
						|
			if output[4] != iface {
 | 
						|
				t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
 | 
						|
			}
 | 
						|
			if ix == 1 && output[12] != test.expectedHandle {
 | 
						|
				t.Errorf("unexpected handle: %s, expected: %s", output[12], test.expectedHandle)
 | 
						|
			}
 | 
						|
			if ix == 2 && output[8] != test.expectedClass {
 | 
						|
				t.Errorf("unexpected class: %s, expected: %s", output[8], test.expectedClass)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
var tcQdisc = "qdisc htb 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n"
 | 
						|
 | 
						|
func TestReconcileInterfaceExists(t *testing.T) {
 | 
						|
	fcmd := fakeexec.FakeCmd{
 | 
						|
		CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
			func() ([]byte, []byte, error) { return []byte(tcQdisc), nil, nil },
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	fexec := fakeexec.FakeExec{
 | 
						|
		CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
		},
 | 
						|
	}
 | 
						|
	iface := "cbr0"
 | 
						|
	shaper := &tcShaper{e: &fexec, iface: iface}
 | 
						|
	err := shaper.ReconcileInterface()
 | 
						|
	if err != nil {
 | 
						|
		t.Errorf("unexpected error: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if fcmd.CombinedOutputCalls != 1 {
 | 
						|
		t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
 | 
						|
	}
 | 
						|
 | 
						|
	output := fcmd.CombinedOutputLog[0]
 | 
						|
	if len(output) != 5 {
 | 
						|
		t.Errorf("unexpected command: %v", output)
 | 
						|
	}
 | 
						|
	if output[0] != "tc" {
 | 
						|
		t.Errorf("unexpected command: %s", output[0])
 | 
						|
	}
 | 
						|
	if output[4] != iface {
 | 
						|
		t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
 | 
						|
	}
 | 
						|
	if output[2] != "show" {
 | 
						|
		t.Errorf("unexpected action: %s", output[2])
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func testReconcileInterfaceHasNoData(t *testing.T, output string) {
 | 
						|
	fcmd := fakeexec.FakeCmd{
 | 
						|
		CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
			func() ([]byte, []byte, error) { return []byte(output), nil, nil },
 | 
						|
			func() ([]byte, []byte, error) { return []byte(output), nil, nil },
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	fexec := fakeexec.FakeExec{
 | 
						|
		CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
		},
 | 
						|
	}
 | 
						|
	iface := "cbr0"
 | 
						|
	shaper := &tcShaper{e: &fexec, iface: iface}
 | 
						|
	err := shaper.ReconcileInterface()
 | 
						|
	if err != nil {
 | 
						|
		t.Errorf("unexpected error: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if fcmd.CombinedOutputCalls != 2 {
 | 
						|
		t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
 | 
						|
	}
 | 
						|
 | 
						|
	for ix, output := range fcmd.CombinedOutputLog {
 | 
						|
		if output[0] != "tc" {
 | 
						|
			t.Errorf("unexpected command: %s", output[0])
 | 
						|
		}
 | 
						|
		if output[4] != iface {
 | 
						|
			t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
 | 
						|
		}
 | 
						|
		if ix == 0 {
 | 
						|
			if len(output) != 5 {
 | 
						|
				t.Errorf("unexpected command: %v", output)
 | 
						|
			}
 | 
						|
			if output[2] != "show" {
 | 
						|
				t.Errorf("unexpected action: %s", output[2])
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if ix == 1 {
 | 
						|
			if len(output) != 11 {
 | 
						|
				t.Errorf("unexpected command: %v", output)
 | 
						|
			}
 | 
						|
			if output[2] != "add" {
 | 
						|
				t.Errorf("unexpected action: %s", output[2])
 | 
						|
			}
 | 
						|
			if output[7] != "1:" {
 | 
						|
				t.Errorf("unexpected root class: %s", output[7])
 | 
						|
			}
 | 
						|
			if output[8] != "htb" {
 | 
						|
				t.Errorf("unexpected qdisc algo: %s", output[8])
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestReconcileInterfaceDoesntExist(t *testing.T) {
 | 
						|
	testReconcileInterfaceHasNoData(t, "\n")
 | 
						|
}
 | 
						|
 | 
						|
var tcQdiscNoqueue = "qdisc noqueue 0: root refcnt 2 \n"
 | 
						|
 | 
						|
func TestReconcileInterfaceExistsWithNoqueue(t *testing.T) {
 | 
						|
	testReconcileInterfaceHasNoData(t, tcQdiscNoqueue)
 | 
						|
}
 | 
						|
 | 
						|
var tcQdiscWrong = []string{
 | 
						|
	"qdisc htb 2: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
 | 
						|
	"qdisc foo 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
 | 
						|
}
 | 
						|
 | 
						|
func TestReconcileInterfaceIsWrong(t *testing.T) {
 | 
						|
	for _, test := range tcQdiscWrong {
 | 
						|
		fcmd := fakeexec.FakeCmd{
 | 
						|
			CombinedOutputScript: []fakeexec.FakeAction{
 | 
						|
				func() ([]byte, []byte, error) { return []byte(test), nil, nil },
 | 
						|
				func() ([]byte, []byte, error) { return []byte("\n"), nil, nil },
 | 
						|
				func() ([]byte, []byte, error) { return []byte("\n"), nil, nil },
 | 
						|
			},
 | 
						|
		}
 | 
						|
 | 
						|
		fexec := fakeexec.FakeExec{
 | 
						|
			CommandScript: []fakeexec.FakeCommandAction{
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
				func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
 | 
						|
			},
 | 
						|
		}
 | 
						|
		iface := "cbr0"
 | 
						|
		shaper := &tcShaper{e: &fexec, iface: iface}
 | 
						|
		err := shaper.ReconcileInterface()
 | 
						|
		if err != nil {
 | 
						|
			t.Errorf("unexpected error: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		if fcmd.CombinedOutputCalls != 3 {
 | 
						|
			t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
 | 
						|
		}
 | 
						|
 | 
						|
		for ix, output := range fcmd.CombinedOutputLog {
 | 
						|
			if output[0] != "tc" {
 | 
						|
				t.Errorf("unexpected command: %s", output[0])
 | 
						|
			}
 | 
						|
			if output[4] != iface {
 | 
						|
				t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
 | 
						|
			}
 | 
						|
			if ix == 0 {
 | 
						|
				if len(output) != 5 {
 | 
						|
					t.Errorf("unexpected command: %v", output)
 | 
						|
				}
 | 
						|
				if output[2] != "show" {
 | 
						|
					t.Errorf("unexpected action: %s", output[2])
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if ix == 1 {
 | 
						|
				if len(output) != 8 {
 | 
						|
					t.Errorf("unexpected command: %v", output)
 | 
						|
				}
 | 
						|
				if output[2] != "delete" {
 | 
						|
					t.Errorf("unexpected action: %s", output[2])
 | 
						|
				}
 | 
						|
				if output[7] != strings.Split(test, " ")[2] {
 | 
						|
					t.Errorf("unexpected class: %s, expected: %s", output[7], strings.Split(test, " ")[2])
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if ix == 2 {
 | 
						|
				if len(output) != 11 {
 | 
						|
					t.Errorf("unexpected command: %v", output)
 | 
						|
				}
 | 
						|
				if output[7] != "1:" {
 | 
						|
					t.Errorf("unexpected root class: %s", output[7])
 | 
						|
				}
 | 
						|
				if output[8] != "htb" {
 | 
						|
					t.Errorf("unexpected qdisc algo: %s", output[8])
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |