github.com/htcondor/osdf-client/v6@v6.13.0-rc1.0.20231009141709-766e7b4d1dc8/main_test.go (about) 1 package stashcp 2 3 import ( 4 "net" 5 "net/url" 6 "os" 7 "path/filepath" 8 "strconv" 9 "strings" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 14 namespaces "github.com/htcondor/osdf-client/v6/namespaces" 15 ) 16 17 // TestGetIps calls main.get_ips with a hostname, checking 18 // for a valid return value. 19 func TestGetIps(t *testing.T) { 20 t.Parallel() 21 22 ips := get_ips("wlcg-wpad.fnal.gov") 23 for _, ip := range ips { 24 parsedIP := net.ParseIP(ip) 25 if parsedIP.To4() != nil { 26 // Make sure that the ip doesn't start with a "[", breaks downloads 27 if strings.HasPrefix(ip, "[") { 28 t.Fatal("IPv4 address has brackets, will break downloads") 29 } 30 } else if parsedIP.To16() != nil { 31 if !strings.HasPrefix(ip, "[") { 32 t.Fatal("IPv6 address doesn't have brackets, downloads will parse it as invalid ports") 33 } 34 } 35 } 36 37 } 38 39 // TestGetToken tests getToken 40 func TestGetToken(t *testing.T) { 41 42 // Need a namespace for token acquisition 43 namespace, err := namespaces.MatchNamespace("/user/foo") 44 assert.NoError(t, err) 45 46 url, err := url.Parse("osdf:///user/foo") 47 assert.NoError(t, err) 48 49 // ENVs to test: BEARER_TOKEN, BEARER_TOKEN_FILE, XDG_RUNTIME_DIR/bt_u<uid>, TOKEN, _CONDOR_CREDS/scitoken.use, .condor_creds/scitokens.use 50 os.Setenv("BEARER_TOKEN", "bearer_token_contents") 51 token, err := getToken(url, namespace, true, "") 52 assert.NoError(t, err) 53 assert.Equal(t, "bearer_token_contents", token) 54 os.Unsetenv("BEARER_TOKEN") 55 56 // BEARER_TOKEN_FILE 57 tmpDir := t.TempDir() 58 token_contents := "bearer_token_file_contents" 59 tmpFile := []byte(token_contents) 60 bearer_token_file := filepath.Join(tmpDir, "bearer_token_file") 61 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 62 assert.NoError(t, err) 63 os.Setenv("BEARER_TOKEN_FILE", bearer_token_file) 64 token, err = getToken(url, namespace, true, "") 65 assert.NoError(t, err) 66 assert.Equal(t, token_contents, token) 67 os.Unsetenv("BEARER_TOKEN_FILE") 68 69 // XDG_RUNTIME_DIR/bt_u<uid> 70 token_contents = "bearer_token_file_contents xdg" 71 tmpFile = []byte(token_contents) 72 bearer_token_file = filepath.Join(tmpDir, "bt_u"+strconv.Itoa(os.Getuid())) 73 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 74 assert.NoError(t, err) 75 os.Setenv("XDG_RUNTIME_DIR", tmpDir) 76 token, err = getToken(url, namespace, true, "") 77 assert.NoError(t, err) 78 assert.Equal(t, token_contents, token) 79 os.Unsetenv("XDG_RUNTIME_DIR") 80 81 // TOKEN 82 token_contents = "bearer_token_file_contents token" 83 tmpFile = []byte(token_contents) 84 bearer_token_file = filepath.Join(tmpDir, "token_file") 85 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 86 assert.NoError(t, err) 87 os.Setenv("TOKEN", bearer_token_file) 88 token, err = getToken(url, namespace, true, "") 89 assert.NoError(t, err) 90 assert.Equal(t, token_contents, token) 91 os.Unsetenv("TOKEN") 92 93 // _CONDOR_CREDS/scitokens.use 94 token_contents = "bearer_token_file_contents scitokens.use" 95 tmpFile = []byte(token_contents) 96 bearer_token_file = filepath.Join(tmpDir, "scitokens.use") 97 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 98 assert.NoError(t, err) 99 os.Setenv("_CONDOR_CREDS", tmpDir) 100 token, err = getToken(url, namespace, true, "") 101 assert.NoError(t, err) 102 assert.Equal(t, token_contents, token) 103 os.Unsetenv("_CONDOR_CREDS") 104 105 // _CONDOR_CREDS/renamed.use 106 token_contents = "bearer_token_file_contents renamed.use" 107 tmpFile = []byte(token_contents) 108 tmpDir = t.TempDir() 109 bearer_token_file = filepath.Join(tmpDir, "renamed.use") 110 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 111 assert.NoError(t, err) 112 os.Setenv("_CONDOR_CREDS", tmpDir) 113 renamedUrl, err := url.Parse("renamed+osdf:///user/ligo/frames") 114 assert.NoError(t, err) 115 renamedNamespace, err := namespaces.MatchNamespace("/user/ligo/frames") 116 assert.NoError(t, err) 117 token, err = getToken(renamedUrl, renamedNamespace, false, "") 118 assert.NoError(t, err) 119 assert.Equal(t, token_contents, token) 120 os.Unsetenv("_CONDOR_CREDS") 121 122 // _CONDOR_CREDS/renamed_handle1.use via renamed_handle1+osdf:///user/ligo/frames 123 token_contents = "bearer_token_file_contents renamed_handle1.use" 124 tmpFile = []byte(token_contents) 125 tmpDir = t.TempDir() 126 bearer_token_file = filepath.Join(tmpDir, "renamed_handle1.use") 127 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 128 assert.NoError(t, err) 129 os.Setenv("_CONDOR_CREDS", tmpDir) 130 // Use a valid URL, then replace the scheme 131 renamedUrl, err = url.Parse("renamed.handle1+osdf:///user/ligo/frames") 132 renamedUrl.Scheme = "renamed_handle1+osdf" 133 assert.NoError(t, err) 134 renamedNamespace, err = namespaces.MatchNamespace("/user/ligo/frames") 135 assert.NoError(t, err) 136 token, err = getToken(renamedUrl, renamedNamespace, false, "") 137 assert.NoError(t, err) 138 assert.Equal(t, token_contents, token) 139 os.Unsetenv("_CONDOR_CREDS") 140 141 // _CONDOR_CREDS/renamed_handle2.use via renamed.handle2+osdf:///user/ligo/frames 142 token_contents = "bearer_token_file_contents renamed.handle2.use" 143 tmpFile = []byte(token_contents) 144 tmpDir = t.TempDir() 145 bearer_token_file = filepath.Join(tmpDir, "renamed_handle2.use") 146 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 147 assert.NoError(t, err) 148 os.Setenv("_CONDOR_CREDS", tmpDir) 149 renamedUrl, err = url.Parse("renamed.handle2+osdf:///user/ligo/frames") 150 assert.NoError(t, err) 151 renamedNamespace, err = namespaces.MatchNamespace("/user/ligo/frames") 152 assert.NoError(t, err) 153 token, err = getToken(renamedUrl, renamedNamespace, false, "") 154 assert.NoError(t, err) 155 assert.Equal(t, token_contents, token) 156 os.Unsetenv("_CONDOR_CREDS") 157 158 // _CONDOR_CREDS/renamed.handle3.use via renamed.handle3+osdf:///user/ligo/frames 159 token_contents = "bearer_token_file_contents renamed.handle3.use" 160 tmpFile = []byte(token_contents) 161 tmpDir = t.TempDir() 162 bearer_token_file = filepath.Join(tmpDir, "renamed.handle3.use") 163 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 164 assert.NoError(t, err) 165 os.Setenv("_CONDOR_CREDS", tmpDir) 166 renamedUrl, err = url.Parse("renamed.handle3+osdf:///user/ligo/frames") 167 assert.NoError(t, err) 168 renamedNamespace, err = namespaces.MatchNamespace("/user/ligo/frames") 169 assert.NoError(t, err) 170 token, err = getToken(renamedUrl, renamedNamespace, false, "") 171 assert.NoError(t, err) 172 assert.Equal(t, token_contents, token) 173 os.Unsetenv("_CONDOR_CREDS") 174 175 // _CONDOR_CREDS/renamed.use 176 token_contents = "bearer_token_file_contents renamed.use" 177 tmpFile = []byte(token_contents) 178 tmpDir = t.TempDir() 179 bearer_token_file = filepath.Join(tmpDir, "renamed.use") 180 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 181 assert.NoError(t, err) 182 os.Setenv("_CONDOR_CREDS", tmpDir) 183 renamedUrl, err = url.Parse("/user/ligo/frames") 184 assert.NoError(t, err) 185 renamedNamespace, err = namespaces.MatchNamespace("/user/ligo/frames") 186 assert.NoError(t, err) 187 token, err = getToken(renamedUrl, renamedNamespace, false, "renamed") 188 assert.NoError(t, err) 189 assert.Equal(t, token_contents, token) 190 os.Unsetenv("_CONDOR_CREDS") 191 192 // Current directory .condor_creds/scitokens.use 193 token_contents = "bearer_token_file_contents .condor_creds/scitokens.use" 194 tmpFile = []byte(token_contents) 195 bearer_token_file = filepath.Join(tmpDir, ".condor_creds", "scitokens.use") 196 err = os.Mkdir(filepath.Join(tmpDir, ".condor_creds"), 0755) 197 assert.NoError(t, err) 198 err = os.WriteFile(bearer_token_file, tmpFile, 0644) 199 assert.NoError(t, err) 200 currentDir, err := os.Getwd() 201 assert.NoError(t, err) 202 err = os.Chdir(tmpDir) 203 assert.NoError(t, err) 204 token, err = getToken(url, namespace, true, "") 205 assert.NoError(t, err) 206 assert.Equal(t, token_contents, token) 207 err = os.Chdir(currentDir) 208 assert.NoError(t, err) 209 210 } 211 212 // TestGetTokenName tests getTokenName 213 func TestGetTokenName(t *testing.T) { 214 cases := []struct { 215 url string 216 name string 217 scheme string 218 }{ 219 {"osdf://blah+asdf", "", "osdf"}, 220 {"stash://blah+asdf", "", "stash"}, 221 {"file://blah+asdf", "", "file"}, 222 {"tokename+osdf://blah+asdf", "tokename", "osdf"}, 223 {"tokename+stash://blah+asdf", "tokename", "stash"}, 224 {"tokename+file://blah+asdf", "tokename", "file"}, 225 {"tokename+tokename2+osdf://blah+asdf", "tokename+tokename2", "osdf"}, 226 {"token+tokename2+stash://blah+asdf", "token+tokename2", "stash"}, 227 {"token.use+stash://blah+asdf", "token.use", "stash"}, 228 {"token.blah.asdf+stash://blah+asdf", "token.blah.asdf", "stash"}, 229 } 230 for _, c := range cases { 231 url, err := url.Parse(c.url) 232 assert.NoError(t, err) 233 scheme, tokenName := getTokenName(url) 234 assert.Equal(t, c.name, tokenName) 235 assert.Equal(t, c.scheme, scheme) 236 } 237 238 } 239 240 func FuzzGetTokenName(f *testing.F) { 241 testcases := []string{"", "tokename", "tokename+tokename2"} 242 for _, tc := range testcases { 243 f.Add(tc) // Use f.Add to provide a seed corpus 244 } 245 f.Fuzz(func(t *testing.T, orig string) { 246 // Make sure it's a valid URL 247 urlString := orig + "+osdf://blah+asdf" 248 url, err := url.Parse(urlString) 249 // If it's not a valid URL, then it's not a valid token name 250 if err != nil || url.Scheme == "" { 251 return 252 } 253 assert.NoError(t, err) 254 _, tokenName := getTokenName(url) 255 assert.Equal(t, strings.ToLower(orig), tokenName, "URL: "+urlString+"URL String: "+url.String()+" Scheme: "+url.Scheme) 256 }) 257 } 258 259 func TestCorrectURLWithUnderscore(t *testing.T) { 260 tests := []struct { 261 name string 262 url string 263 expectedURL string 264 expectedScheme string 265 }{ 266 { 267 name: "LIGO URL with underscore", 268 url: "ligo_data://ligo.org/data/1", 269 expectedURL: "ligo.data://ligo.org/data/1", 270 expectedScheme: "ligo_data", 271 }, 272 { 273 name: "URL without underscore", 274 url: "http://example.com", 275 expectedURL: "http://example.com", 276 expectedScheme: "http", 277 }, 278 { 279 name: "URL with no scheme", 280 url: "example.com", 281 expectedURL: "example.com", 282 expectedScheme: "", 283 }, 284 } 285 286 for _, tt := range tests { 287 t.Run(tt.name, func(t *testing.T) { 288 actualURL, actualScheme := correctURLWithUnderscore(tt.url) 289 if actualURL != tt.expectedURL || actualScheme != tt.expectedScheme { 290 t.Errorf("correctURLWithUnderscore(%v) = %v, %v; want %v, %v", tt.url, actualURL, actualScheme, tt.expectedURL, tt.expectedScheme) 291 } 292 }) 293 } 294 } 295 296 func TestParseNoJobAd(t *testing.T) { 297 // Job ad file does not exist 298 tempDir := t.TempDir() 299 path := filepath.Join(tempDir, ".job.ad") 300 os.Setenv("_CONDOR_JOB_AD", path) 301 302 payload := payloadStruct{} 303 parse_job_ad(payload) 304 }