github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/fortify/fortify_test.go (about)

     1  //go:build unit
     2  // +build unit
     3  
     4  package fortify
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"os"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/go-openapi/strfmt"
    17  	ff "github.com/piper-validation/fortify-client-go/fortify"
    18  	"github.com/piper-validation/fortify-client-go/models"
    19  	"github.com/sirupsen/logrus"
    20  	"github.com/stretchr/testify/assert"
    21  
    22  	piperHttp "github.com/SAP/jenkins-library/pkg/http"
    23  )
    24  
    25  func spinUpServer(f func(http.ResponseWriter, *http.Request)) (*SystemInstance, *httptest.Server) {
    26  	server := httptest.NewServer(http.HandlerFunc(f))
    27  
    28  	parts := strings.Split(server.URL, "://")
    29  	client := ff.NewHTTPClientWithConfig(strfmt.Default, &ff.TransportConfig{
    30  		Host:     parts[1],
    31  		Schemes:  []string{parts[0]},
    32  		BasePath: ""},
    33  	)
    34  
    35  	httpClient := &piperHttp.Client{}
    36  	httpClientOptions := piperHttp.ClientOptions{Token: "test2456", TransportTimeout: 60 * time.Second}
    37  	httpClient.SetOptions(httpClientOptions)
    38  
    39  	sys := NewSystemInstanceForClient(client, httpClient, server.URL, "test2456", 60*time.Second)
    40  	return sys, server
    41  }
    42  
    43  func TestCreateTransportConfig(t *testing.T) {
    44  	t.Run("Valid URL", func(t *testing.T) {
    45  		config := createTransportConfig("http://some.fortify.host.com/ssc", "/api/v2")
    46  		assert.Equal(t, []string{"http"}, config.Schemes)
    47  		assert.Equal(t, "some.fortify.host.com", config.Host)
    48  		assert.Equal(t, "ssc/api/v2", config.BasePath)
    49  	})
    50  	t.Run("Slashes are trimmed", func(t *testing.T) {
    51  		config := createTransportConfig("http://some.fortify.host.com/ssc//", "//api/v2/")
    52  		assert.Equal(t, []string{"http"}, config.Schemes)
    53  		assert.Equal(t, "some.fortify.host.com", config.Host)
    54  		assert.Equal(t, "ssc/api/v2", config.BasePath)
    55  	})
    56  	t.Run("URL missing scheme results in no error", func(t *testing.T) {
    57  		config := createTransportConfig("some.fortify.host.com/ssc", "api/v1")
    58  		assert.Equal(t, []string{"https"}, config.Schemes)
    59  		assert.Equal(t, "some.fortify.host.com", config.Host)
    60  		assert.Equal(t, "ssc/api/v1", config.BasePath)
    61  	})
    62  	t.Run("URL with more than one slash is accepted", func(t *testing.T) {
    63  		config := createTransportConfig("https://some.fortify.host.com/some/path/ssc", "api/v1")
    64  		assert.Equal(t, []string{"https"}, config.Schemes)
    65  		assert.Equal(t, "some.fortify.host.com", config.Host)
    66  		assert.Equal(t, "some/path/ssc/api/v1", config.BasePath)
    67  	})
    68  }
    69  
    70  func TestNewSystemInstance(t *testing.T) {
    71  	t.Run("fields are initialized", func(t *testing.T) {
    72  		sys := NewSystemInstance("https://some.fortify.host.com/ssc", "api/v1", "akjhskjhks", "", 10*time.Second)
    73  		assert.IsType(t, ff.Fortify{}, *sys.client, "Expected to get a Fortify client instance")
    74  		assert.IsType(t, piperHttp.Client{}, *sys.httpClient, "Expected to get a HTTP client instance")
    75  		assert.IsType(t, logrus.Entry{}, *sys.logger, "Expected to get a logrus entry instance")
    76  		assert.Equal(t, 10*time.Second, sys.timeout, "Expected different timeout value")
    77  		assert.Equal(t, "akjhskjhks", sys.token, "Expected different token value")
    78  		assert.Equal(t, "https://some.fortify.host.com/ssc", sys.serverURL)
    79  	})
    80  	t.Run("SSC URL is trimmed", func(t *testing.T) {
    81  		sys := NewSystemInstance("https://some.fortify.host.com/ssc/", "api/v1", "akjhskjhks", "", 10*time.Second)
    82  		assert.Equal(t, "https://some.fortify.host.com/ssc", sys.serverURL)
    83  	})
    84  }
    85  
    86  func TestGetProjectByName(t *testing.T) {
    87  	// Start a local HTTP server
    88  	autocreateCalled := false
    89  	commitCalled := false
    90  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
    91  		if req.URL.Path == "/projects" && req.URL.RawQuery == "q=name%3A%22python-test%22" {
    92  			header := rw.Header()
    93  			header.Add("Content-type", "application/json")
    94  			rw.Write([]byte(
    95  				`{"data": [{"_href": "https://fortify/ssc/api/v1/projects/4711","createdBy": "someUser","name": "python-test",
    96  				"description": "","id": 4711,"creationDate": "2018-12-03T06:29:38.197+0000","issueTemplateId": "dasdasdasdsadasdasdasdasdas"}],
    97  				"count": 1,"responseCode": 200,"links": {"last": {"href": "https://fortify/ssc/api/v1/projects?q=name%A3python-test&start=0"},
    98  				"first": {"href": "https://fortify/ssc/api/v1/projects?q=name%3Apython-test&start=0"}}}`))
    99  			return
   100  		}
   101  		if req.URL.Path == "/projects" && req.URL.RawQuery == "q=name%3A%22python+with+space+test%22" {
   102  			header := rw.Header()
   103  			header.Add("Content-type", "application/json")
   104  			rw.Write([]byte(
   105  				`{"data": [{"_href": "https://fortify/ssc/api/v1/projects/4711","createdBy": "someUser","name": "python with space test",
   106  				"description": "","id": 4711,"creationDate": "2018-12-03T06:29:38.197+0000","issueTemplateId": "dasdasdasdsadasdasdasdasdas"}],
   107  				"count": 1,"responseCode": 200,"links": {"last": {"href": "https://fortify/ssc/api/v1/projects?q=name%3A%22python+with+space+test%22&start=0"},
   108  				"first": {"href": "https://fortify/ssc/api/v1/projects?q=name%3A%22python+with+space+test%22&start=0"}}}`))
   109  			return
   110  		}
   111  		if req.URL.Path == "/projects" && req.URL.RawQuery == "q=name%3A%22python-empty%22" {
   112  			header := rw.Header()
   113  			header.Add("Content-type", "application/json")
   114  			rw.Write([]byte(
   115  				`{"data": [],"count": 0,"responseCode": 404,"links": {}}`))
   116  			return
   117  		}
   118  		if req.URL.Path == "/projects" && req.URL.RawQuery == "q=name%3A%22python-error%22" {
   119  			rw.WriteHeader(400)
   120  			return
   121  		}
   122  		if req.URL.Path == "/projectVersions" && req.Method == "POST" {
   123  			autocreateCalled = true
   124  			header := rw.Header()
   125  			header.Add("Content-type", "application/json")
   126  			rw.WriteHeader(201)
   127  			rw.Write([]byte(
   128  				`{"data":{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
   129  				"project":{"id":815,"name":"autocreate","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
   130  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
   131  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
   132  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
   133  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
   134  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
   135  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
   136  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
   137  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
   138  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
   139  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null},
   140  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/815/versions?start=0"},
   141  				"first":{"href":"https://fortify/ssc/api/v1/projects/815/versions?start=0"}}}`))
   142  			return
   143  		}
   144  		if req.URL.Path == "/projectVersions/10172" {
   145  			commitCalled = true
   146  			header := rw.Header()
   147  			header.Add("Content-type", "application/json")
   148  			rw.Write([]byte(
   149  				`{"data": {"_href": "https://fortify/ssc/api/v1/projects/815", "committed": true,"createdBy": "someUser","name": "autocreate",
   150  				"description": "","id": 815,"creationDate": "2018-12-03T06:29:38.197+0000","issueTemplateId": "dasdasdasdsadasdasdasdasdas"},
   151  				"count": 1,"responseCode": 200,"links": {"last": {"href": "https://fortify/ssc/api/v1/projects?q=name%3Apython-test&start=0"},
   152  				"first": {"href": ""}}}`))
   153  			return
   154  		}
   155  	})
   156  	// Close the server when test finishes
   157  	defer server.Close()
   158  
   159  	t.Run("test success", func(t *testing.T) {
   160  		result, err := sys.GetProjectByName("python-test", false, "")
   161  		assert.NoError(t, err, "GetProjectByName call not successful")
   162  		assert.Equal(t, "python-test", strings.ToLower(*result.Name), "Expected to get python-test")
   163  	})
   164  
   165  	t.Run("test space", func(t *testing.T) {
   166  		result, err := sys.GetProjectByName("python with space test", false, "")
   167  		assert.NoError(t, err, "GetProjectByName call not successful")
   168  		assert.Equal(t, "python with space test", strings.ToLower(*result.Name), "Expected to get python with space test")
   169  	})
   170  
   171  	t.Run("test empty", func(t *testing.T) {
   172  		_, err := sys.GetProjectByName("python-empty", false, "")
   173  		assert.Error(t, err, "Expected error but got success")
   174  	})
   175  
   176  	t.Run("test error", func(t *testing.T) {
   177  		_, err := sys.GetProjectByName("python-error", false, "")
   178  		assert.Error(t, err, "Expected error but got success")
   179  	})
   180  
   181  	t.Run("test auto create success", func(t *testing.T) {
   182  		result, err := sys.GetProjectByName("autocreate", true, "123456")
   183  		assert.NoError(t, err, "GetProjectByName call not successful")
   184  		assert.Equal(t, true, autocreateCalled, "Expected autocreation function to be called but wasn't")
   185  		assert.Equal(t, true, commitCalled, "Expected commit function to be called but wasn't")
   186  		assert.Equal(t, "autocreate", strings.ToLower(*result.Name), "Expected to get autocreate project")
   187  	})
   188  }
   189  
   190  func TestGetProjectVersionDetailsByProjectIDAndVersionName(t *testing.T) {
   191  	// Start a local HTTP server
   192  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   193  		if req.URL.Path == "/projects/4711/versions" {
   194  			header := rw.Header()
   195  			header.Add("Content-type", "application/json")
   196  			rw.Write([]byte(
   197  				`{"data":[{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
   198  				"project":{"id":4711,"name":"python-test","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
   199  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
   200  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
   201  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
   202  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
   203  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
   204  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
   205  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
   206  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
   207  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
   208  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null}],
   209  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"},
   210  				"first":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"}}}`))
   211  			return
   212  		}
   213  		if req.URL.Path == "/projects/777/versions" {
   214  			header := rw.Header()
   215  			header.Add("Content-type", "application/json")
   216  			rw.Write([]byte(
   217  				`{"data": [],"count": 0,"responseCode": 404,"links": {}}`))
   218  			return
   219  		}
   220  		if req.URL.Path == "/projects/999/versions" {
   221  			rw.WriteHeader(500)
   222  			return
   223  		}
   224  		if req.URL.Path == "/projectVersions" {
   225  			header := rw.Header()
   226  			header.Add("Content-type", "application/json")
   227  			rw.WriteHeader(201)
   228  			rw.Write([]byte(
   229  				`{"data":{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
   230  				"project":{"id":815,"name":"autocreate","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
   231  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
   232  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
   233  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
   234  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
   235  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
   236  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
   237  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
   238  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
   239  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
   240  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null},
   241  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/815/versions?start=0"},
   242  				"first":{"href":"https://fortify/ssc/api/v1/projects/815/versions?start=0"}}}`))
   243  			return
   244  		}
   245  		if req.URL.Path == "/projectVersions/0" {
   246  			header := rw.Header()
   247  			header.Add("Content-type", "application/json")
   248  			rw.Write([]byte(
   249  				`{"data":{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
   250  				"project":{"id":815,"name":"autocreate","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
   251  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
   252  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
   253  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
   254  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
   255  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
   256  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
   257  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
   258  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
   259  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
   260  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null},
   261  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/815/versions?start=0"},
   262  				"first":{"href":"https://fortify/ssc/api/v1/projects/815/versions?start=0"}}}`))
   263  			return
   264  		}
   265  		if req.URL.Path == "/projects/8888/versions" && req.URL.RawQuery == "q=name%3A%221%22" {
   266  			header := rw.Header()
   267  			header.Add("Content-type", "application/json")
   268  			rw.Write([]byte(`{"data":[{"id":9910,"project":{"id":8888,"name":"test","description":"Created by Go script","creationDate":"2022-06-24T04:44:12.344+0000",
   269  				"createdBy":"jajajajja","issueTemplateId":"asxasca-asff-b57aedaf41"},"name":"1","description":"","createdBy":"afsafa","creationDate":"2021-07-17T04:09:17.909+0000",
   270  				"sourceBasePath":null,"committed":true,"issueTemplateId":"asdawffbcad88eb041","issueTemplateName":"aiudfnwofn","loadProperties":null,"staleIssueTemplate":false,
   271  				"snapshotOutOfDate":false,"refreshRequired":false,"attachmentsOutOfDate":false,"migrationVersion":null,"masterAttrGuid":"akjnfkjsnfkj686b","tracesOutOfDate":false,
   272  				"issueTemplateModifiedTime":1556502937909,"active":true,"obfuscatedId":null,"owner":"","serverVersion":21.2,"siteId":null,"latestScanId":null,"mode":"BASIC",
   273  				"currentState":{"id":9910,"committed":true,"attentionRequired":false,"analysisResultsExist":false,"auditEnabled":false,"lastFprUploadDate":null,"extraMessage":null,
   274  				"analysisUploadEnabled":true,"batchBugSubmissionExists":false,"hasCustomIssues":false,"metricEvaluationDate":null,"deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0,
   275  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0},"bugTrackerPluginId":null,"bugTrackerEnabled":false,"securityGroup":null,"status":null,
   276  				"assignedIssuesCount":0,"customTagValuesAutoApply":null,"autoPredict":null,"predictionPolicy":null,"_href":"https://fortify/ssc/api/v1/projectVersions/8888"}],"count":1,
   277  				"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/8888/versions?q=name%3A1&start=0"},"first":{"href":"https://fortify/ssc/api/v1/projects/8888/versions?q=name%3A1&start=0"}}}`))
   278  			return
   279  		}
   280  	})
   281  
   282  	// Close the server when test finishes
   283  	defer server.Close()
   284  
   285  	t.Run("test success", func(t *testing.T) {
   286  		result, err := sys.GetProjectVersionDetailsByProjectIDAndVersionName(4711, "0", false, "")
   287  		assert.NoError(t, err, "GetProjectVersionDetailsByNameAndProjectID call not successful")
   288  		assert.Equal(t, "0", *result.Name, "Expected to get project version with different name")
   289  	})
   290  
   291  	t.Run("test empty", func(t *testing.T) {
   292  		_, err := sys.GetProjectVersionDetailsByProjectIDAndVersionName(777, "python-empty", false, "")
   293  		assert.Error(t, err, "Expected error but got success")
   294  	})
   295  
   296  	t.Run("test HTTP error", func(t *testing.T) {
   297  		_, err := sys.GetProjectVersionDetailsByProjectIDAndVersionName(999, "python-http-error", false, "")
   298  		assert.Error(t, err, "Expected error but got success")
   299  	})
   300  
   301  	t.Run("test auto create success", func(t *testing.T) {
   302  		result, err := sys.GetProjectVersionDetailsByProjectIDAndVersionName(815, "0", true, "autocreate")
   303  		assert.NoError(t, err, "GetProjectVersionDetailsByNameAndProjectID call not successful")
   304  		assert.Equal(t, "0", *result.Name, "Expected to get project version with different name")
   305  		assert.Equal(t, "autocreate", *result.Project.Name, "Expected to get project with different name")
   306  	})
   307  	t.Run("test filter projectVersion", func(t *testing.T) {
   308  		result, err := sys.GetProjectVersionDetailsByProjectIDAndVersionName(8888, "1", true, "autocreate")
   309  		assert.NoError(t, err, "GetProjectVersionDetailsByNameAndProjectID call not successful")
   310  		assert.Equal(t, "1", *result.Name, "Expected to get exact project version")
   311  	})
   312  }
   313  
   314  func TestGetProjectVersionAttributesByProjectVersionID(t *testing.T) {
   315  	// Start a local HTTP server
   316  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   317  		if req.URL.Path == "/projectVersions/4711/attributes" {
   318  			header := rw.Header()
   319  			header.Add("Content-type", "application/json")
   320  			rw.Write([]byte(
   321  				`{"data": [{"_href": "https://fortify/ssc/api/v1/projectVersions/4711/attributes/4712","attributeDefinitionId": 31,
   322  				"values": null,"guid": "gdgfdgfdgfdgfd","id": 4712,"value": "abcd"}],"count": 8,"responseCode": 200}`))
   323  			return
   324  		}
   325  		if req.URL.Path == "/projectVersions/777/attributes" {
   326  			header := rw.Header()
   327  			header.Add("Content-type", "application/json")
   328  			rw.Write([]byte(
   329  				`{"data": [],"count": 0,"responseCode": 404,"links": {}}`))
   330  			return
   331  		}
   332  		if req.URL.Path == "/projectVersions/999/attributes" {
   333  			rw.WriteHeader(500)
   334  			return
   335  		}
   336  	})
   337  
   338  	// Close the server when test finishes
   339  	defer server.Close()
   340  
   341  	t.Run("test success", func(t *testing.T) {
   342  		result, err := sys.GetProjectVersionAttributesByProjectVersionID(4711)
   343  		assert.NoError(t, err, "GetProjectVersionAttributesByProjectVersionID call not successful")
   344  		assert.Equal(t, "abcd", *result[0].Value, "Expected to get attribute with different value")
   345  		assert.Equal(t, int64(4712), result[0].ID, "Expected to get attribute with different id")
   346  	})
   347  
   348  	t.Run("test empty", func(t *testing.T) {
   349  		result, err := sys.GetProjectVersionAttributesByProjectVersionID(777)
   350  		assert.NoError(t, err, "GetProjectVersionAttributesByID call not successful")
   351  		assert.Equal(t, 0, len(result), "Expected to not get any attributes")
   352  	})
   353  
   354  	t.Run("test HTTP error", func(t *testing.T) {
   355  		_, err := sys.GetProjectVersionAttributesByProjectVersionID(999)
   356  		assert.Error(t, err, "Expected error but got success")
   357  	})
   358  }
   359  
   360  func TestSetProjectVersionAttributesByProjectVersionID(t *testing.T) {
   361  	// Start a local HTTP server
   362  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   363  		if req.URL.Path == "/projectVersions/4711/attributes" {
   364  			header := rw.Header()
   365  			header.Add("Content-type", "application/json")
   366  			bodyBytes, _ := io.ReadAll(req.Body)
   367  			bodyString := string(bodyBytes)
   368  			response := `{"data": `
   369  			response += bodyString
   370  			response += `,"count": 1,"responseCode": 200}`
   371  			rw.WriteHeader(200)
   372  			rw.Write([]byte(response))
   373  			return
   374  		}
   375  	})
   376  
   377  	// Close the server when test finishes
   378  	defer server.Close()
   379  
   380  	t.Run("test success", func(t *testing.T) {
   381  		value := "abcd"
   382  		defID := int64(18)
   383  		attributes := []*models.Attribute{{ID: 4712, Value: &value, AttributeDefinitionID: &defID}}
   384  		result, err := sys.SetProjectVersionAttributesByProjectVersionID(4711, attributes)
   385  		assert.NoError(t, err, "SetProjectVersionAttributesByProjectVersionID call not successful")
   386  		assert.Equal(t, 1, len(result), "Expected to get slice with different amount of values")
   387  		assert.Equal(t, "abcd", *result[0].Value, "Expected to get attribute with different value")
   388  		assert.Equal(t, int64(4712), result[0].ID, "Expected to get attribute with different id")
   389  	})
   390  }
   391  
   392  func TestCreateProjectVersion(t *testing.T) {
   393  	// Start a local HTTP server
   394  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   395  		if req.URL.Path == "/projectVersions" {
   396  			header := rw.Header()
   397  			header.Add("Content-type", "application/json")
   398  			bodyBytes, _ := io.ReadAll(req.Body)
   399  			bodyContent := string(bodyBytes)
   400  			responseContent := `{"data": `
   401  			responseContent += bodyContent
   402  			responseContent += `,"count": 1,"responseCode": 201,"links": {}}`
   403  			fmt.Println(responseContent)
   404  			rw.WriteHeader(201)
   405  			rw.Write([]byte(responseContent))
   406  			return
   407  		}
   408  	})
   409  
   410  	// Close the server when test finishes
   411  	defer server.Close()
   412  
   413  	t.Run("test success", func(t *testing.T) {
   414  		int64Value := int64(65)
   415  		int32Value := int32(876)
   416  		float32Value := float32(19.12)
   417  		now := models.NewIso8601MilliDateTime()
   418  		enabled := true
   419  		disabled := false
   420  		name := "Test new PV"
   421  		owner := "someUser"
   422  		masterGUID := "dsadaoudoiud"
   423  		project := models.Project{CreatedBy: &owner, CreationDate: now, Description: name, ID: int64Value, IssueTemplateID: &name, Name: &name}
   424  		projectVersionState := models.ProjectVersionState{AnalysisResultsExist: &disabled, AnalysisUploadEnabled: &disabled,
   425  			AttentionRequired: &disabled, AuditEnabled: &enabled, BatchBugSubmissionExists: &disabled, Committed: &enabled,
   426  			CriticalPriorityIssueCountDelta: &int32Value, DeltaPeriod: &int32Value, ExtraMessage: &name, HasCustomIssues: &disabled,
   427  			ID: &int64Value, IssueCountDelta: &int32Value, LastFprUploadDate: &now, MetricEvaluationDate: &now, PercentAuditedDelta: &float32Value,
   428  			PercentCriticalPriorityIssuesAuditedDelta: &float32Value}
   429  		version := models.ProjectVersion{AssignedIssuesCount: int64Value, Project: &project, Name: &name, Active: &enabled,
   430  			Committed: &enabled, AttachmentsOutOfDate: disabled, AutoPredict: disabled, BugTrackerEnabled: &disabled,
   431  			CustomTagValuesAutoApply: disabled, RefreshRequired: disabled, Owner: &owner, ServerVersion: &float32Value,
   432  			SnapshotOutOfDate: &disabled, StaleIssueTemplate: &disabled, MasterAttrGUID: &masterGUID,
   433  			LatestScanID: &int64Value, IssueTemplateName: &name, IssueTemplateModifiedTime: &int64Value,
   434  			IssueTemplateID: &name, Description: &name, CreatedBy: &owner, BugTrackerPluginID: &name, Mode: "NONE",
   435  			CurrentState: &projectVersionState, ID: int64Value, LoadProperties: "", CreationDate: &now,
   436  			MigrationVersion: float32Value, ObfuscatedID: "", PredictionPolicy: "", SecurityGroup: "",
   437  			SiteID: "", SourceBasePath: "", Status: "", TracesOutOfDate: false}
   438  		result, err := sys.CreateProjectVersion(&version)
   439  		assert.NoError(t, err, "CreateProjectVersion call not successful")
   440  		assert.Equal(t, name, *result.Name, "Expected to get PV with different value")
   441  		assert.Equal(t, int64(65), result.ID, "Expected to get PV with different id")
   442  	})
   443  }
   444  
   445  func TestProjectVersionCopyFromPartial(t *testing.T) {
   446  	// Start a local HTTP server
   447  	bodyContent := ""
   448  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   449  		if req.URL.Path == "/projectVersions/action/copyFromPartial" {
   450  			header := rw.Header()
   451  			header.Add("Content-type", "application/json")
   452  			bodyBytes, _ := io.ReadAll(req.Body)
   453  			bodyContent = string(bodyBytes)
   454  			rw.Write([]byte(
   455  				`{"data":[{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
   456  				"project":{"id":4711,"name":"python-test","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
   457  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
   458  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
   459  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
   460  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
   461  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
   462  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
   463  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
   464  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
   465  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
   466  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null}],
   467  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"},
   468  				"first":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"}}}`))
   469  			return
   470  		}
   471  	})
   472  	// Close the server when test finishes
   473  	defer server.Close()
   474  
   475  	t.Run("test success", func(t *testing.T) {
   476  		expected := `{"copyAnalysisProcessingRules":true,"copyBugTrackerConfiguration":true,"copyCustomTags":true,"previousProjectVersionId":10172,"projectVersionId":10173}
   477  `
   478  		err := sys.ProjectVersionCopyFromPartial(10172, 10173)
   479  		assert.NoError(t, err, "ProjectVersionCopyFromPartial call not successful")
   480  		assert.Equal(t, expected, bodyContent, "Different request content expected")
   481  	})
   482  }
   483  
   484  func TestProjectVersionCopyCurrentState(t *testing.T) {
   485  	// Start a local HTTP server
   486  	bodyContent := ""
   487  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   488  		if req.URL.Path == "/projectVersions/action/copyCurrentState" {
   489  			header := rw.Header()
   490  			header.Add("Content-type", "application/json")
   491  			bodyBytes, _ := io.ReadAll(req.Body)
   492  			bodyContent = string(bodyBytes)
   493  			rw.Write([]byte(
   494  				`{"data":[{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
   495  				"project":{"id":4711,"name":"python-test","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
   496  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
   497  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
   498  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
   499  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
   500  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
   501  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
   502  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
   503  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
   504  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
   505  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null}],
   506  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"},
   507  				"first":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"}}}`))
   508  			return
   509  		}
   510  	})
   511  	// Close the server when test finishes
   512  	defer server.Close()
   513  
   514  	t.Run("test success", func(t *testing.T) {
   515  		expected := `{"previousProjectVersionId":10172,"projectVersionId":10173}
   516  `
   517  		err := sys.ProjectVersionCopyCurrentState(10172, 10173)
   518  		assert.NoError(t, err, "ProjectVersionCopyCurrentState call not successful")
   519  		assert.Equal(t, expected, bodyContent, "Different request content expected")
   520  	})
   521  }
   522  
   523  func TestProjectVersionCopyPermissions(t *testing.T) {
   524  	// Start a local HTTP server
   525  	bodyContent := ""
   526  	referenceContent := `[{"displayName":"some user","email":"some.one@test.com","entityName":"some_user","firstName":"some","id":589,"lastName":"user","type":"User"}]
   527  `
   528  	response := `{"data": `
   529  	response += referenceContent
   530  	response += `,"count": 1,"responseCode": 200}`
   531  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   532  		if req.URL.Path == "/projectVersions/10172/authEntities" {
   533  			header := rw.Header()
   534  			header.Add("Content-type", "application/json")
   535  			rw.Write([]byte(response))
   536  			return
   537  		}
   538  		if req.URL.Path == "/projectVersions/10173/authEntities" {
   539  			header := rw.Header()
   540  			header.Add("Content-type", "application/json")
   541  			bodyBytes, _ := io.ReadAll(req.Body)
   542  			bodyContent = string(bodyBytes)
   543  			rw.Write([]byte(response))
   544  			return
   545  		}
   546  	})
   547  	// Close the server when test finishes
   548  	defer server.Close()
   549  
   550  	t.Run("test success", func(t *testing.T) {
   551  		err := sys.ProjectVersionCopyPermissions(10172, 10173)
   552  		assert.NoError(t, err, "ProjectVersionCopyPermissions call not successful")
   553  		assert.Equal(t, referenceContent, bodyContent, "Different request content expected")
   554  	})
   555  }
   556  
   557  func TestCommitProjectVersion(t *testing.T) {
   558  	// Start a local HTTP server
   559  	bodyContent := ""
   560  	referenceContent := `{"active":null,"bugTrackerEnabled":null,"bugTrackerPluginId":null,"committed":true,"createdBy":null,"creationDate":null,"description":null,"issueTemplateId":null,"issueTemplateModifiedTime":null,"issueTemplateName":null,"latestScanId":null,"masterAttrGuid":null,"name":null,"owner":null,"serverVersion":null,"snapshotOutOfDate":null,"staleIssueTemplate":null}
   561  `
   562  	response := `{"data": `
   563  	response += referenceContent
   564  	response += `,"count": 1,"responseCode": 200}`
   565  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   566  		if req.URL.Path == "/projectVersions/10172" {
   567  			header := rw.Header()
   568  			header.Add("Content-type", "application/json")
   569  			bodyBytes, _ := io.ReadAll(req.Body)
   570  			bodyContent = string(bodyBytes)
   571  			rw.Write([]byte(response))
   572  			return
   573  		}
   574  	})
   575  	// Close the server when test finishes
   576  	defer server.Close()
   577  
   578  	t.Run("test success", func(t *testing.T) {
   579  		result, err := sys.CommitProjectVersion(10172)
   580  		assert.NoError(t, err, "CommitProjectVersion call not successful")
   581  		assert.Equal(t, true, *result.Committed, "Different result content expected")
   582  		assert.Equal(t, referenceContent, bodyContent, "Different request content expected")
   583  	})
   584  }
   585  
   586  func TestInactivateProjectVersion(t *testing.T) {
   587  	// Start a local HTTP server
   588  	bodyContent := ""
   589  	referenceContent := `{"active":false,"bugTrackerEnabled":null,"bugTrackerPluginId":null,"committed":true,"createdBy":null,"creationDate":null,"description":null,"issueTemplateId":null,"issueTemplateModifiedTime":null,"issueTemplateName":null,"latestScanId":null,"masterAttrGuid":null,"name":null,"owner":null,"serverVersion":null,"snapshotOutOfDate":null,"staleIssueTemplate":null}
   590  `
   591  	response := `{"data": `
   592  	response += referenceContent
   593  	response += `,"count": 1,"responseCode": 200}`
   594  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   595  		if req.URL.Path == "/projectVersions/10172" {
   596  			header := rw.Header()
   597  			header.Add("Content-type", "application/json")
   598  			bodyBytes, _ := io.ReadAll(req.Body)
   599  			bodyContent = string(bodyBytes)
   600  			rw.Write([]byte(response))
   601  			return
   602  		}
   603  	})
   604  	// Close the server when test finishes
   605  	defer server.Close()
   606  
   607  	t.Run("test success", func(t *testing.T) {
   608  		result, err := sys.inactivateProjectVersion(10172)
   609  		assert.NoError(t, err, "InactivateProjectVersion call not successful")
   610  		assert.Equal(t, true, *result.Committed, "Different result content expected")
   611  		assert.Equal(t, false, *result.Active, "Different result content expected")
   612  		assert.Equal(t, referenceContent, bodyContent, "Different request content expected")
   613  	})
   614  }
   615  
   616  func TestGetArtifactsOfProjectVersion(t *testing.T) {
   617  	// Start a local HTTP server
   618  	response := `{"data": [{"artifactType": "FPR","fileName": "df54e2ade34c4f6aaddf35679dd87a21.tmp","approvalDate": null,"messageCount": 0,
   619  		"scanErrorsCount": 0,"uploadIP": "10.238.8.48","allowApprove": false,"allowPurge": false,"lastScanDate": "2019-11-26T22:37:52.000+0000",
   620  		"fileURL": null,"id": 56,"purged": false,"webInspectStatus": "NONE","inModifyingStatus": false,"originalFileName": "result.fpr",
   621  		"allowDelete": true,"scaStatus": "PROCESSED","indexed": true,"runtimeStatus": "NONE","userName": "some_user","versionNumber": null,
   622  		"otherStatus": "NOT_EXIST","uploadDate": "2019-11-26T22:38:11.813+0000","approvalComment": null,"approvalUsername": null,"fileSize": 984703,
   623  		"messages": "","auditUpdated": false,"status": "PROCESS_COMPLETE"}],"count": 1,"responseCode": 200}`
   624  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   625  		if req.URL.Path == "/projectVersions/10172/artifacts" {
   626  			header := rw.Header()
   627  			header.Add("Content-type", "application/json")
   628  			rw.Write([]byte(response))
   629  			return
   630  		}
   631  	})
   632  	// Close the server when test finishes
   633  	defer server.Close()
   634  
   635  	t.Run("test success", func(t *testing.T) {
   636  		result, err := sys.GetArtifactsOfProjectVersion(10172)
   637  		assert.NoError(t, err, "GetArtifactsOfProjectVersion call not successful")
   638  		assert.Equal(t, 1, len(result), "Different result content expected")
   639  		assert.Equal(t, int64(56), result[0].ID, "Different result content expected")
   640  	})
   641  }
   642  
   643  func TestGetFilterSetOfProjectVersionByTitle(t *testing.T) {
   644  	// Start a local HTTP server
   645  	response := `{"data":[{"defaultFilterSet":true,"folders":[
   646  	{"id":1,"guid":"4711","name":"Corporate Security Requirements","color":"000000"},
   647  	{"id":2,"guid":"4712","name":"Audit All","color":"ff0000"},
   648  	{"id":3,"guid":"4713","name":"Spot Checks of Each Category","color":"ff8000"},
   649  	{"id":4,"guid":"4714","name":"Optional","color":"808080"}],"description":"",
   650  	"guid":"666","title":"Special"}],"count":1,"responseCode":200}}`
   651  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   652  		if req.URL.Path == "/projectVersions/10172/filterSets" {
   653  			header := rw.Header()
   654  			header.Add("Content-type", "application/json")
   655  			rw.Write([]byte(response))
   656  			return
   657  		}
   658  	})
   659  	// Close the server when test finishes
   660  	defer server.Close()
   661  
   662  	t.Run("test success", func(t *testing.T) {
   663  		result, err := sys.GetFilterSetOfProjectVersionByTitle(10172, "Special")
   664  		assert.NoError(t, err, "GetFilterSetOfProjectVersionByTitle call not successful")
   665  		assert.Equal(t, "Special", result.Title, "Different result content expected")
   666  	})
   667  
   668  	t.Run("test default", func(t *testing.T) {
   669  		result, err := sys.GetFilterSetOfProjectVersionByTitle(10172, "")
   670  		assert.NoError(t, err, "GetFilterSetOfProjectVersionByTitle call not successful")
   671  		assert.Equal(t, "Special", result.Title, "Different result content expected")
   672  	})
   673  }
   674  
   675  func TestGetIssueFilterSelectorOfProjectVersionByName(t *testing.T) {
   676  	// Start a local HTTP server
   677  	response := `{"data":{"groupBySet": [{"entityType": "CUSTOMTAG","guid": "adsffghjkl","displayName": "Analysis",
   678  	"value": "87f2364f-dcd4-49e6-861d-f8d3f351686b","description": ""},{"entityType": "ISSUE","guid": "lkjhgfd",
   679  	"displayName": "Category","value": "11111111-1111-1111-1111-111111111165","description": ""}],"filterBySet":[{
   680  	"entityType": "CUSTOMTAG","filterSelectorType": "LIST","guid": "87f2364f-dcd4-49e6-861d-f8d3f351686b","displayName": "Analysis",
   681  	"value": "87f2364f-dcd4-49e6-861d-f8d3f351686b","description": "The analysis tag must be set.",
   682  	"selectorOptions": []},{"entityType": "FOLDER","filterSelectorType": "LIST","guid": "userAssignment","displayName": "Folder",
   683  	"value": "FOLDER","description": "","selectorOptions": []}]},"responseCode":200}}`
   684  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   685  		if req.URL.Path == "/projectVersions/10172/issueSelectorSet" {
   686  			header := rw.Header()
   687  			header.Add("Content-type", "application/json")
   688  			rw.Write([]byte(response))
   689  			return
   690  		}
   691  	})
   692  	// Close the server when test finishes
   693  	defer server.Close()
   694  
   695  	t.Run("test success one", func(t *testing.T) {
   696  		result, err := sys.GetIssueFilterSelectorOfProjectVersionByName(10172, []string{"Analysis"}, nil)
   697  		assert.NoError(t, err, "GetIssueFilterSelectorOfProjectVersionByName call not successful")
   698  		assert.NotNil(t, result, "Expected non nil value")
   699  		assert.Equal(t, 1, len(result.FilterBySet), "Different result expected")
   700  		assert.Equal(t, 1, len(result.GroupBySet), "Different result expected")
   701  	})
   702  
   703  	t.Run("test success several", func(t *testing.T) {
   704  		result, err := sys.GetIssueFilterSelectorOfProjectVersionByName(10172, []string{"Analysis", "Folder"}, nil)
   705  		assert.NoError(t, err, "GetIssueFilterSelectorOfProjectVersionByName call not successful")
   706  		assert.NotNil(t, result, "Expected non nil value")
   707  		assert.Equal(t, 2, len(result.FilterBySet), "Different result expected")
   708  		assert.Equal(t, 1, len(result.GroupBySet), "Different result expected")
   709  	})
   710  
   711  	t.Run("test empty", func(t *testing.T) {
   712  		result, err := sys.GetIssueFilterSelectorOfProjectVersionByName(10172, []string{"Some", "Other"}, nil)
   713  		assert.NoError(t, err, "GetIssueFilterSelectorOfProjectVersionByName call not successful")
   714  		assert.NotNil(t, result, "Expected non nil value")
   715  		assert.Equal(t, 0, len(result.FilterBySet), "Different result expected")
   716  		assert.Equal(t, 0, len(result.GroupBySet), "Different result expected")
   717  	})
   718  }
   719  
   720  func TestReduceIssueFilterSelectorSet(t *testing.T) {
   721  	sys, _ := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {})
   722  	name1 := "Special"
   723  	name2 := "Other"
   724  	guid := "FOLDER"
   725  	options := []*models.SelectorOption{{GUID: "1234567", DisplayName: "Test"}, {GUID: "1234568", DisplayName: "Test2"}}
   726  	filterSet := models.IssueFilterSelectorSet{FilterBySet: []*models.IssueFilterSelector{}, GroupBySet: []*models.IssueSelector{}}
   727  	filterSet.FilterBySet = append(filterSet.FilterBySet, &models.IssueFilterSelector{DisplayName: name1, SelectorOptions: options})
   728  	filterSet.FilterBySet = append(filterSet.FilterBySet, &models.IssueFilterSelector{DisplayName: name2})
   729  	filterSet.GroupBySet = append(filterSet.GroupBySet, &models.IssueSelector{DisplayName: &name2, GUID: &guid})
   730  	reducedFilterSet := sys.ReduceIssueFilterSelectorSet(&filterSet, []string{"Special"}, []string{"Test"})
   731  	assert.Equal(t, 1, len(reducedFilterSet.FilterBySet), "Different result expected")
   732  	assert.Equal(t, 1, len(reducedFilterSet.FilterBySet[0].SelectorOptions), "Different result expected")
   733  	assert.Equal(t, "Test", reducedFilterSet.FilterBySet[0].SelectorOptions[0].DisplayName, "Different result expected")
   734  	assert.Equal(t, 0, len(reducedFilterSet.GroupBySet), "Different result expected")
   735  }
   736  
   737  func TestGetProjectIssuesByIDAndFilterSetGroupedBySelector(t *testing.T) {
   738  	// Start a local HTTP server
   739  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   740  		if req.URL.Path == "/projectVersions/10172/filterSets" {
   741  			header := rw.Header()
   742  			header.Add("Content-type", "application/json")
   743  			rw.Write([]byte(`{"data":[{"defaultFilterSet":true,"folders":[
   744  				{"id":1,"guid":"4711","name":"Corporate Security Requirements","color":"000000"},
   745  				{"id":2,"guid":"4712","name":"Audit All","color":"ff0000"},
   746  				{"id":3,"guid":"4713","name":"Spot Checks of Each Category","color":"ff8000"},
   747  				{"id":4,"guid":"4714","name":"Optional","color":"808080"}],"description":"",
   748  				"guid":"666","title":"Special"}],"count":1,"responseCode":200}}`))
   749  			return
   750  		}
   751  		if req.URL.Path == "/projectVersions/10172/issueGroups" {
   752  			assert.Equal(t, "filterset=666&groupingtype=FOLDER&showsuppressed=true", req.URL.RawQuery)
   753  			return
   754  		}
   755  		rw.WriteHeader(400)
   756  	})
   757  	// Close the server when test finishes
   758  	defer server.Close()
   759  
   760  	t.Run("test success", func(t *testing.T) {
   761  		name := "Special"
   762  		guid := "FOLDER"
   763  		filterSet := models.IssueFilterSelectorSet{FilterBySet: []*models.IssueFilterSelector{}, GroupBySet: []*models.IssueSelector{}}
   764  		filterSet.FilterBySet = append(filterSet.FilterBySet, &models.IssueFilterSelector{DisplayName: name})
   765  		filterSet.GroupBySet = append(filterSet.GroupBySet, &models.IssueSelector{DisplayName: &name, GUID: &guid})
   766  		_, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(10172, "", "666", &filterSet)
   767  		assert.NoError(t, err, "GetProjectIssuesByIDAndFilterSetGroupedByFolder call not successful")
   768  	})
   769  }
   770  
   771  func TestGetProjectIssuesByIDAndFilterSetGroupedByCategory(t *testing.T) {
   772  	// Start a local HTTP server
   773  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   774  		if req.URL.Path == "/projectVersions/10172/filterSets" {
   775  			header := rw.Header()
   776  			header.Add("Content-type", "application/json")
   777  			rw.Write([]byte(`{"data":[{"defaultFilterSet":true,"folders":[
   778  				{"id":1,"guid":"4711","name":"Corporate Security Requirements","color":"000000"},
   779  				{"id":2,"guid":"4712","name":"Audit All","color":"ff0000"},
   780  				{"id":3,"guid":"4713","name":"Spot Checks of Each Category","color":"ff8000"},
   781  				{"id":4,"guid":"4714","name":"Optional","color":"808080"}],"description":"",
   782  				"guid":"666","title":"Special"}],"count":1,"responseCode":200}}`))
   783  			return
   784  		}
   785  		if req.URL.Path == "/projectVersions/10172/issueGroups" {
   786  			assert.Equal(t, "filter=4713&filterset=666&groupingtype=11111111-1111-1111-1111-111111111165&showsuppressed=true", req.URL.RawQuery)
   787  			return
   788  		}
   789  		rw.WriteHeader(400)
   790  	})
   791  	// Close the server when test finishes
   792  	defer server.Close()
   793  
   794  	t.Run("test success", func(t *testing.T) {
   795  		name := "Special"
   796  		guid := "11111111-1111-1111-1111-111111111165"
   797  		filterSet := models.IssueFilterSelectorSet{FilterBySet: []*models.IssueFilterSelector{}, GroupBySet: []*models.IssueSelector{}}
   798  		filterSet.FilterBySet = append(filterSet.FilterBySet, &models.IssueFilterSelector{DisplayName: name})
   799  		filterSet.GroupBySet = append(filterSet.GroupBySet, &models.IssueSelector{DisplayName: &name, GUID: &guid})
   800  		_, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(10172, "4713", "666", &filterSet)
   801  		assert.NoError(t, err, "GetProjectIssuesByIDAndFilterSetGroupedByCategory call not successful")
   802  	})
   803  }
   804  
   805  func TestGetProjectIssuesByIDAndFilterSetGroupedByAnalysis(t *testing.T) {
   806  	// Start a local HTTP server
   807  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   808  		if req.URL.Path == "/projectVersions/10172/filterSets" {
   809  			header := rw.Header()
   810  			header.Add("Content-type", "application/json")
   811  			rw.Write([]byte(`{"data":[{"defaultFilterSet":true,"folders":[
   812  				{"id":1,"guid":"4711","name":"Corporate Security Requirements","color":"000000"},
   813  				{"id":2,"guid":"4712","name":"Audit All","color":"ff0000"},
   814  				{"id":3,"guid":"4713","name":"Spot Checks of Each Category","color":"ff8000"},
   815  				{"id":4,"guid":"4714","name":"Optional","color":"808080"}],"description":"",
   816  				"guid":"666","title":"Special"}],"count":1,"responseCode":200}}`))
   817  			return
   818  		}
   819  		if req.URL.Path == "/projectVersions/10172/issueGroups" {
   820  			assert.Equal(t, "filterset=666&groupingtype=87f2364f-dcd4-49e6-861d-f8d3f351686b&showsuppressed=true", req.URL.RawQuery)
   821  			return
   822  		}
   823  		rw.WriteHeader(400)
   824  	})
   825  	// Close the server when test finishes
   826  	defer server.Close()
   827  
   828  	t.Run("test success", func(t *testing.T) {
   829  		name := "Special"
   830  		guid := "87f2364f-dcd4-49e6-861d-f8d3f351686b"
   831  		filterSet := models.IssueFilterSelectorSet{FilterBySet: []*models.IssueFilterSelector{}, GroupBySet: []*models.IssueSelector{}}
   832  		filterSet.FilterBySet = append(filterSet.FilterBySet, &models.IssueFilterSelector{DisplayName: name})
   833  		filterSet.GroupBySet = append(filterSet.GroupBySet, &models.IssueSelector{DisplayName: &name, GUID: &guid})
   834  		_, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(10172, "", "666", &filterSet)
   835  		assert.NoError(t, err, "GetProjectIssuesByIDAndFilterSetGroupedByAnalysis call not successful")
   836  	})
   837  }
   838  
   839  func TestGetIssueStatisticsOfProjectVersion(t *testing.T) {
   840  	// Start a local HTTP server
   841  	response := `{"data": [{"filterSetId": 3887,"hiddenCount": 0,"suppressedDisplayableCount": 0,"suppressedCount": 11,"hiddenDisplayableCount": 0,"projectVersionId": 10172,
   842  				"removedDisplayableCount": 0,"removedCount": 747}],"count": 1,"responseCode": 200}`
   843  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   844  		if req.URL.Path == "/projectVersions/10172/issueStatistics" {
   845  			header := rw.Header()
   846  			header.Add("Content-type", "application/json")
   847  			rw.Write([]byte(response))
   848  			return
   849  		}
   850  	})
   851  	// Close the server when test finishes
   852  	defer server.Close()
   853  
   854  	t.Run("test success", func(t *testing.T) {
   855  		result, err := sys.GetIssueStatisticsOfProjectVersion(10172)
   856  		assert.NoError(t, err, "GetArtifactsOfProjectVersion call not successful")
   857  		assert.Equal(t, 1, len(result), "Different result content expected")
   858  		assert.Equal(t, int64(10172), *result[0].ProjectVersionID, "Different result content expected")
   859  		assert.Equal(t, int32(11), *result[0].SuppressedCount, "Different result content expected")
   860  	})
   861  }
   862  
   863  func TestGenerateQGateReport(t *testing.T) {
   864  	// Start a local HTTP server
   865  	data := ""
   866  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   867  		if req.URL.Path == "/reports" {
   868  			header := rw.Header()
   869  			header.Add("Content-type", "application/json")
   870  			bodyBytes, _ := io.ReadAll(req.Body)
   871  			data = string(bodyBytes)
   872  			response := `{"data": `
   873  			response += data
   874  			response += `,"responseCode": 201}`
   875  			rw.WriteHeader(201)
   876  			rw.Write([]byte(response))
   877  			return
   878  		}
   879  	})
   880  	// Close the server when test finishes
   881  	defer server.Close()
   882  
   883  	t.Run("test success", func(t *testing.T) {
   884  		result, err := sys.GenerateQGateReport(2837, 17540, 18, "Fortify", "develop", "PDF")
   885  		assert.NoError(t, err, "GetArtifactsOfProjectVersion call not successful")
   886  		assert.Equal(t, int64(2837), result.Projects[0].ID, "Different result content expected")
   887  		assert.Equal(t, int64(17540), result.Projects[0].Versions[0].ID, "Different result content expected")
   888  		assert.Equal(t, int64(18), *result.ReportDefinitionID, "Different result content expected")
   889  	})
   890  }
   891  
   892  func TestGetReportDetails(t *testing.T) {
   893  	// Start a local HTTP server
   894  	response := `{"data": {"id":999,"name":"FortifyReport","note":"","type":"PORTFOLIO","reportDefinitionId":18,"format":"PDF",
   895  	"projects":[{"id":2837,"name":"Fortify","versions":[{"id":17540,"name":"develop"}]}],"projectVersionDisplayName":"develop",
   896  	"inputReportParameters":[{"name":"Q-gate-report","identifier":"projectVersionId","paramValue":17540,"type":"SINGLE_PROJECT"}]},"count": 1,"responseCode": 200}`
   897  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   898  		if req.URL.Path == "/reports/999" {
   899  			header := rw.Header()
   900  			header.Add("Content-type", "application/json")
   901  			rw.Write([]byte(response))
   902  			return
   903  		}
   904  	})
   905  	// Close the server when test finishes
   906  	defer server.Close()
   907  
   908  	t.Run("test success", func(t *testing.T) {
   909  		result, err := sys.GetReportDetails(999)
   910  		assert.NoError(t, err, "GetReportDetails call not successful")
   911  		assert.Equal(t, int64(999), result.ID, "Different result content expected")
   912  	})
   913  }
   914  
   915  func TestGetFileToken(t *testing.T) {
   916  	// Start a local HTTP server
   917  	bodyContent := ""
   918  	reference := `{"fileTokenType":"TOKEN_TYPE"}
   919  `
   920  	response := `{"data": {"fileTokenType": "TOKEN_TYPE","token": "ZjE1OTdjZjEtMjAzNS00NTFmLThiOWItNzBkYzI0MWEzZGNj"},"responseCode": 201}`
   921  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   922  		if req.URL.Path == "/fileTokens" {
   923  			header := rw.Header()
   924  			header.Add("Content-type", "application/json")
   925  			bodyBytes, _ := io.ReadAll(req.Body)
   926  			bodyContent = string(bodyBytes)
   927  			rw.WriteHeader(201)
   928  			rw.Write([]byte(response))
   929  			return
   930  		}
   931  	})
   932  	// Close the server when test finishes
   933  	defer server.Close()
   934  
   935  	t.Run("test success", func(t *testing.T) {
   936  		result, err := sys.getFileToken("TOKEN_TYPE")
   937  		assert.NoError(t, err)
   938  		assert.Equal(t, "ZjE1OTdjZjEtMjAzNS00NTFmLThiOWItNzBkYzI0MWEzZGNj", result.Token)
   939  		assert.Equal(t, reference, bodyContent)
   940  	})
   941  }
   942  
   943  func TestInvalidateFileToken(t *testing.T) {
   944  	// Start a local HTTP server
   945  	response := `{"responseCode": 200}`
   946  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   947  		if req.URL.Path == "/fileTokens" && req.Method == "DELETE" {
   948  			header := rw.Header()
   949  			header.Add("Content-type", "application/json")
   950  			rw.WriteHeader(200)
   951  			rw.Write([]byte(response))
   952  			return
   953  		}
   954  	})
   955  	// Close the server when test finishes
   956  	defer server.Close()
   957  
   958  	t.Run("test success", func(t *testing.T) {
   959  		err := sys.invalidateFileTokens()
   960  		assert.NoError(t, err, "invalidateFileTokens call not successful")
   961  	})
   962  }
   963  
   964  func TestUploadResultFile(t *testing.T) {
   965  	// Start a local HTTP server
   966  	bodyContent := ""
   967  	getTokenCalled := false
   968  	invalidateTokenCalled := false
   969  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
   970  		if req.URL.Path == "/fileTokens" && req.Method == "DELETE" {
   971  			header := rw.Header()
   972  			header.Add("Content-type", "application/json")
   973  			rw.WriteHeader(200)
   974  			rw.Write([]byte(`{"responseCode": 200}`))
   975  			invalidateTokenCalled = true
   976  			return
   977  		}
   978  		if req.URL.Path == "/fileTokens" && req.Method == "POST" {
   979  			header := rw.Header()
   980  			header.Add("Content-type", "application/json")
   981  			rw.WriteHeader(201)
   982  			rw.Write([]byte(`{"data": {"token": "89ee873"}, "responseCode": 201}`))
   983  			getTokenCalled = true
   984  			return
   985  		}
   986  		if req.URL.Path == "/upload/resultFileUpload.html" && req.URL.RawQuery == "mat=89ee873" {
   987  			header := rw.Header()
   988  			header.Add("Content-type", "application/json")
   989  			bodyBytes, _ := io.ReadAll(req.Body)
   990  			bodyContent = string(bodyBytes)
   991  			rw.WriteHeader(200)
   992  			rw.Write([]byte("OK"))
   993  			return
   994  		}
   995  	})
   996  	// Close the server when test finishes
   997  	defer server.Close()
   998  
   999  	testFile, err := os.CreateTemp("", "result.fpr")
  1000  	if err != nil {
  1001  		t.FailNow()
  1002  	}
  1003  	defer os.RemoveAll(testFile.Name()) // clean up
  1004  
  1005  	t.Run("test success", func(t *testing.T) {
  1006  		err := sys.UploadResultFile("/upload/resultFileUpload.html", testFile.Name(), 10770)
  1007  		assert.NoError(t, err, "UploadFile call not successful")
  1008  		assert.Contains(t, bodyContent, `Content-Disposition: form-data; name="file"; filename=`, "Expected different content in request body")
  1009  		assert.Contains(t, bodyContent, `Content-Disposition: form-data; name="entityId"`, "Expected different content in request body")
  1010  		assert.Contains(t, bodyContent, `10770`, "Expected different content in request body")
  1011  		assert.Equal(t, true, getTokenCalled, "Expected GetUploadToken to be called")
  1012  		assert.Equal(t, true, invalidateTokenCalled, "Expected InvalidateFileTokens to be called")
  1013  	})
  1014  }
  1015  
  1016  func TestDownloadResultFile(t *testing.T) {
  1017  	// Start a local HTTP server
  1018  	bodyContent := ""
  1019  	getTokenCalled := false
  1020  	invalidateTokenCalled := false
  1021  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
  1022  		if req.URL.Path == "/fileTokens" && req.Method == "DELETE" {
  1023  			header := rw.Header()
  1024  			header.Add("Content-type", "application/json")
  1025  			rw.WriteHeader(200)
  1026  			rw.Write([]byte(`{"responseCode": 200}`))
  1027  			invalidateTokenCalled = true
  1028  			return
  1029  		}
  1030  		if req.URL.Path == "/fileTokens" && req.Method == "POST" {
  1031  			header := rw.Header()
  1032  			header.Add("Content-type", "application/json")
  1033  			rw.WriteHeader(201)
  1034  			rw.Write([]byte(`{"data": {"token": "89ee873"}, "responseCode": 201}`))
  1035  			getTokenCalled = true
  1036  			return
  1037  		}
  1038  		if req.URL.Path == "/download/currentStateFprDownload.html" {
  1039  			header := rw.Header()
  1040  			header.Add("Content-type", "application/json")
  1041  			bodyContent = req.URL.RawQuery
  1042  			rw.WriteHeader(200)
  1043  			rw.Write([]byte("OK"))
  1044  			return
  1045  		}
  1046  	})
  1047  	// Close the server when test finishes
  1048  	defer server.Close()
  1049  
  1050  	t.Run("test success", func(t *testing.T) {
  1051  		data, err := sys.DownloadResultFile("/download/currentStateFprDownload.html", 10775)
  1052  		assert.NoError(t, err, "DownloadResultFile call not successful")
  1053  		assert.Equal(t, "id=10775&mat=89ee873", bodyContent, "Expected different request body")
  1054  		assert.Equal(t, []byte("OK"), data, "Expected different result")
  1055  		assert.Equal(t, true, getTokenCalled, "Expected GetUploadToken to be called")
  1056  		assert.Equal(t, true, invalidateTokenCalled, "Expected InvalidateFileTokens to be called")
  1057  	})
  1058  }
  1059  
  1060  func TestDownloadReportFile(t *testing.T) {
  1061  	// Start a local HTTP server
  1062  	getTokenCalled := false
  1063  	invalidateTokenCalled := false
  1064  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
  1065  		if req.URL.Path == "/fileTokens" && req.Method == "DELETE" {
  1066  			header := rw.Header()
  1067  			header.Add("Content-type", "application/json")
  1068  			rw.WriteHeader(200)
  1069  			rw.Write([]byte(`{"responseCode": 200}`))
  1070  			invalidateTokenCalled = true
  1071  			return
  1072  		}
  1073  		if req.URL.Path == "/fileTokens" && req.Method == "POST" {
  1074  			header := rw.Header()
  1075  			header.Add("Content-type", "application/json")
  1076  			rw.WriteHeader(201)
  1077  			rw.Write([]byte(`{"data": {"token": "89ee873"}, "responseCode": 201}`))
  1078  			getTokenCalled = true
  1079  			return
  1080  		}
  1081  		if req.URL.Path == "/transfer/reportDownload.html" && req.URL.RawQuery == "id=10775&mat=89ee873" {
  1082  			header := rw.Header()
  1083  			header.Add("Content-type", "application/json")
  1084  			rw.WriteHeader(200)
  1085  			rw.Write([]byte("OK"))
  1086  			return
  1087  		}
  1088  	})
  1089  	// Close the server when test finishes
  1090  	defer server.Close()
  1091  
  1092  	t.Run("test success", func(t *testing.T) {
  1093  		data, err := sys.DownloadReportFile("/transfer/reportDownload.html", 10775)
  1094  		assert.NoError(t, err, "DownloadReportFile call not successful")
  1095  		assert.Equal(t, []byte("OK"), data, "Expected different result")
  1096  		assert.Equal(t, true, getTokenCalled, "Expected GetUploadToken to be called")
  1097  		assert.Equal(t, true, invalidateTokenCalled, "Expected InvalidateFileTokens to be called")
  1098  	})
  1099  }
  1100  
  1101  func TestLookupOrCreateProjectVersionDetailsForPullRequest(t *testing.T) {
  1102  	// Start a local HTTP server
  1103  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
  1104  		if req.URL.Path == "/projects/4711/versions" {
  1105  			header := rw.Header()
  1106  			header.Add("Content-type", "application/json")
  1107  			rw.WriteHeader(200)
  1108  			rw.Write([]byte(`{"data": [], "count": 0, "responseCode": 200}`))
  1109  			return
  1110  		}
  1111  		if req.URL.Path == "/projectVersions" && req.Method == "POST" {
  1112  			header := rw.Header()
  1113  			header.Add("Content-type", "application/json")
  1114  			bodyBytes, _ := io.ReadAll(req.Body)
  1115  			bodyContent := string(bodyBytes)
  1116  			responseContent := `{"data": `
  1117  			responseContent += bodyContent
  1118  			responseContent += `,"count": 1,"responseCode": 201,"links": {}}`
  1119  			fmt.Println(responseContent)
  1120  			rw.WriteHeader(201)
  1121  			rw.Write([]byte(responseContent))
  1122  			return
  1123  		}
  1124  		if req.URL.Path == "/projectVersions/4711/attributes" {
  1125  			header := rw.Header()
  1126  			header.Add("Content-type", "application/json")
  1127  			rw.Write([]byte(
  1128  				`{"data": [{"_href": "https://fortify/ssc/api/v1/projectVersions/4711/attributes/4712","attributeDefinitionId": 31,
  1129  				"values": null,"guid": "gdgfdgfdgfdgfd","id": 4712,"value": "abcd"}],"count": 8,"responseCode": 200}`))
  1130  			return
  1131  		}
  1132  		if req.URL.Path == "/projectVersions/4712/attributes" {
  1133  			header := rw.Header()
  1134  			header.Add("Content-type", "application/json")
  1135  			bodyBytes, _ := io.ReadAll(req.Body)
  1136  			bodyString := string(bodyBytes)
  1137  			response := `{"data": `
  1138  			response += bodyString
  1139  			response += `,"count": 1,"responseCode": 200}`
  1140  			rw.WriteHeader(200)
  1141  			rw.Write([]byte(response))
  1142  			return
  1143  		}
  1144  		if req.URL.Path == "/projectVersions/action/copyFromPartial" {
  1145  			header := rw.Header()
  1146  			header.Add("Content-type", "application/json")
  1147  			rw.Write([]byte(
  1148  				`{"data":[{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
  1149  				"project":{"id":4711,"name":"python-test","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
  1150  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
  1151  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
  1152  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
  1153  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
  1154  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
  1155  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
  1156  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
  1157  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
  1158  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
  1159  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null}],
  1160  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"},
  1161  				"first":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"}}}`))
  1162  			return
  1163  		}
  1164  		if req.URL.Path == "/projectVersions/10172" {
  1165  			header := rw.Header()
  1166  			header.Add("Content-type", "application/json")
  1167  			rw.Write([]byte(`{"data": {"active":null,"bugTrackerEnabled":null,"bugTrackerPluginId":null,"committed":true,"createdBy":null,"creationDate":null,"description":null,"issueTemplateId":null,"issueTemplateModifiedTime":null,"issueTemplateName":null,"latestScanId":null,"masterAttrGuid":null,"name":null,"owner":null,"serverVersion":null,"snapshotOutOfDate":null,"staleIssueTemplate":null}, "responseCode": 200}`))
  1168  			return
  1169  		}
  1170  		if req.URL.Path == "/projectVersions/action/copyCurrentState" {
  1171  			header := rw.Header()
  1172  			header.Add("Content-type", "application/json")
  1173  			rw.Write([]byte(
  1174  				`{"data":[{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
  1175  				"project":{"id":4711,"name":"python-test","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
  1176  				"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
  1177  				"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
  1178  				"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
  1179  				"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
  1180  				"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
  1181  				"migrationVersion":null,"createdBy":"admin","name":"0","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
  1182  				"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
  1183  				"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
  1184  				"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
  1185  				"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null}],
  1186  				"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"},
  1187  				"first":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"}}}`))
  1188  			return
  1189  		}
  1190  		if req.URL.Path == "/projectVersions/10172/authEntities" {
  1191  			header := rw.Header()
  1192  			header.Add("Content-type", "application/json")
  1193  			rw.Write([]byte(`{"data": [{"displayName":"some user","email":"some.one@test.com","entityName":"some_user","firstName":"some","id":589,"lastName":"user","type":"User"}],"count": 1,"responseCode": 200}`))
  1194  			return
  1195  		}
  1196  		if req.URL.Path == "/projectVersions/10173/authEntities" {
  1197  			header := rw.Header()
  1198  			header.Add("Content-type", "application/json")
  1199  			rw.Write([]byte(`{"data": [{"displayName":"some user","email":"some.one@test.com","entityName":"some_user","firstName":"some","id":589,"lastName":"user","type":"User"}],"count": 1,"responseCode": 200}`))
  1200  			return
  1201  		}
  1202  	})
  1203  	// Close the server when test finishes
  1204  	defer server.Close()
  1205  
  1206  	t.Run("test success", func(t *testing.T) {
  1207  		int64Value := int64(65)
  1208  		int32Value := int32(876)
  1209  		float32Value := float32(19.12)
  1210  		now := models.NewIso8601MilliDateTime()
  1211  		enabled := true
  1212  		disabled := false
  1213  		name := "Test new PV"
  1214  		owner := "someUser"
  1215  		masterGUID := "dsadaoudoiud"
  1216  		project := models.Project{CreatedBy: &owner, CreationDate: now, Description: name, ID: int64Value, IssueTemplateID: &name, Name: &name}
  1217  		projectVersionState := models.ProjectVersionState{AnalysisResultsExist: &disabled, AnalysisUploadEnabled: &disabled,
  1218  			AttentionRequired: &disabled, AuditEnabled: &enabled, BatchBugSubmissionExists: &disabled, Committed: &enabled,
  1219  			CriticalPriorityIssueCountDelta: &int32Value, DeltaPeriod: &int32Value, ExtraMessage: &name, HasCustomIssues: &disabled,
  1220  			ID: &int64Value, IssueCountDelta: &int32Value, LastFprUploadDate: &now, MetricEvaluationDate: &now, PercentAuditedDelta: &float32Value,
  1221  			PercentCriticalPriorityIssuesAuditedDelta: &float32Value}
  1222  		masterProjectVersion := models.ProjectVersion{AssignedIssuesCount: int64Value, Project: &project, Name: &name, Active: &enabled,
  1223  			Committed: &enabled, AttachmentsOutOfDate: disabled, AutoPredict: disabled, BugTrackerEnabled: &disabled,
  1224  			CustomTagValuesAutoApply: disabled, RefreshRequired: disabled, Owner: &owner, ServerVersion: &float32Value,
  1225  			SnapshotOutOfDate: &disabled, StaleIssueTemplate: &disabled, MasterAttrGUID: &masterGUID,
  1226  			LatestScanID: &int64Value, IssueTemplateName: &name, IssueTemplateModifiedTime: &int64Value,
  1227  			IssueTemplateID: &name, Description: &name, CreatedBy: &owner, BugTrackerPluginID: &name, Mode: "NONE",
  1228  			CurrentState: &projectVersionState, ID: int64Value, LoadProperties: "", CreationDate: &now,
  1229  			MigrationVersion: float32Value, ObfuscatedID: "", PredictionPolicy: "", SecurityGroup: "",
  1230  			SiteID: "", SourceBasePath: "", Status: "", TracesOutOfDate: false}
  1231  		prProjectVersion, err := sys.LookupOrCreateProjectVersionDetailsForPullRequest(4711, &masterProjectVersion, "PR-815")
  1232  		assert.NoError(t, err, "LookupOrCreateProjectVersionDetailsForPullRequest call not successful")
  1233  		assert.Equal(t, "PR-815", *prProjectVersion.Name, "Expected different result")
  1234  		assert.Equal(t, masterProjectVersion.Description, prProjectVersion.Description, "Expected different result")
  1235  		assert.Equal(t, masterProjectVersion.Active, prProjectVersion.Active, "Expected different result")
  1236  		assert.Equal(t, masterProjectVersion.Committed, prProjectVersion.Committed, "Expected different result")
  1237  		assert.Equal(t, masterProjectVersion.Project.Name, prProjectVersion.Project.Name, "Expected different result")
  1238  		assert.Equal(t, masterProjectVersion.Project.Description, prProjectVersion.Project.Description, "Expected different result")
  1239  		assert.Equal(t, masterProjectVersion.Project.ID, prProjectVersion.Project.ID, "Expected different result")
  1240  		assert.Equal(t, masterProjectVersion.IssueTemplateID, prProjectVersion.IssueTemplateID, "Expected different result")
  1241  	})
  1242  }
  1243  
  1244  func TestMergeProjectVersionStateOfPRIntoMaster(t *testing.T) {
  1245  	// Start a local HTTP server
  1246  	getPRProjectVersionCalled := false
  1247  	invalidateTokenCalled := false
  1248  	getTokenCalled := false
  1249  	downloadCalled := false
  1250  	uploadCalled := false
  1251  	inactivateCalled := false
  1252  	sys, server := spinUpServer(func(rw http.ResponseWriter, req *http.Request) {
  1253  		if req.URL.Path == "/projects/4711/versions" {
  1254  			header := rw.Header()
  1255  			header.Add("Content-type", "application/json")
  1256  			rw.Write([]byte(`{"data":[{"latestScanId":null,"serverVersion":17.2,"tracesOutOfDate":false,"attachmentsOutOfDate":false,"description":"",
  1257  			"project":{"id":4711,"name":"product.some.com","description":"","creationDate":"2018-12-03T06:29:38.197+0000","createdBy":"someUser",
  1258  			"issueTemplateId":"dasdasdasdsadasdasdasdasdas"},"sourceBasePath":null,"mode":"BASIC","masterAttrGuid":"sddasdasda","obfuscatedId":null,
  1259  			"id":10172,"customTagValuesAutoApply":null,"issueTemplateId":"dasdasdasdsadasdasdasdasdas","loadProperties":null,"predictionPolicy":null,
  1260  			"bugTrackerPluginId":null,"owner":"admin","_href":"https://fortify/ssc/api/v1/projectVersions/10172",
  1261  			"committed":true,"bugTrackerEnabled":false,"active":true,"snapshotOutOfDate":false,"issueTemplateModifiedTime":1578411924701,
  1262  			"securityGroup":null,"creationDate":"2018-02-09T16:59:41.297+0000","refreshRequired":false,"issueTemplateName":"someTemplate",
  1263  			"migrationVersion":null,"createdBy":"admin","name":"PR-815","siteId":null,"staleIssueTemplate":false,"autoPredict":null,
  1264  			"currentState":{"id":10172,"committed":true,"attentionRequired":false,"analysisResultsExist":true,"auditEnabled":true,
  1265  			"lastFprUploadDate":"2018-02-09T16:59:53.497+0000","extraMessage":null,"analysisUploadEnabled":true,"batchBugSubmissionExists":false,
  1266  			"hasCustomIssues":false,"metricEvaluationDate":"2018-03-10T00:02:45.553+0000","deltaPeriod":7,"issueCountDelta":0,"percentAuditedDelta":0.0,
  1267  			"criticalPriorityIssueCountDelta":0,"percentCriticalPriorityIssuesAuditedDelta":0.0},"assignedIssuesCount":0,"status":null}],
  1268  			"count":1,"responseCode":200,"links":{"last":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"},
  1269  			"first":{"href":"https://fortify/ssc/api/v1/projects/4711/versions?start=0"}}}`))
  1270  			getPRProjectVersionCalled = true
  1271  			return
  1272  		}
  1273  		if req.URL.Path == "/fileTokens" && req.Method == "DELETE" {
  1274  			header := rw.Header()
  1275  			header.Add("Content-type", "application/json")
  1276  			rw.WriteHeader(200)
  1277  			rw.Write([]byte(`{"responseCode": 200}`))
  1278  			invalidateTokenCalled = true
  1279  			return
  1280  		}
  1281  		if req.URL.Path == "/fileTokens" && req.Method == "POST" {
  1282  			header := rw.Header()
  1283  			header.Add("Content-type", "application/json")
  1284  			rw.WriteHeader(201)
  1285  			rw.Write([]byte(`{"data": {"token": "89ee873"}, "responseCode": 201}`))
  1286  			getTokenCalled = true
  1287  			return
  1288  		}
  1289  		if req.URL.Path == "/download/currentStateFprDownload.html" {
  1290  			header := rw.Header()
  1291  			header.Add("Content-type", "application/json")
  1292  			rw.WriteHeader(200)
  1293  			rw.Write([]byte("OK"))
  1294  			downloadCalled = true
  1295  			return
  1296  		}
  1297  		if req.URL.Path == "/upload/resultFileUpload.html" {
  1298  			header := rw.Header()
  1299  			header.Add("Content-type", "application/json")
  1300  			rw.WriteHeader(200)
  1301  			rw.Write([]byte("OK"))
  1302  			uploadCalled = true
  1303  			return
  1304  		}
  1305  		if req.URL.Path == "/projectVersions/10172" {
  1306  			header := rw.Header()
  1307  			header.Add("Content-type", "application/json")
  1308  			rw.Write([]byte(`{"data": {"active":false,"bugTrackerEnabled":null,"bugTrackerPluginId":null,"committed":true,"createdBy":null,"creationDate":null,"description":null,"issueTemplateId":null,"issueTemplateModifiedTime":null,"issueTemplateName":null,"latestScanId":null,"masterAttrGuid":null,"name":null,"owner":null,"serverVersion":null,"snapshotOutOfDate":null,"staleIssueTemplate":null}, "responseCode": 200}`))
  1309  			inactivateCalled = true
  1310  			return
  1311  		}
  1312  	})
  1313  	// Close the server when test finishes
  1314  	defer server.Close()
  1315  
  1316  	t.Run("test success", func(t *testing.T) {
  1317  		err := sys.MergeProjectVersionStateOfPRIntoMaster("/download/currentStateFprDownload.html", "/upload/resultFileUpload.html", 4711, 10171, "PR-815")
  1318  		assert.NoError(t, err, "MergeProjectVersionStateOfPRIntoMaster call not successful")
  1319  		assert.Equal(t, true, getPRProjectVersionCalled, "Expected different value")
  1320  		assert.Equal(t, true, invalidateTokenCalled, "Expected different value")
  1321  		assert.Equal(t, true, getTokenCalled, "Expected different value")
  1322  		assert.Equal(t, true, downloadCalled, "Expected different value")
  1323  		assert.Equal(t, true, uploadCalled, "Expected different value")
  1324  		assert.Equal(t, true, inactivateCalled, "Expected different value")
  1325  	})
  1326  }
  1327  
  1328  func TestBase64EndodePlainToken(t *testing.T) {
  1329  	t.Run("Encoded token untouched", func(t *testing.T) {
  1330  		token := "OTUzODcwNDYtNWFjOC00NTcwLTg3NWQtYTVlYzhiZDhkM2Qy"
  1331  		encodedToken := base64EndodePlainToken(token)
  1332  		assert.Equal(t, token, encodedToken)
  1333  	})
  1334  	t.Run("Unencoded token gets encoded", func(t *testing.T) {
  1335  		token := "95387046-5ac8-4570-875d-a5ec8bd8d3d2"
  1336  		encodedToken := base64EndodePlainToken(token)
  1337  		assert.Equal(t, "OTUzODcwNDYtNWFjOC00NTcwLTg3NWQtYTVlYzhiZDhkM2Qy", encodedToken)
  1338  	})
  1339  }
  1340  
  1341  func TestCreateJSONReport(t *testing.T) {
  1342  	t.Run("test success", func(t *testing.T) {
  1343  		spotChecksCountByCategory := []SpotChecksAuditCount{}
  1344  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 3, Total: 3, Type: "J2EE Misconfiguration: Missing Error Handling"})
  1345  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 1, Total: 3, Type: "J2EE Bad Practices: Leftover Debug Code"})
  1346  		fortifyReportData := FortifyReportData{CorporateAudited: 30, CorporateTotal: 30, AuditAllTotal: 1, AuditAllAudited: 1, ProjectVersionID: 4999}
  1347  		jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
  1348  		assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
  1349  		assert.Equal(t, true, jsonReport.IsSpotChecksPerCategoryAudited)
  1350  		assert.Equal(t, 1, jsonReport.AuditAllAudited)
  1351  		assert.Equal(t, 1, jsonReport.AuditAllTotal)
  1352  		assert.Equal(t, 30, jsonReport.CorporateAudited)
  1353  		assert.Equal(t, 30, jsonReport.CorporateTotal)
  1354  		assert.Equal(t, "https://fortify-test.com/ssc/html/ssc/version/4999", jsonReport.URL)
  1355  		assert.Equal(t, "https://fortify-test.com/ssc", jsonReport.ToolInstance)
  1356  	})
  1357  
  1358  	t.Run("atleast one category spotchecks failed", func(t *testing.T) {
  1359  		spotChecksCountByCategory := []SpotChecksAuditCount{}
  1360  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 3, Total: 3, Type: "J2EE Misconfiguration: Missing Error Handling"})
  1361  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 0, Total: 1, Type: "J2EE Bad Practices: Leftover Debug Code"})
  1362  		fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
  1363  		jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
  1364  		assert.Equal(t, false, jsonReport.AtleastOneSpotChecksCategoryAudited)
  1365  		assert.Equal(t, false, jsonReport.IsSpotChecksPerCategoryAudited)
  1366  	})
  1367  
  1368  	t.Run("no spot checks audited", func(t *testing.T) {
  1369  		spotChecksCountByCategory := []SpotChecksAuditCount{}
  1370  		fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
  1371  		jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
  1372  		assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
  1373  		assert.Equal(t, true, jsonReport.IsSpotChecksPerCategoryAudited)
  1374  	})
  1375  
  1376  	t.Run("isSpotChecksPerCategoryAudited passed spotchecks test 1", func(t *testing.T) {
  1377  		spotChecksCountByCategory := []SpotChecksAuditCount{}
  1378  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 10, Total: 100, Type: "J2EE Misconfiguration: Missing Error Handling"})
  1379  		fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
  1380  		jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
  1381  		assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
  1382  		assert.Equal(t, true, jsonReport.IsSpotChecksPerCategoryAudited)
  1383  	})
  1384  
  1385  	t.Run("isSpotChecksPerCategoryAudited failed spotchecks test 2", func(t *testing.T) {
  1386  		spotChecksCountByCategory := []SpotChecksAuditCount{}
  1387  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 3, Total: 100, Type: "J2EE Misconfiguration: Missing Error Handling"})
  1388  		fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
  1389  		jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
  1390  		assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
  1391  		assert.Equal(t, false, jsonReport.IsSpotChecksPerCategoryAudited)
  1392  	})
  1393  
  1394  	t.Run("isSpotChecksPerCategoryAudited failed spotchecks test 3", func(t *testing.T) {
  1395  		spotChecksCountByCategory := []SpotChecksAuditCount{}
  1396  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 9, Total: 200, Type: "J2EE Misconfiguration: Missing Error Handling"})
  1397  		fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
  1398  		jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
  1399  		assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
  1400  		assert.Equal(t, false, jsonReport.IsSpotChecksPerCategoryAudited)
  1401  	})
  1402  
  1403  	t.Run("isSpotChecksPerCategoryAudited passed spotchecks test 4", func(t *testing.T) {
  1404  		spotChecksCountByCategory := []SpotChecksAuditCount{}
  1405  		spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 10, Total: 200, Type: "J2EE Misconfiguration: Missing Error Handling"})
  1406  		fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
  1407  		jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
  1408  		assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
  1409  		assert.Equal(t, true, jsonReport.IsSpotChecksPerCategoryAudited)
  1410  	})
  1411  }