1// Copyright (C) 2019 Storj Labs, Inc. 2// See LICENSE for copying information. 3 4package trust_test 5 6import ( 7 "context" 8 "fmt" 9 "net/http" 10 "net/http/httptest" 11 "testing" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "storj.io/storj/storagenode/trust" 17) 18 19func TestHTTPSourceNew(t *testing.T) { 20 for _, tt := range []struct { 21 name string 22 httpURL string 23 errs []string 24 }{ 25 { 26 name: "not a valid URL", 27 httpURL: "://", 28 errs: []string{ 29 `HTTP source: "://": not a URL: parse ://: missing protocol scheme`, 30 `HTTP source: "://": not a URL: parse "://": missing protocol scheme`, 31 }, 32 }, 33 { 34 name: "not an HTTP or HTTPS URL", 35 httpURL: "file://", 36 errs: []string{`HTTP source: "file://": scheme is not supported`}, 37 }, 38 { 39 name: "missing host", 40 httpURL: "http:///path", 41 errs: []string{`HTTP source: "http:///path": host is missing`}, 42 }, 43 { 44 name: "fragment not allowed", 45 httpURL: "http://localhost/path#OHNO", 46 errs: []string{`HTTP source: "http://localhost/path#OHNO": fragment is not allowed`}, 47 }, 48 { 49 name: "success", 50 httpURL: "http://localhost/path", 51 }, 52 } { 53 tt := tt // quiet linting 54 t.Run(tt.name, func(t *testing.T) { 55 _, err := trust.NewHTTPSource(tt.httpURL) 56 if len(tt.errs) > 0 { 57 require.Error(t, err) 58 require.Contains(t, tt.errs, err.Error()) 59 return 60 } 61 require.NoError(t, err) 62 }) 63 } 64} 65 66func TestHTTPSourceString(t *testing.T) { 67 source, err := trust.NewHTTPSource("http://localhost:1234/path") 68 require.NoError(t, err) 69 require.Equal(t, "http://localhost:1234/path", source.String()) 70} 71 72func TestHTTPSourceIsNotStatic(t *testing.T) { 73 source, err := trust.NewHTTPSource("http://localhost/path") 74 require.NoError(t, err) 75 require.False(t, source.Static(), "HTTP source is unexpectedly static") 76} 77 78func TestHTTPSourceFetchEntries(t *testing.T) { 79 url1 := makeSatelliteURL("127.0.0.1") 80 url2 := makeSatelliteURL("domain.test") 81 82 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 83 switch { 84 case r.Method != "GET": 85 http.Error(w, fmt.Sprintf("%s method not allowed", r.Method), http.StatusMethodNotAllowed) 86 case r.URL.Path == "/good": 87 fmt.Fprintf(w, ` 88 # Some comment 89 %s 90 %s 91 `, url1.String(), url2.String()) 92 case r.URL.Path == "/bad": 93 fmt.Fprintln(w, "BAD") 94 case r.URL.Path == "/ugly": 95 http.Error(w, "OHNO", http.StatusInternalServerError) 96 } 97 })) 98 defer server.Close() 99 100 goodURL := server.URL + "/good" 101 badURL := server.URL + "/bad" 102 uglyURL := server.URL + "/ugly" 103 104 for _, tt := range []struct { 105 name string 106 httpURL string 107 err string 108 entries []trust.Entry 109 }{ 110 { 111 name: "well-formed list was fetched", 112 httpURL: goodURL, 113 entries: []trust.Entry{ 114 { 115 SatelliteURL: url1, 116 Authoritative: true, 117 }, 118 { 119 SatelliteURL: url2, 120 Authoritative: false, 121 }, 122 }, 123 }, 124 { 125 name: "malformed list was fetched", 126 httpURL: badURL, 127 err: fmt.Sprintf("HTTP source: cannot parse list at %q: invalid satellite URL: must contain an ID", badURL), 128 }, 129 { 130 name: "endpoint returned unsuccessful status code", 131 httpURL: uglyURL, 132 err: fmt.Sprintf(`HTTP source: %q: unexpected status code 500: "OHNO"`, uglyURL), 133 }, 134 } { 135 tt := tt // quiet linting 136 t.Run(tt.name, func(t *testing.T) { 137 source, err := trust.NewHTTPSource(tt.httpURL) 138 require.NoError(t, err) 139 entries, err := source.FetchEntries(context.Background()) 140 if tt.err != "" { 141 require.EqualError(t, err, tt.err) 142 return 143 } 144 require.NoError(t, err) 145 assert.Equal(t, tt.entries, entries) 146 }) 147 } 148} 149 150func TestURLMatchesHTTPSourceHost(t *testing.T) { 151 for _, tt := range []struct { 152 name string 153 urlHost string 154 sourceHost string 155 matches bool 156 }{ 157 { 158 name: "URL IP and source domain should not match", 159 urlHost: "1.2.3.4", 160 sourceHost: "domain.test", 161 matches: false, 162 }, 163 { 164 name: "URL domain and source IP should not match", 165 urlHost: "domain.test", 166 sourceHost: "1.2.3.4", 167 matches: false, 168 }, 169 { 170 name: "equal URL and source IP should match", 171 urlHost: "1.2.3.4", 172 sourceHost: "1.2.3.4", 173 matches: true, 174 }, 175 { 176 name: "inequal URL and source IP should not match", 177 urlHost: "1.2.3.4", 178 sourceHost: "4.3.2.1", 179 matches: false, 180 }, 181 { 182 name: "equal URL and source domains should match", 183 urlHost: "domain.test", 184 sourceHost: "domain.test", 185 matches: true, 186 }, 187 { 188 name: "URL domain and source subdomains should not match", 189 urlHost: "domain.test", 190 sourceHost: "sub.domain.test", 191 matches: false, 192 }, 193 { 194 name: "URL subdomain and source domain should match", 195 urlHost: "sub.domain.test", 196 sourceHost: "domain.test", 197 matches: true, 198 }, 199 } { 200 tt := tt // quiet linting 201 t.Run(tt.name, func(t *testing.T) { 202 require.Equal(t, tt.matches, trust.URLMatchesHTTPSourceHost(tt.urlHost, tt.sourceHost)) 203 }) 204 } 205} 206