github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/net_test.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"errors"
    22  	"fmt"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"github.com/minio/minio-go/v7/pkg/set"
    27  )
    28  
    29  func TestMustSplitHostPort(t *testing.T) {
    30  	testCases := []struct {
    31  		hostPort     string
    32  		expectedHost string
    33  		expectedPort string
    34  	}{
    35  		{":54321", "", "54321"},
    36  		{"server:54321", "server", "54321"},
    37  		{":0", "", "0"},
    38  		{"server:https", "server", "443"},
    39  		{"server:http", "server", "80"},
    40  	}
    41  
    42  	for _, testCase := range testCases {
    43  		host, port := mustSplitHostPort(testCase.hostPort)
    44  		if testCase.expectedHost != host {
    45  			t.Fatalf("host: expected = %v, got = %v", testCase.expectedHost, host)
    46  		}
    47  
    48  		if testCase.expectedPort != port {
    49  			t.Fatalf("port: expected = %v, got = %v", testCase.expectedPort, port)
    50  		}
    51  	}
    52  }
    53  
    54  func TestSortIPs(t *testing.T) {
    55  	testCases := []struct {
    56  		ipList       []string
    57  		sortedIPList []string
    58  	}{
    59  		// Default case of two ips one with higher octet moves
    60  		// to the beginning of the list.
    61  		{
    62  			ipList:       []string{"127.0.0.1", "10.0.0.13"},
    63  			sortedIPList: []string{"10.0.0.13", "127.0.0.1"},
    64  		},
    65  		// With multiple types of octet, chooses a higher octet.
    66  		{
    67  			ipList:       []string{"127.0.0.1", "172.0.21.1", "192.168.1.106"},
    68  			sortedIPList: []string{"192.168.1.106", "172.0.21.1", "127.0.0.1"},
    69  		},
    70  		// With different ip along with localhost.
    71  		{
    72  			ipList:       []string{"127.0.0.1", "192.168.1.106"},
    73  			sortedIPList: []string{"192.168.1.106", "127.0.0.1"},
    74  		},
    75  		// With a list of only one element nothing to sort.
    76  		{
    77  			ipList:       []string{"hostname"},
    78  			sortedIPList: []string{"hostname"},
    79  		},
    80  		// With a list of only one element nothing to sort.
    81  		{
    82  			ipList:       []string{"127.0.0.1"},
    83  			sortedIPList: []string{"127.0.0.1"},
    84  		},
    85  		// Non parsable ip is assumed to be hostame and gets preserved
    86  		// as the left most elements, regardless of IP based sorting.
    87  		{
    88  			ipList:       []string{"hostname", "127.0.0.1", "192.168.1.106"},
    89  			sortedIPList: []string{"hostname", "192.168.1.106", "127.0.0.1"},
    90  		},
    91  		// Non parsable ip is assumed to be hostname, with a mixed input of ip and hostname.
    92  		// gets preserved and moved into left most elements, regardless of
    93  		// IP based sorting.
    94  		{
    95  			ipList:       []string{"hostname1", "10.0.0.13", "hostname2", "127.0.0.1", "192.168.1.106"},
    96  			sortedIPList: []string{"hostname1", "hostname2", "192.168.1.106", "10.0.0.13", "127.0.0.1"},
    97  		},
    98  		// With same higher octets, preferentially move the localhost.
    99  		{
   100  			ipList:       []string{"127.0.0.1", "10.0.0.1", "192.168.0.1"},
   101  			sortedIPList: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"},
   102  		},
   103  	}
   104  	for i, testCase := range testCases {
   105  		gotIPList := sortIPs(testCase.ipList)
   106  		if !reflect.DeepEqual(testCase.sortedIPList, gotIPList) {
   107  			t.Errorf("Test %d: Expected %s, got %s", i+1, testCase.sortedIPList, gotIPList)
   108  		}
   109  	}
   110  }
   111  
   112  func TestMustGetLocalIP4(t *testing.T) {
   113  	testCases := []struct {
   114  		expectedIPList set.StringSet
   115  	}{
   116  		{set.CreateStringSet("127.0.0.1")},
   117  	}
   118  
   119  	for _, testCase := range testCases {
   120  		ipList := mustGetLocalIP4()
   121  		if testCase.expectedIPList != nil && testCase.expectedIPList.Intersection(ipList).IsEmpty() {
   122  			t.Fatalf("host: expected = %v, got = %v", testCase.expectedIPList, ipList)
   123  		}
   124  	}
   125  }
   126  
   127  func TestGetHostIP(t *testing.T) {
   128  	testCases := []struct {
   129  		host           string
   130  		expectedIPList set.StringSet
   131  		expectedErr    error
   132  	}{
   133  		{"localhost", set.CreateStringSet("127.0.0.1"), nil},
   134  		{"example.org", set.CreateStringSet("93.184.216.34"), nil},
   135  	}
   136  
   137  	for _, testCase := range testCases {
   138  		ipList, err := getHostIP(testCase.host)
   139  		switch {
   140  		case testCase.expectedErr == nil:
   141  			if err != nil {
   142  				t.Fatalf("error: expected = <nil>, got = %v", err)
   143  			}
   144  		case err == nil:
   145  			t.Fatalf("error: expected = %v, got = <nil>", testCase.expectedErr)
   146  		case testCase.expectedErr.Error() != err.Error():
   147  			t.Fatalf("error: expected = %v, got = %v", testCase.expectedErr, err)
   148  		}
   149  
   150  		if testCase.expectedIPList != nil && testCase.expectedIPList.Intersection(ipList).IsEmpty() {
   151  			t.Fatalf("host: expected = %v, got = %v", testCase.expectedIPList, ipList)
   152  		}
   153  	}
   154  }
   155  
   156  // Tests finalize api endpoints.
   157  func TestGetAPIEndpoints(t *testing.T) {
   158  	host, port := globalMinioHost, globalMinioPort
   159  	defer func() {
   160  		globalMinioHost, globalMinioPort = host, port
   161  	}()
   162  	testCases := []struct {
   163  		host, port     string
   164  		expectedResult string
   165  	}{
   166  		{"", "80", "http://127.0.0.1:80"},
   167  		{"127.0.0.1", "80", "http://127.0.0.1:80"},
   168  		{"localhost", "80", "http://localhost:80"},
   169  	}
   170  
   171  	for i, testCase := range testCases {
   172  		globalMinioHost, globalMinioPort = testCase.host, testCase.port
   173  		apiEndpoints := getAPIEndpoints()
   174  		apiEndpointSet := set.CreateStringSet(apiEndpoints...)
   175  		if !apiEndpointSet.Contains(testCase.expectedResult) {
   176  			t.Fatalf("test %d: expected: Found, got: Not Found", i+1)
   177  		}
   178  	}
   179  }
   180  
   181  func TestCheckLocalServerAddr(t *testing.T) {
   182  	testCases := []struct {
   183  		serverAddr  string
   184  		expectedErr error
   185  	}{
   186  		{":54321", nil},
   187  		{"localhost:54321", nil},
   188  		{"0.0.0.0:9000", nil},
   189  		{":0", nil},
   190  		{"localhost", nil},
   191  		{"", fmt.Errorf("invalid argument")},
   192  		{"example.org:54321", fmt.Errorf("host in server address should be this server")},
   193  		{":-10", fmt.Errorf("port must be between 0 to 65535")},
   194  	}
   195  
   196  	for _, testCase := range testCases {
   197  		testCase := testCase
   198  		t.Run("", func(t *testing.T) {
   199  			err := CheckLocalServerAddr(testCase.serverAddr)
   200  			switch {
   201  			case testCase.expectedErr == nil:
   202  				if err != nil {
   203  					t.Errorf("error: expected = <nil>, got = %v", err)
   204  				}
   205  			case err == nil:
   206  				t.Errorf("error: expected = %v, got = <nil>", testCase.expectedErr)
   207  			case testCase.expectedErr.Error() != err.Error():
   208  				t.Errorf("error: expected = %v, got = %v", testCase.expectedErr, err)
   209  			}
   210  		})
   211  	}
   212  }
   213  
   214  func TestExtractHostPort(t *testing.T) {
   215  	testCases := []struct {
   216  		addr        string
   217  		host        string
   218  		port        string
   219  		expectedErr error
   220  	}{
   221  		{"", "", "", errors.New("unable to process empty address")},
   222  		{"localhost:9000", "localhost", "9000", nil},
   223  		{"http://:9000/", "", "9000", nil},
   224  		{"http://8.8.8.8:9000/", "8.8.8.8", "9000", nil},
   225  		{"https://facebook.com:9000/", "facebook.com", "9000", nil},
   226  	}
   227  
   228  	for i, testCase := range testCases {
   229  		host, port, err := extractHostPort(testCase.addr)
   230  		if testCase.expectedErr == nil && err != nil {
   231  			t.Fatalf("Test %d: should succeed but failed with err: %v", i+1, err)
   232  		}
   233  		if testCase.expectedErr != nil && err == nil {
   234  			t.Fatalf("Test %d:, should fail but succeeded.", i+1)
   235  		}
   236  		if err == nil {
   237  			if host != testCase.host {
   238  				t.Fatalf("Test %d: expected: %v, found: %v", i+1, testCase.host, host)
   239  			}
   240  			if port != testCase.port {
   241  				t.Fatalf("Test %d: expected: %v, found: %v", i+1, testCase.port, port)
   242  			}
   243  		}
   244  		if testCase.expectedErr != nil && err != nil {
   245  			if testCase.expectedErr.Error() != err.Error() {
   246  				t.Fatalf("Test %d: failed with different error, expected: '%v', found:'%v'.", i+1, testCase.expectedErr, err)
   247  			}
   248  		}
   249  	}
   250  }
   251  
   252  func TestSameLocalAddrs(t *testing.T) {
   253  	testCases := []struct {
   254  		addr1       string
   255  		addr2       string
   256  		sameAddr    bool
   257  		expectedErr error
   258  	}{
   259  		{"", "", false, errors.New("unable to process empty address")},
   260  		{":9000", ":9000", true, nil},
   261  		{"localhost:9000", ":9000", true, nil},
   262  		{"localhost:9000", "http://localhost:9000", true, nil},
   263  		{"http://localhost:9000", ":9000", true, nil},
   264  		{"http://localhost:9000", "http://localhost:9000", true, nil},
   265  		{"http://8.8.8.8:9000", "http://localhost:9000", false, nil},
   266  	}
   267  
   268  	for _, testCase := range testCases {
   269  		testCase := testCase
   270  		t.Run("", func(t *testing.T) {
   271  			sameAddr, err := sameLocalAddrs(testCase.addr1, testCase.addr2)
   272  			if testCase.expectedErr != nil && err == nil {
   273  				t.Errorf("should fail but succeeded")
   274  			}
   275  			if testCase.expectedErr == nil && err != nil {
   276  				t.Errorf("should succeed but failed with %v", err)
   277  			}
   278  			if err == nil {
   279  				if sameAddr != testCase.sameAddr {
   280  					t.Errorf("expected: %v, found: %v", testCase.sameAddr, sameAddr)
   281  				}
   282  			} else {
   283  				if err.Error() != testCase.expectedErr.Error() {
   284  					t.Errorf("failed with different error, expected: '%v', found:'%v'.",
   285  						testCase.expectedErr, err)
   286  				}
   287  			}
   288  		})
   289  	}
   290  }
   291  
   292  func TestIsHostIP(t *testing.T) {
   293  	testCases := []struct {
   294  		args           string
   295  		expectedResult bool
   296  	}{
   297  		{"localhost", false},
   298  		{"localhost:9000", false},
   299  		{"example.com", false},
   300  		{"http://192.168.1.0", false},
   301  		{"http://192.168.1.0:9000", false},
   302  		{"192.168.1.0", true},
   303  		{"[2001:3984:3989::20%eth0]:9000", true},
   304  	}
   305  
   306  	for _, testCase := range testCases {
   307  		ret := isHostIP(testCase.args)
   308  		if testCase.expectedResult != ret {
   309  			t.Fatalf("expected: %v , got: %v", testCase.expectedResult, ret)
   310  		}
   311  	}
   312  }