You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
9.3 KiB

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