github.com/jaylevin/jenkins-library@v1.230.4/pkg/blackduck/blackduck_test.go (about)

     1  package blackduck
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"testing"
    10  	"time"
    11  
    12  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  type httpMockClient struct {
    17  	responseBodyForURL map[string]string
    18  	errorMessageForURL map[string]string
    19  	header             map[string]http.Header
    20  }
    21  
    22  func (c *httpMockClient) SetOptions(opts piperhttp.ClientOptions) {}
    23  func (c *httpMockClient) SendRequest(method, url string, body io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
    24  	c.header[url] = header
    25  	response := http.Response{
    26  		StatusCode: 200,
    27  		Body:       ioutil.NopCloser(bytes.NewReader([]byte(""))),
    28  	}
    29  
    30  	if c.errorMessageForURL[url] != "" {
    31  		response.StatusCode = 400
    32  		return &response, fmt.Errorf(c.errorMessageForURL[url])
    33  	}
    34  
    35  	if c.responseBodyForURL[url] != "" {
    36  		response.Body = ioutil.NopCloser(bytes.NewReader([]byte(c.responseBodyForURL[url])))
    37  		return &response, nil
    38  	}
    39  
    40  	return &response, nil
    41  }
    42  
    43  const (
    44  	authContent = `{
    45  		"bearerToken":"bearerTestToken",
    46  		"expiresInMilliseconds":7199997
    47  	}`
    48  	projectContent = `{
    49  		"totalCount": 1,
    50  		"items": [
    51  			{
    52  				"name": "SHC-PiperTest",
    53  				"_meta": {
    54  					"href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf",
    55  					"links": [
    56  						{
    57  							"rel": "versions",
    58  							"href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions"
    59  						}
    60  					]
    61  				}
    62  			}
    63  		]
    64  	}`
    65  	projectVersionContent = `{
    66  		"totalCount": 1,
    67  		"items": [
    68  			{
    69  				"versionName": "1.0",
    70  				"_meta": {
    71  					"href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36",
    72  					"links": [
    73  						{
    74  							"rel": "components",
    75  							"href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components"
    76  						},
    77  						{
    78  							"rel": "vulnerable-components",
    79  							"href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/vunlerable-bom-components"
    80  						},
    81  						{
    82  							"rel": "policy-status",
    83  							"href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/policy-status"
    84  						}
    85  					]
    86  				}
    87  			}
    88  		]
    89  	}`
    90  )
    91  
    92  func TestGetProject(t *testing.T) {
    93  	t.Run("success", func(t *testing.T) {
    94  		myTestClient := httpMockClient{
    95  			responseBodyForURL: map[string]string{
    96  				"https://my.blackduck.system/api/tokens/authenticate":             authContent,
    97  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent,
    98  			},
    99  			header: map[string]http.Header{},
   100  		}
   101  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   102  		project, err := bdClient.GetProject("SHC-PiperTest")
   103  		assert.NoError(t, err)
   104  		assert.Equal(t, "SHC-PiperTest", project.Name)
   105  		assert.Equal(t, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions", project.Metadata.Links[0].Href)
   106  		headerExpected := http.Header{"Authorization": []string{"Bearer bearerTestToken"}, "Accept": {"application/vnd.blackducksoftware.project-detail-4+json"}}
   107  		assert.Equal(t, headerExpected, myTestClient.header["https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest"])
   108  	})
   109  
   110  	t.Run("failure - not found", func(t *testing.T) {
   111  		myTestClient := httpMockClient{
   112  			responseBodyForURL: map[string]string{
   113  				"https://my.blackduck.system/api/tokens/authenticate": authContent,
   114  			},
   115  			errorMessageForURL: map[string]string{
   116  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": "not found",
   117  			},
   118  			header: map[string]http.Header{},
   119  		}
   120  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   121  		_, err := bdClient.GetProject("SHC-PiperTest")
   122  		assert.Contains(t, fmt.Sprint(err), "failed to get project 'SHC-PiperTest'")
   123  	})
   124  
   125  	t.Run("failure - 0 results", func(t *testing.T) {
   126  		myTestClient := httpMockClient{
   127  			responseBodyForURL: map[string]string{
   128  				"https://my.blackduck.system/api/tokens/authenticate": authContent,
   129  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": `{
   130  					"totalCount": 0,
   131  					"items": []
   132  				}`,
   133  			},
   134  			header: map[string]http.Header{},
   135  		}
   136  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   137  		_, err := bdClient.GetProject("SHC-PiperTest")
   138  		assert.Contains(t, fmt.Sprint(err), "project 'SHC-PiperTest' not found")
   139  	})
   140  
   141  	t.Run("failure - unmarshalling", func(t *testing.T) {
   142  		myTestClient := httpMockClient{
   143  			responseBodyForURL: map[string]string{
   144  				"https://my.blackduck.system/api/tokens/authenticate":             authContent,
   145  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": "",
   146  			},
   147  			header: map[string]http.Header{},
   148  		}
   149  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   150  		_, err := bdClient.GetProject("SHC-PiperTest")
   151  		assert.Contains(t, fmt.Sprint(err), "failed to retrieve details for project 'SHC-PiperTest'")
   152  	})
   153  }
   154  
   155  func TestGetProjectVersion(t *testing.T) {
   156  	t.Run("success", func(t *testing.T) {
   157  		myTestClient := httpMockClient{
   158  			responseBodyForURL: map[string]string{
   159  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   160  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   161  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   162  			},
   163  			header: map[string]http.Header{},
   164  		}
   165  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   166  		projectVersion, err := bdClient.GetProjectVersion("SHC-PiperTest", "1.0")
   167  		assert.NoError(t, err)
   168  		assert.Equal(t, "1.0", projectVersion.Name)
   169  		assert.Equal(t, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36", projectVersion.Metadata.Href)
   170  		headerExpected := http.Header{"Authorization": []string{"Bearer bearerTestToken"}, "Accept": {"application/vnd.blackducksoftware.project-detail-4+json"}}
   171  		assert.Equal(t, headerExpected, myTestClient.header["https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0"])
   172  	})
   173  
   174  	t.Run("failure - project not found", func(t *testing.T) {
   175  		myTestClient := httpMockClient{
   176  			responseBodyForURL: map[string]string{
   177  				"https://my.blackduck.system/api/tokens/authenticate": authContent,
   178  			},
   179  			errorMessageForURL: map[string]string{
   180  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": "not found",
   181  			},
   182  			header: map[string]http.Header{},
   183  		}
   184  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   185  		_, err := bdClient.GetProjectVersion("SHC-PiperTest", "1.0")
   186  		assert.Contains(t, fmt.Sprint(err), "failed to get project 'SHC-PiperTest'")
   187  	})
   188  
   189  	t.Run("failure - version not found", func(t *testing.T) {
   190  		myTestClient := httpMockClient{
   191  			responseBodyForURL: map[string]string{
   192  				"https://my.blackduck.system/api/tokens/authenticate":             authContent,
   193  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent,
   194  			},
   195  			errorMessageForURL: map[string]string{
   196  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": "not found",
   197  			},
   198  			header: map[string]http.Header{},
   199  		}
   200  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   201  		_, err := bdClient.GetProjectVersion("SHC-PiperTest", "1.0")
   202  		assert.Contains(t, fmt.Sprint(err), "failed to get project version 'SHC-PiperTest:1.0'")
   203  	})
   204  
   205  	t.Run("failure - 0 results", func(t *testing.T) {
   206  		myTestClient := httpMockClient{
   207  			responseBodyForURL: map[string]string{
   208  				"https://my.blackduck.system/api/tokens/authenticate":             authContent,
   209  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest": projectContent,
   210  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": `{
   211  					"totalCount": 0,
   212  					"items": []
   213  				}`,
   214  			},
   215  			header: map[string]http.Header{},
   216  		}
   217  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   218  		_, err := bdClient.GetProjectVersion("SHC-PiperTest", "1.0")
   219  		assert.Contains(t, fmt.Sprint(err), "project version 'SHC-PiperTest:1.0' not found")
   220  	})
   221  
   222  	t.Run("failure - unmarshalling", func(t *testing.T) {
   223  		myTestClient := httpMockClient{
   224  			responseBodyForURL: map[string]string{
   225  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   226  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   227  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": "",
   228  			},
   229  			header: map[string]http.Header{},
   230  		}
   231  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   232  		_, err := bdClient.GetProjectVersion("SHC-PiperTest", "1.0")
   233  		assert.Contains(t, fmt.Sprint(err), "failed to retrieve details for project version 'SHC-PiperTest:1.0'")
   234  	})
   235  }
   236  
   237  func TestGetVulnerabilities(t *testing.T) {
   238  	t.Run("success", func(t *testing.T) {
   239  		myTestClient := httpMockClient{
   240  			responseBodyForURL: map[string]string{
   241  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   242  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   243  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   244  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/vunlerable-bom-components?limit=999&offset=0": `{
   245  					"totalCount": 1,
   246  					"items": [
   247  						{
   248  							"componentName": "Spring Framework",
   249  							"componentVersionName": "5.3.2",
   250  							"vulnerabilityWithRemediation" : {
   251  								"vulnerabilityName" : "BDSA-2019-2021",
   252  								"baseScore" : 1.0,
   253        							"overallScore" : 1.0,
   254  								"severity" : "HIGH",
   255  								"remediationStatus" : "IGNORED",
   256  								"description" : "description"
   257  							}
   258  						}
   259  					]
   260  				}`,
   261  			},
   262  			header: map[string]http.Header{},
   263  		}
   264  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   265  		vulns, err := bdClient.GetVulnerabilities("SHC-PiperTest", "1.0")
   266  		assert.NoError(t, err)
   267  		assert.GreaterOrEqual(t, vulns.TotalCount, 1)
   268  	})
   269  
   270  	t.Run("Success - 0 vulns", func(t *testing.T) {
   271  		myTestClient := httpMockClient{
   272  			responseBodyForURL: map[string]string{
   273  				"https://my.blackduck.system/api/tokens/authenticate":                                                                                                                      authContent,
   274  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                                                                                          projectContent,
   275  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0":                                                                projectVersionContent,
   276  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/vunlerable-bom-components?limit=999&offset=0": `{"totalCount":0,"items":[]}`,
   277  			},
   278  			header: map[string]http.Header{},
   279  		}
   280  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   281  		vulns, err := bdClient.GetVulnerabilities("SHC-PiperTest", "1.0")
   282  		assert.NoError(t, err)
   283  		assert.Equal(t, vulns.TotalCount, 0)
   284  	})
   285  
   286  	t.Run("Failure - unmarshalling", func(t *testing.T) {
   287  		myTestClient := httpMockClient{
   288  			responseBodyForURL: map[string]string{
   289  				"https://my.blackduck.system/api/tokens/authenticate":                                                                                                                      authContent,
   290  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                                                                                          projectContent,
   291  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0":                                                                projectVersionContent,
   292  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/vunlerable-bom-components?limit=999&offset=0": "",
   293  			},
   294  			header: map[string]http.Header{},
   295  		}
   296  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   297  		_, err := bdClient.GetVulnerabilities("SHC-PiperTest", "1.0")
   298  		assert.Contains(t, fmt.Sprint(err), "failed to retrieve Vulnerability details for project version 'SHC-PiperTest:1.0'")
   299  	})
   300  }
   301  
   302  func TestGetComponents(t *testing.T) {
   303  	t.Run("success", func(t *testing.T) {
   304  		myTestClient := httpMockClient{
   305  			responseBodyForURL: map[string]string{
   306  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   307  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   308  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   309  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?limit=999&offset=0": `{
   310  					"totalCount": 2,
   311  					"items" : [
   312  						{
   313  							"componentName": "Spring Framework",
   314  							"componentVersionName": "5.3.9"
   315  						}, {
   316  							"componentName": "Apache Tomcat",
   317  							"componentVersionName": "9.0.52"
   318  						}
   319  					]
   320  				}`,
   321  			},
   322  			header: map[string]http.Header{},
   323  		}
   324  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   325  		components, err := bdClient.GetComponents("SHC-PiperTest", "1.0")
   326  		assert.NoError(t, err)
   327  		assert.GreaterOrEqual(t, components.TotalCount, 2)
   328  	})
   329  
   330  	t.Run("Failure - 0 components", func(t *testing.T) {
   331  		myTestClient := httpMockClient{
   332  			responseBodyForURL: map[string]string{
   333  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   334  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   335  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   336  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?limit=999&offset=0": `{
   337  					"totalCount": 0,
   338  					"items" : []}`,
   339  			},
   340  			header: map[string]http.Header{},
   341  		}
   342  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   343  		components, err := bdClient.GetComponents("SHC-PiperTest", "1.0")
   344  		assert.Contains(t, fmt.Sprint(err), "No Components found for project version 'SHC-PiperTest:1.0'")
   345  		assert.Nilf(t, components, "Expected Components to be nil")
   346  	})
   347  
   348  	t.Run("Failure - unmarshalling", func(t *testing.T) {
   349  		myTestClient := httpMockClient{
   350  			responseBodyForURL: map[string]string{
   351  				"https://my.blackduck.system/api/tokens/authenticate":                                                                                                       authContent,
   352  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                                                                           projectContent,
   353  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0":                                                 projectVersionContent,
   354  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?limit=999&offset=0": "",
   355  			},
   356  			header: map[string]http.Header{},
   357  		}
   358  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   359  		components, err := bdClient.GetComponents("SHC-PiperTest", "1.0")
   360  		assert.Contains(t, fmt.Sprint(err), "failed to retrieve component details for project version 'SHC-PiperTest:1.0'")
   361  		assert.Nilf(t, components, "Expected Components to be nil")
   362  	})
   363  }
   364  
   365  func TestGetComponentsWithLicensePolicyRule(t *testing.T) {
   366  	t.Run("success", func(t *testing.T) {
   367  		myTestClient := httpMockClient{
   368  			responseBodyForURL: map[string]string{
   369  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   370  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   371  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   372  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?filter=policyCategory%3Alicense&limit=999&offset=0": `{
   373  					"totalCount": 2,
   374  					"items" : [
   375  						{
   376  							"componentName": "Spring Framework",
   377  							"componentVersionName": "5.3.9",
   378  							"policyStatus": "IN_VIOLATION"
   379  						}, {
   380  							"componentName": "Apache Tomcat",
   381  							"componentVersionName": "9.0.52",
   382  							"policyStatus": "NOT_IN_VIOLATION"
   383  						}
   384  					]
   385  				}`,
   386  			},
   387  			header: map[string]http.Header{},
   388  		}
   389  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   390  		components, err := bdClient.GetComponentsWithLicensePolicyRule("SHC-PiperTest", "1.0")
   391  		assert.NoError(t, err)
   392  		assert.GreaterOrEqual(t, components.TotalCount, 2)
   393  		assert.Equal(t, components.Items[0].PolicyStatus, "IN_VIOLATION")
   394  	})
   395  
   396  	t.Run("Failure - 0 components", func(t *testing.T) {
   397  		myTestClient := httpMockClient{
   398  			responseBodyForURL: map[string]string{
   399  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   400  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   401  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   402  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?filter=policyCategory%3Alicense&limit=999&offset=0": `{
   403  					"totalCount": 0,
   404  					"items" : []}`,
   405  			},
   406  			header: map[string]http.Header{},
   407  		}
   408  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   409  		components, err := bdClient.GetComponentsWithLicensePolicyRule("SHC-PiperTest", "1.0")
   410  		assert.NoError(t, err)
   411  		assert.NotNil(t, components)
   412  		assert.Equal(t, components.TotalCount, 0)
   413  	})
   414  
   415  	t.Run("Failure - unmarshalling", func(t *testing.T) {
   416  		myTestClient := httpMockClient{
   417  			responseBodyForURL: map[string]string{
   418  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   419  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   420  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   421  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/components?filter=policyCategory%3Alicense&limit=999&offset=0": "",
   422  			},
   423  			header: map[string]http.Header{},
   424  		}
   425  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   426  		components, err := bdClient.GetComponentsWithLicensePolicyRule("SHC-PiperTest", "1.0")
   427  		assert.Contains(t, fmt.Sprint(err), "failed to retrieve component details for project version 'SHC-PiperTest:1.0'")
   428  		assert.Nilf(t, components, "Expected Components to be nil")
   429  	})
   430  }
   431  
   432  func TestGetPolicyStatus(t *testing.T) {
   433  	t.Run("success", func(t *testing.T) {
   434  		myTestClient := httpMockClient{
   435  			responseBodyForURL: map[string]string{
   436  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   437  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   438  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   439  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/policy-status": `{
   440  					"overallStatus": "IN_VIOLATION",
   441  					"componentVersionPolicyViolationDetails": {
   442  						"name": "IN_VIOLATION",
   443  						"severityLevels": [
   444  						  {	"name": "BLOCKER", "value": 16 },
   445  						  { "name": "CRITICAL", "value": 1 },
   446  						  { "name": "MAJOR", "value": 0 },
   447  						  { "name": "MINOR", "value": 0 },
   448  						  { "name": "TRIVIAL", "value": 0 },
   449  						  { "name": "UNSPECIFIED", "value": 0 },
   450  						  { "name": "OK", "value": 0}
   451  						]
   452  					  }
   453  				}`,
   454  			},
   455  			header: map[string]http.Header{},
   456  		}
   457  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   458  		policyStatus, err := bdClient.GetPolicyStatus("SHC-PiperTest", "1.0")
   459  		assert.NoError(t, err)
   460  		assert.Equal(t, policyStatus.OverallStatus, "IN_VIOLATION")
   461  		assert.Equal(t, len(policyStatus.PolicyVersionDetails.SeverityLevels), 7)
   462  		assert.Equal(t, policyStatus.PolicyVersionDetails.Name, "IN_VIOLATION")
   463  	})
   464  
   465  	t.Run("Failure - unmarshalling", func(t *testing.T) {
   466  		myTestClient := httpMockClient{
   467  			responseBodyForURL: map[string]string{
   468  				"https://my.blackduck.system/api/tokens/authenticate":                                                                                       authContent,
   469  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                                                           projectContent,
   470  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0":                                 projectVersionContent,
   471  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36/policy-status": "",
   472  			},
   473  			header: map[string]http.Header{},
   474  		}
   475  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   476  		policyStatus, err := bdClient.GetPolicyStatus("SHC-PiperTest", "1.0")
   477  		assert.Contains(t, fmt.Sprint(err), "failed to retrieve Policy violation details for project version 'SHC-PiperTest:1.0'")
   478  		assert.Nilf(t, policyStatus, "Expected Components to be nil")
   479  	})
   480  }
   481  
   482  func TestGetProjectVersionLink(t *testing.T) {
   483  	t.Run("Success Case", func(t *testing.T) {
   484  		myTestClient := httpMockClient{
   485  			responseBodyForURL: map[string]string{
   486  				"https://my.blackduck.system/api/tokens/authenticate":                                                       authContent,
   487  				"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                           projectContent,
   488  				"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0": projectVersionContent,
   489  			},
   490  			header: map[string]http.Header{},
   491  		}
   492  		bdClient := NewClient("token", "https://my.blackduck.system", &myTestClient)
   493  		link, err := bdClient.GetProjectVersionLink("SHC-PiperTest", "1.0")
   494  		assert.NoError(t, err)
   495  		assert.Equal(t, link, "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36")
   496  	})
   497  }
   498  
   499  func TestAuthenticate(t *testing.T) {
   500  	t.Run("success", func(t *testing.T) {
   501  		myTestClient := httpMockClient{
   502  			responseBodyForURL: map[string]string{
   503  				"https://my.blackduck.system/api/tokens/authenticate": authContent,
   504  			},
   505  			header: map[string]http.Header{},
   506  		}
   507  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   508  		err := bdClient.authenticate()
   509  		assert.NoError(t, err)
   510  		headerExpected := http.Header{"Authorization": {"token myTestToken"}, "Accept": {"application/vnd.blackducksoftware.user-4+json"}}
   511  		assert.Equal(t, headerExpected, myTestClient.header["https://my.blackduck.system/api/tokens/authenticate"])
   512  	})
   513  
   514  	t.Run("authentication failure", func(t *testing.T) {
   515  		myTestClient := httpMockClient{
   516  			errorMessageForURL: map[string]string{
   517  				"https://my.blackduck.system/api/tokens/authenticate": "not authorized",
   518  			},
   519  			header: map[string]http.Header{},
   520  		}
   521  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   522  		err := bdClient.authenticate()
   523  		assert.EqualError(t, err, "authentication to BlackDuck API failed: request to BlackDuck API failed: not authorized")
   524  	})
   525  
   526  	t.Run("parse failure", func(t *testing.T) {
   527  		myTestClient := httpMockClient{
   528  			responseBodyForURL: map[string]string{
   529  				"https://my.blackduck.system/api/tokens/authenticate": "",
   530  			},
   531  			header: map[string]http.Header{},
   532  		}
   533  		bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   534  		err := bdClient.authenticate()
   535  		assert.Contains(t, fmt.Sprint(err), "failed to parse BlackDuck response")
   536  	})
   537  }
   538  
   539  func TestSendRequest(t *testing.T) {
   540  	myTestClient := httpMockClient{
   541  		responseBodyForURL: map[string]string{
   542  			"https://my.blackduck.system/api/endpoint":        "testContent",
   543  			"https://my.blackduck.system/api/endpoint?q=test": "testContentQuery",
   544  		},
   545  		header: map[string]http.Header{},
   546  	}
   547  	bdClient := NewClient("myTestToken", "https://my.blackduck.system", &myTestClient)
   548  
   549  	t.Run("simple", func(t *testing.T) {
   550  		responseBody, err := bdClient.sendRequest(http.MethodGet, "api/endpoint", map[string]string{}, nil, http.Header{})
   551  		assert.NoError(t, err)
   552  		assert.Equal(t, "testContent", string(responseBody))
   553  	})
   554  
   555  	t.Run("with query params and bearer", func(t *testing.T) {
   556  		bdClient.BearerToken = "testBearer"
   557  		responseBody, err := bdClient.sendRequest(http.MethodGet, "api/endpoint", map[string]string{"q": "test"}, nil, http.Header{})
   558  		assert.NoError(t, err)
   559  		assert.Equal(t, "testContentQuery", string(responseBody))
   560  		assert.Equal(t, http.Header{"Authorization": {"Bearer testBearer"}}, myTestClient.header["https://my.blackduck.system/api/endpoint?q=test"])
   561  	})
   562  }
   563  
   564  func TestApiURL(t *testing.T) {
   565  	tt := []struct {
   566  		description string
   567  		apiEndpoint string
   568  		client      Client
   569  		expected    string
   570  	}{
   571  		{
   572  			description: "trailing / in path",
   573  			apiEndpoint: "/my/path/",
   574  			client:      Client{serverURL: "https://my.test.server"},
   575  			expected:    "https://my.test.server/my/path",
   576  		},
   577  		{
   578  			description: "trailing / in server",
   579  			apiEndpoint: "/my/path",
   580  			client:      Client{serverURL: "https://my.test.server/"},
   581  			expected:    "https://my.test.server/my/path",
   582  		},
   583  	}
   584  
   585  	for _, test := range tt {
   586  		res, err := test.client.apiURL(test.apiEndpoint)
   587  		assert.NoError(t, err)
   588  		assert.Equalf(t, test.expected, res.String(), test.description)
   589  	}
   590  }
   591  
   592  func TestAuthenticationValid(t *testing.T) {
   593  	tt := []struct {
   594  		description string
   595  		now         time.Time
   596  		client      Client
   597  		expected    bool
   598  	}{
   599  		{
   600  			description: "login still valid",
   601  			now:         time.Date(2020, time.January, 1, 12, 0, 0, 0, time.UTC),
   602  			client:      Client{BearerExpiresInMilliseconds: 120000, lastAuthentication: time.Date(2020, time.January, 01, 11, 59, 0, 0, time.UTC)},
   603  			expected:    true,
   604  		},
   605  		{
   606  			description: "login still valid - edge",
   607  			now:         time.Date(2020, time.January, 1, 12, 0, 0, 0, time.UTC),
   608  			client:      Client{BearerExpiresInMilliseconds: 120000, lastAuthentication: time.Date(2020, time.January, 01, 11, 58, 1, 0, time.UTC)},
   609  			expected:    true,
   610  		},
   611  		{
   612  			description: "login expired",
   613  			now:         time.Date(2020, time.January, 1, 12, 0, 0, 0, time.UTC),
   614  			client:      Client{BearerExpiresInMilliseconds: 120000, lastAuthentication: time.Date(2020, time.January, 01, 11, 57, 0, 0, time.UTC)},
   615  			expected:    false,
   616  		},
   617  		{
   618  			description: "login expired - edge",
   619  			now:         time.Date(2020, time.January, 1, 12, 0, 0, 0, time.UTC),
   620  			client:      Client{BearerExpiresInMilliseconds: 120000, lastAuthentication: time.Date(2020, time.January, 01, 11, 58, 0, 0, time.UTC)},
   621  			expected:    false,
   622  		},
   623  	}
   624  
   625  	for _, test := range tt {
   626  		assert.Equalf(t, test.expected, test.client.authenticationValid(test.now), test.description)
   627  	}
   628  }
   629  
   630  func TestUrlPath(t *testing.T) {
   631  	assert.Equal(t, "/this/is/the/path", urlPath("https://the.server.domain:8080/this/is/the/path"))
   632  }