github.com/google/cloudprober@v0.11.3/probes/options/options_test.go (about)

     1  // Copyright 2017-2020 The Cloudprober Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package options
    16  
    17  import (
    18  	"errors"
    19  	"net"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/golang/protobuf/proto"
    24  	"github.com/google/cloudprober/common/iputils"
    25  	"github.com/google/cloudprober/logger"
    26  	configpb "github.com/google/cloudprober/probes/proto"
    27  	targetspb "github.com/google/cloudprober/targets/proto"
    28  )
    29  
    30  type intf struct {
    31  	addrs []net.Addr
    32  }
    33  
    34  func (i *intf) Addrs() ([]net.Addr, error) {
    35  	return i.addrs, nil
    36  }
    37  
    38  func mockInterfaceByName(iname string, addrs []string) {
    39  	ips := make([]net.Addr, len(addrs))
    40  	for i, a := range addrs {
    41  		ips[i] = &net.IPAddr{IP: net.ParseIP(a)}
    42  	}
    43  	i := &intf{addrs: ips}
    44  	iputils.InterfaceByName = func(name string) (iputils.Addr, error) {
    45  		if name != iname {
    46  			return nil, errors.New("device not found")
    47  		}
    48  		return i, nil
    49  	}
    50  }
    51  
    52  var ipVersionToEnum = map[int]*configpb.ProbeDef_IPVersion{
    53  	4: configpb.ProbeDef_IPV4.Enum(),
    54  	6: configpb.ProbeDef_IPV6.Enum(),
    55  }
    56  
    57  func TestGetSourceIPFromConfig(t *testing.T) {
    58  	rows := []struct {
    59  		name       string
    60  		sourceIP   string
    61  		sourceIntf string
    62  		intf       string
    63  		intfAddrs  []string
    64  		ipVer      int
    65  		want       string
    66  		wantError  bool
    67  	}{
    68  		{
    69  			name:     "Use IP",
    70  			sourceIP: "1.1.1.1",
    71  			want:     "1.1.1.1",
    72  		},
    73  		{
    74  			name:      "Source IP doesn't match IP version",
    75  			sourceIP:  "1.1.1.1",
    76  			ipVer:     6,
    77  			wantError: true,
    78  		},
    79  		{
    80  			name:     "Use IPv6",
    81  			sourceIP: "::1",
    82  			ipVer:    6,
    83  			want:     "::1",
    84  		},
    85  		{
    86  			name:      "Invalid IP",
    87  			sourceIP:  "12ab",
    88  			wantError: true,
    89  		},
    90  		{
    91  			name:       "Interface with no adders fails",
    92  			sourceIntf: "eth1",
    93  			intf:       "eth1",
    94  			wantError:  true,
    95  		},
    96  		{
    97  			name:       "Unknown interface fails",
    98  			sourceIntf: "eth1",
    99  			intf:       "eth0",
   100  			wantError:  true,
   101  		},
   102  		{
   103  			name:       "Uses first addr for interface",
   104  			sourceIntf: "eth1",
   105  			intf:       "eth1",
   106  			intfAddrs:  []string{"1.1.1.1", "2.2.2.2"},
   107  			want:       "1.1.1.1",
   108  		},
   109  		{
   110  			name:       "Uses first IPv6 addr for interface",
   111  			sourceIntf: "eth1",
   112  			intf:       "eth1",
   113  			intfAddrs:  []string{"1.1.1.1", "::1"},
   114  			ipVer:      6,
   115  			want:       "::1",
   116  		},
   117  	}
   118  
   119  	for _, r := range rows {
   120  		p := &configpb.ProbeDef{
   121  			IpVersion: ipVersionToEnum[r.ipVer],
   122  		}
   123  
   124  		if r.sourceIP != "" {
   125  			p.SourceIpConfig = &configpb.ProbeDef_SourceIp{r.sourceIP}
   126  		} else if r.sourceIntf != "" {
   127  			p.SourceIpConfig = &configpb.ProbeDef_SourceInterface{r.sourceIntf}
   128  			mockInterfaceByName(r.intf, r.intfAddrs)
   129  		}
   130  
   131  		source, err := getSourceIPFromConfig(p, &logger.Logger{})
   132  
   133  		if (err != nil) != r.wantError {
   134  			t.Errorf("Row %q: getSourceIPFromConfig() gave error %q, want error is %v", r.name, err, r.wantError)
   135  			continue
   136  		}
   137  		if r.wantError {
   138  			continue
   139  		}
   140  		if source.String() != r.want {
   141  			t.Errorf("Row %q: source= %q, want %q", r.name, source, r.want)
   142  		}
   143  	}
   144  }
   145  
   146  var testTargets = &targetspb.TargetsDef{
   147  	Type: &targetspb.TargetsDef_HostNames{HostNames: "testHost"},
   148  }
   149  
   150  func TestIPVersionFromSourceIP(t *testing.T) {
   151  	rows := []struct {
   152  		name     string
   153  		sourceIP string
   154  		ipVer    int
   155  	}{
   156  		{
   157  			name:  "No source IP",
   158  			ipVer: 0,
   159  		},
   160  		{
   161  			name:     "IPv4 from source IP",
   162  			sourceIP: "1.1.1.1",
   163  			ipVer:    4,
   164  		},
   165  		{
   166  			name:     "IPv6 from source IP",
   167  			sourceIP: "::1",
   168  			ipVer:    6,
   169  		},
   170  	}
   171  
   172  	for _, r := range rows {
   173  		p := &configpb.ProbeDef{
   174  			Targets: testTargets,
   175  		}
   176  
   177  		if r.sourceIP != "" {
   178  			p.SourceIpConfig = &configpb.ProbeDef_SourceIp{r.sourceIP}
   179  		}
   180  
   181  		opts, err := BuildProbeOptions(p, nil, nil, nil)
   182  		if err != nil {
   183  			t.Errorf("got unexpected error: %v", err)
   184  			continue
   185  		}
   186  
   187  		if opts.IPVersion != r.ipVer {
   188  			t.Errorf("Unexpected IPVersion (test case: %s) want=%d, got=%d", r.name, r.ipVer, opts.IPVersion)
   189  		}
   190  	}
   191  }
   192  
   193  func TestStatsExportInterval(t *testing.T) {
   194  	rows := []struct {
   195  		name       string
   196  		pType      *configpb.ProbeDef_Type
   197  		interval   int32
   198  		timeout    int32
   199  		configured int32
   200  		want       int
   201  		wantError  bool
   202  	}{
   203  		{
   204  			name:     "Interval bigger than default",
   205  			interval: 15,
   206  			timeout:  10,
   207  			want:     15,
   208  		},
   209  		{
   210  			name:     "Timeout bigger than interval",
   211  			interval: 10,
   212  			timeout:  12,
   213  			want:     12,
   214  		},
   215  		{
   216  			name:     "Interval and timeout less than default",
   217  			interval: 2,
   218  			timeout:  1,
   219  			want:     int(defaultStatsExtportIntv.Seconds()),
   220  		},
   221  		{
   222  			name:     "UDP probe: default twice of timeout- I",
   223  			interval: 10,
   224  			timeout:  12,
   225  			pType:    configpb.ProbeDef_UDP.Enum(),
   226  			want:     24,
   227  		},
   228  		{
   229  			name:     "UDP probe: default twice of timeout - II",
   230  			interval: 5,
   231  			timeout:  6,
   232  			pType:    configpb.ProbeDef_UDP.Enum(),
   233  			want:     12,
   234  		},
   235  		{
   236  			name:       "Error: stats export interval smaller than interval",
   237  			interval:   2,
   238  			timeout:    1,
   239  			configured: 1,
   240  			wantError:  true,
   241  		},
   242  		{
   243  			name:       "Configured value is good",
   244  			interval:   2,
   245  			timeout:    1,
   246  			configured: 10,
   247  			want:       10,
   248  		},
   249  	}
   250  
   251  	for _, r := range rows {
   252  		p := &configpb.ProbeDef{
   253  			Targets:      testTargets,
   254  			IntervalMsec: proto.Int32(r.interval * 1000),
   255  			TimeoutMsec:  proto.Int32(r.timeout * 1000),
   256  		}
   257  
   258  		if r.pType != nil {
   259  			p.Type = r.pType
   260  		}
   261  
   262  		if r.configured != 0 {
   263  			p.StatsExportIntervalMsec = proto.Int32(r.configured * 1000)
   264  		}
   265  
   266  		opts, err := BuildProbeOptions(p, nil, nil, nil)
   267  		if (err != nil) != r.wantError {
   268  			t.Errorf("Row %q: BuildProbeOptions() gave error %q, want error is %v", r.name, err, r.wantError)
   269  			continue
   270  		}
   271  		if r.wantError {
   272  			continue
   273  		}
   274  
   275  		want := time.Duration(r.want) * time.Second
   276  		if opts.StatsExportInterval != want {
   277  			t.Errorf("Unexpected stats export interval (test case: %s): want=%s, got=%s", r.name, want, opts.StatsExportInterval)
   278  		}
   279  	}
   280  }
   281  
   282  func TestDefaultOptions(t *testing.T) {
   283  	// Most of all, it verifies that DefaultOptions() doesn't generate panic.
   284  	opts := DefaultOptions()
   285  	if opts == nil {
   286  		t.Errorf("Got nil default options")
   287  	}
   288  }