storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/net_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2017 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "errors" 21 "fmt" 22 "net" 23 "reflect" 24 "runtime" 25 "testing" 26 27 "github.com/minio/minio-go/v7/pkg/set" 28 ) 29 30 func TestMustSplitHostPort(t *testing.T) { 31 testCases := []struct { 32 hostPort string 33 expectedHost string 34 expectedPort string 35 }{ 36 {":54321", "", "54321"}, 37 {"server:54321", "server", "54321"}, 38 {":0", "", "0"}, 39 {"server:https", "server", "443"}, 40 {"server:http", "server", "80"}, 41 } 42 43 for _, testCase := range testCases { 44 host, port := mustSplitHostPort(testCase.hostPort) 45 if testCase.expectedHost != host { 46 t.Fatalf("host: expected = %v, got = %v", testCase.expectedHost, host) 47 } 48 49 if testCase.expectedPort != port { 50 t.Fatalf("port: expected = %v, got = %v", testCase.expectedPort, port) 51 } 52 } 53 } 54 55 func TestSortIPs(t *testing.T) { 56 testCases := []struct { 57 ipList []string 58 sortedIPList []string 59 }{ 60 // Default case of two ips one with higher octet moves 61 // to the beginning of the list. 62 { 63 ipList: []string{"127.0.0.1", "10.0.0.13"}, 64 sortedIPList: []string{"10.0.0.13", "127.0.0.1"}, 65 }, 66 // With multiple types of octet, chooses a higher octet. 67 { 68 ipList: []string{"127.0.0.1", "172.0.21.1", "192.168.1.106"}, 69 sortedIPList: []string{"192.168.1.106", "172.0.21.1", "127.0.0.1"}, 70 }, 71 // With different ip along with localhost. 72 { 73 ipList: []string{"127.0.0.1", "192.168.1.106"}, 74 sortedIPList: []string{"192.168.1.106", "127.0.0.1"}, 75 }, 76 // With a list of only one element nothing to sort. 77 { 78 ipList: []string{"hostname"}, 79 sortedIPList: []string{"hostname"}, 80 }, 81 // With a list of only one element nothing to sort. 82 { 83 ipList: []string{"127.0.0.1"}, 84 sortedIPList: []string{"127.0.0.1"}, 85 }, 86 // Non parsable ip is assumed to be hostame and gets preserved 87 // as the left most elements, regardless of IP based sorting. 88 { 89 ipList: []string{"hostname", "127.0.0.1", "192.168.1.106"}, 90 sortedIPList: []string{"hostname", "192.168.1.106", "127.0.0.1"}, 91 }, 92 // Non parsable ip is assumed to be hostname, with a mixed input of ip and hostname. 93 // gets preserved and moved into left most elements, regardless of 94 // IP based sorting. 95 { 96 ipList: []string{"hostname1", "10.0.0.13", "hostname2", "127.0.0.1", "192.168.1.106"}, 97 sortedIPList: []string{"hostname1", "hostname2", "192.168.1.106", "10.0.0.13", "127.0.0.1"}, 98 }, 99 // With same higher octets, preferentially move the localhost. 100 { 101 ipList: []string{"127.0.0.1", "10.0.0.1", "192.168.0.1"}, 102 sortedIPList: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"}, 103 }, 104 } 105 for i, testCase := range testCases { 106 gotIPList := sortIPs(testCase.ipList) 107 if !reflect.DeepEqual(testCase.sortedIPList, gotIPList) { 108 t.Errorf("Test %d: Expected %s, got %s", i+1, testCase.sortedIPList, gotIPList) 109 } 110 } 111 } 112 113 func TestMustGetLocalIP4(t *testing.T) { 114 testCases := []struct { 115 expectedIPList set.StringSet 116 }{ 117 {set.CreateStringSet("127.0.0.1")}, 118 } 119 120 for _, testCase := range testCases { 121 ipList := mustGetLocalIP4() 122 if testCase.expectedIPList != nil && testCase.expectedIPList.Intersection(ipList).IsEmpty() { 123 t.Fatalf("host: expected = %v, got = %v", testCase.expectedIPList, ipList) 124 } 125 } 126 } 127 128 func TestGetHostIP(t *testing.T) { 129 testCases := []struct { 130 host string 131 expectedIPList set.StringSet 132 expectedErr error 133 }{ 134 {"localhost", set.CreateStringSet("127.0.0.1"), nil}, 135 {"example.org", set.CreateStringSet("93.184.216.34"), nil}, 136 } 137 138 for _, testCase := range testCases { 139 ipList, err := getHostIP(testCase.host) 140 if testCase.expectedErr == nil { 141 if err != nil { 142 t.Fatalf("error: expected = <nil>, got = %v", err) 143 } 144 } else if err == nil { 145 t.Fatalf("error: expected = %v, got = <nil>", testCase.expectedErr) 146 } else if 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, globalMinioAddr 159 defer func() { 160 globalMinioHost, globalMinioAddr = 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 // Ask the kernel for a free open port. 182 func getFreePort() string { 183 addr, err := net.ResolveTCPAddr("tcp", "localhost:0") 184 if err != nil { 185 panic(err) 186 } 187 188 l, err := net.ListenTCP("tcp", addr) 189 if err != nil { 190 panic(err) 191 } 192 defer l.Close() 193 return fmt.Sprintf("%d", l.Addr().(*net.TCPAddr).Port) 194 } 195 196 // Tests for port availability logic written for server startup sequence. 197 func TestCheckPortAvailability(t *testing.T) { 198 // Make a port is not available. 199 port := getFreePort() 200 listener, err := net.Listen("tcp", net.JoinHostPort("", port)) 201 if err != nil { 202 t.Fatalf("Unable to listen on port %v", port) 203 } 204 defer listener.Close() 205 206 testCases := []struct { 207 host string 208 port string 209 expectedErr error 210 }{ 211 {"", port, fmt.Errorf("listen tcp :%v: bind: address already in use", port)}, 212 {"127.0.0.1", port, fmt.Errorf("listen tcp 127.0.0.1:%v: bind: address already in use", port)}, 213 {"", getFreePort(), nil}, 214 } 215 216 for _, testCase := range testCases { 217 // On MS Windows and Mac, skip checking error case due to https://github.com/golang/go/issues/7598 218 if (runtime.GOOS == globalWindowsOSName || runtime.GOOS == globalMacOSName || runtime.GOOS == "solaris") && testCase.expectedErr != nil { 219 continue 220 } 221 222 err := checkPortAvailability(testCase.host, testCase.port) 223 if testCase.expectedErr == nil { 224 if err != nil { 225 t.Fatalf("error: expected = <nil>, got = %v", err) 226 } 227 } else if err == nil { 228 t.Fatalf("error: expected = %v, got = <nil>", testCase.expectedErr) 229 } else if testCase.expectedErr.Error() != err.Error() { 230 t.Fatalf("error: expected = %v, got = %v", testCase.expectedErr, err) 231 } 232 } 233 } 234 235 func TestCheckLocalServerAddr(t *testing.T) { 236 testCases := []struct { 237 serverAddr string 238 expectedErr error 239 }{ 240 {":54321", nil}, 241 {"localhost:54321", nil}, 242 {"0.0.0.0:9000", nil}, 243 {":0", nil}, 244 {"localhost", nil}, 245 {"", fmt.Errorf("invalid argument")}, 246 {"example.org:54321", fmt.Errorf("host in server address should be this server")}, 247 {":-10", fmt.Errorf("port must be between 0 to 65535")}, 248 } 249 250 for _, testCase := range testCases { 251 testCase := testCase 252 t.Run("", func(t *testing.T) { 253 err := CheckLocalServerAddr(testCase.serverAddr) 254 if testCase.expectedErr == nil { 255 if err != nil { 256 t.Errorf("error: expected = <nil>, got = %v", err) 257 } 258 } else if err == nil { 259 t.Errorf("error: expected = %v, got = <nil>", testCase.expectedErr) 260 } else if testCase.expectedErr.Error() != err.Error() { 261 t.Errorf("error: expected = %v, got = %v", testCase.expectedErr, err) 262 } 263 }) 264 } 265 } 266 267 func TestExtractHostPort(t *testing.T) { 268 testCases := []struct { 269 addr string 270 host string 271 port string 272 expectedErr error 273 }{ 274 {"", "", "", errors.New("unable to process empty address")}, 275 {"localhost:9000", "localhost", "9000", nil}, 276 {"http://:9000/", "", "9000", nil}, 277 {"http://8.8.8.8:9000/", "8.8.8.8", "9000", nil}, 278 {"https://facebook.com:9000/", "facebook.com", "9000", nil}, 279 } 280 281 for i, testCase := range testCases { 282 host, port, err := extractHostPort(testCase.addr) 283 if testCase.expectedErr == nil && err != nil { 284 t.Fatalf("Test %d: should succeed but failed with err: %v", i+1, err) 285 } 286 if testCase.expectedErr != nil && err == nil { 287 t.Fatalf("Test %d:, should fail but succeeded.", i+1) 288 } 289 if err == nil { 290 if host != testCase.host { 291 t.Fatalf("Test %d: expected: %v, found: %v", i+1, testCase.host, host) 292 } 293 if port != testCase.port { 294 t.Fatalf("Test %d: expected: %v, found: %v", i+1, testCase.port, port) 295 } 296 } 297 if testCase.expectedErr != nil && err != nil { 298 if testCase.expectedErr.Error() != err.Error() { 299 t.Fatalf("Test %d: failed with different error, expected: '%v', found:'%v'.", i+1, testCase.expectedErr, err) 300 } 301 } 302 } 303 } 304 305 func TestSameLocalAddrs(t *testing.T) { 306 testCases := []struct { 307 addr1 string 308 addr2 string 309 sameAddr bool 310 expectedErr error 311 }{ 312 {"", "", false, errors.New("unable to process empty address")}, 313 {":9000", ":9000", true, nil}, 314 {"localhost:9000", ":9000", true, nil}, 315 {"localhost:9000", "http://localhost:9000", true, nil}, 316 {"http://localhost:9000", ":9000", true, nil}, 317 {"http://localhost:9000", "http://localhost:9000", true, nil}, 318 {"http://8.8.8.8:9000", "http://localhost:9000", false, nil}, 319 } 320 321 for _, testCase := range testCases { 322 testCase := testCase 323 t.Run("", func(t *testing.T) { 324 sameAddr, err := sameLocalAddrs(testCase.addr1, testCase.addr2) 325 if testCase.expectedErr != nil && err == nil { 326 t.Errorf("should fail but succeeded") 327 } 328 if testCase.expectedErr == nil && err != nil { 329 t.Errorf("should succeed but failed with %v", err) 330 } 331 if err == nil { 332 if sameAddr != testCase.sameAddr { 333 t.Errorf("expected: %v, found: %v", testCase.sameAddr, sameAddr) 334 } 335 } else { 336 if err.Error() != testCase.expectedErr.Error() { 337 t.Errorf("failed with different error, expected: '%v', found:'%v'.", 338 testCase.expectedErr, err) 339 } 340 } 341 }) 342 } 343 } 344 func TestIsHostIP(t *testing.T) { 345 testCases := []struct { 346 args string 347 expectedResult bool 348 }{ 349 {"localhost", false}, 350 {"localhost:9000", false}, 351 {"example.com", false}, 352 {"http://192.168.1.0", false}, 353 {"http://192.168.1.0:9000", false}, 354 {"192.168.1.0", true}, 355 {"[2001:3984:3989::20%eth0]:9000", true}, 356 } 357 358 for _, testCase := range testCases { 359 ret := isHostIP(testCase.args) 360 if testCase.expectedResult != ret { 361 t.Fatalf("expected: %v , got: %v", testCase.expectedResult, ret) 362 } 363 } 364 }