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  }