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 }