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

     1  //go:build unit
     2  // +build unit
     3  
     4  package orchestrator
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"os"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/pkg/errors"
    14  
    15  	"net/http"
    16  
    17  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    18  	"github.com/jarcoal/httpmock"
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func TestJenkins(t *testing.T) {
    23  	t.Run("BranchBuild", func(t *testing.T) {
    24  		defer resetEnv(os.Environ())
    25  		os.Clearenv()
    26  		os.Setenv("JENKINS_URL", "FOO BAR BAZ")
    27  		os.Setenv("BUILD_URL", "https://jaas.url/job/foo/job/bar/job/main/1234/")
    28  		os.Setenv("BRANCH_NAME", "main")
    29  		os.Setenv("GIT_COMMIT", "abcdef42713")
    30  		os.Setenv("GIT_URL", "github.com/foo/bar")
    31  
    32  		p, _ := NewOrchestratorSpecificConfigProvider()
    33  
    34  		assert.False(t, p.IsPullRequest())
    35  		assert.Equal(t, "https://jaas.url/job/foo/job/bar/job/main/1234/", p.GetBuildURL())
    36  		assert.Equal(t, "main", p.GetBranch())
    37  		assert.Equal(t, "refs/heads/main", p.GetReference())
    38  		assert.Equal(t, "abcdef42713", p.GetCommit())
    39  		assert.Equal(t, "github.com/foo/bar", p.GetRepoURL())
    40  		assert.Equal(t, "Jenkins", p.OrchestratorType())
    41  	})
    42  
    43  	t.Run("PR", func(t *testing.T) {
    44  		defer resetEnv(os.Environ())
    45  		os.Clearenv()
    46  		os.Setenv("BRANCH_NAME", "PR-42")
    47  		os.Setenv("CHANGE_BRANCH", "feat/test-jenkins")
    48  		os.Setenv("CHANGE_TARGET", "main")
    49  		os.Setenv("CHANGE_ID", "42")
    50  
    51  		p := JenkinsConfigProvider{}
    52  		c := p.GetPullRequestConfig()
    53  
    54  		assert.True(t, p.IsPullRequest())
    55  		assert.Equal(t, "refs/pull/42/head", p.GetReference())
    56  		assert.Equal(t, "feat/test-jenkins", c.Branch)
    57  		assert.Equal(t, "main", c.Base)
    58  		assert.Equal(t, "42", c.Key)
    59  	})
    60  
    61  	t.Run("env variables", func(t *testing.T) {
    62  		defer resetEnv(os.Environ())
    63  		os.Clearenv()
    64  		os.Setenv("JENKINS_HOME", "/var/lib/jenkins")
    65  		os.Setenv("BUILD_ID", "1234")
    66  		os.Setenv("JOB_URL", "https://jaas.url/job/foo/job/bar/job/main")
    67  		os.Setenv("JENKINS_VERSION", "42")
    68  		os.Setenv("JOB_NAME", "foo/bar/BRANCH")
    69  		os.Setenv("STAGE_NAME", "Promote")
    70  		os.Setenv("BUILD_URL", "https://jaas.url/job/foo/job/bar/job/main/1234/")
    71  		os.Setenv("STAGE_NAME", "Promote")
    72  
    73  		p := JenkinsConfigProvider{}
    74  
    75  		assert.Equal(t, "/var/lib/jenkins", p.getJenkinsHome())
    76  		assert.Equal(t, "1234", p.GetBuildID())
    77  		assert.Equal(t, "https://jaas.url/job/foo/job/bar/job/main", p.GetJobURL())
    78  		assert.Equal(t, "42", p.OrchestratorVersion())
    79  		assert.Equal(t, "Jenkins", p.OrchestratorType())
    80  		assert.Equal(t, "foo/bar/BRANCH", p.GetJobName())
    81  		assert.Equal(t, "Promote", p.GetStageName())
    82  		assert.Equal(t, "https://jaas.url/job/foo/job/bar/job/main/1234/", p.GetBuildURL())
    83  
    84  	})
    85  }
    86  
    87  func TestJenkinsConfigProvider_GetPipelineStartTime(t *testing.T) {
    88  	type fields struct {
    89  		client  piperhttp.Client
    90  		options piperhttp.ClientOptions
    91  	}
    92  	tests := []struct {
    93  		name                    string
    94  		fields                  fields
    95  		want                    time.Time
    96  		wantHTTPErr             bool
    97  		wantHTTPStatusCodeError bool
    98  		wantHTTPJSONParseError  bool
    99  	}{
   100  		{
   101  			name:                    "Retrieve correct time",
   102  			want:                    time.Date(2022, time.March, 21, 22, 30, 0, 0, time.UTC),
   103  			wantHTTPErr:             false,
   104  			wantHTTPStatusCodeError: false,
   105  		},
   106  		{
   107  			name:                    "ParseHTTPResponseBodyJSON error",
   108  			want:                    time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
   109  			wantHTTPErr:             false,
   110  			wantHTTPStatusCodeError: false,
   111  		},
   112  		{
   113  			name:                    "GetRequest fails",
   114  			want:                    time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
   115  			wantHTTPErr:             true,
   116  			wantHTTPStatusCodeError: false,
   117  		},
   118  		{
   119  			name:                    "response code != 200 http.StatusNoContent",
   120  			want:                    time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
   121  			wantHTTPErr:             false,
   122  			wantHTTPStatusCodeError: true,
   123  		},
   124  		{
   125  			name:                    "parseResponseBodyJson fails",
   126  			want:                    time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
   127  			wantHTTPErr:             false,
   128  			wantHTTPStatusCodeError: false,
   129  			wantHTTPJSONParseError:  true,
   130  		},
   131  	}
   132  
   133  	j := &JenkinsConfigProvider{
   134  		client: piperhttp.Client{},
   135  	}
   136  	j.client.SetOptions(piperhttp.ClientOptions{
   137  		MaxRequestDuration:        5 * time.Second,
   138  		Token:                     "TOKEN",
   139  		TransportSkipVerification: true,
   140  		UseDefaultTransport:       true,
   141  		MaxRetries:                -1,
   142  	})
   143  	httpmock.Activate()
   144  
   145  	for _, tt := range tests {
   146  		t.Run(tt.name, func(t *testing.T) {
   147  			defer resetEnv(os.Environ())
   148  			os.Clearenv()
   149  			buildURl := "https://jaas.url/job/foo/job/bar/job/main/1234/"
   150  			os.Setenv("BUILD_URL", buildURl)
   151  
   152  			fakeUrl := buildURl + "api/json"
   153  			defer httpmock.DeactivateAndReset()
   154  			httpmock.RegisterResponder("GET", fakeUrl,
   155  				func(req *http.Request) (*http.Response, error) {
   156  					if tt.wantHTTPErr {
   157  						return nil, errors.New("this error shows up")
   158  					}
   159  					if tt.wantHTTPStatusCodeError {
   160  						return &http.Response{
   161  							Status:     "204",
   162  							StatusCode: http.StatusNoContent,
   163  							Request:    req,
   164  						}, nil
   165  					}
   166  					if tt.wantHTTPJSONParseError {
   167  						// Intentionally malformed JSON response
   168  						return httpmock.NewJsonResponse(200, "timestamp:asdffd")
   169  					}
   170  					return httpmock.NewStringResponse(200, "{\"timestamp\":1647901800932,\"url\":\"https://jaas.url/view/piperpipelines/job/foo/job/bar/job/main/3731/\"}"), nil
   171  				},
   172  			)
   173  
   174  			assert.Equalf(t, tt.want, j.GetPipelineStartTime(), "GetPipelineStartTime()")
   175  		})
   176  	}
   177  }
   178  
   179  func TestJenkinsConfigProvider_GetBuildStatus(t *testing.T) {
   180  	apiSuccess := []byte(`{ "queueId":376475,
   181  				"result":"SUCCESS",
   182  				"timestamp":1647946800925
   183  				}`)
   184  	apiFailure := []byte(`{ "queueId":376475,
   185  				"result":"FAILURE",
   186  				"timestamp":1647946800925
   187  				}`)
   188  	apiAborted := []byte(`{ "queueId":376475,
   189  				"result":"ABORTED",
   190  				"timestamp":1647946800925
   191  				}`)
   192  
   193  	apiOTHER := []byte(`{ "queueId":376475,
   194  				"result":"SOMETHING",
   195  				"timestamp":1647946800925
   196  				}`)
   197  
   198  	tests := []struct {
   199  		name           string
   200  		want           string
   201  		apiInformation []byte
   202  	}{
   203  		{
   204  			name:           "SUCCESS",
   205  			apiInformation: apiSuccess,
   206  			want:           "SUCCESS",
   207  		},
   208  		{
   209  			name:           "ABORTED",
   210  			apiInformation: apiAborted,
   211  			want:           "ABORTED",
   212  		},
   213  		{
   214  			name:           "FAILURE",
   215  			apiInformation: apiFailure,
   216  			want:           "FAILURE",
   217  		},
   218  		{
   219  			name:           "Unknown FAILURE",
   220  			apiInformation: apiOTHER,
   221  			want:           "FAILURE",
   222  		},
   223  	}
   224  	for _, tt := range tests {
   225  		t.Run(tt.name, func(t *testing.T) {
   226  			var apiInformation map[string]interface{}
   227  			err := json.Unmarshal(tt.apiInformation, &apiInformation)
   228  			if err != nil {
   229  				t.Fatal("could not parse json:", err)
   230  			}
   231  			j := &JenkinsConfigProvider{
   232  				apiInformation: apiInformation,
   233  			}
   234  			assert.Equalf(t, tt.want, j.GetBuildStatus(), "GetBuildStatus()")
   235  		})
   236  	}
   237  }
   238  
   239  func TestJenkinsConfigProvider_GetBuildReason(t *testing.T) {
   240  	apiJsonSchedule := []byte(`{
   241  				"_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
   242  				"actions": [{
   243  						"_class": "hudson.model.CauseAction",
   244  						"causes": [{
   245  							"_class": "hudson.triggers.TimerTrigger$TimerTriggerCause",
   246  							"shortDescription": "Started by timer"
   247  						}]
   248  					},
   249  					{
   250  						"_class": "jenkins.metrics.impl.TimeInQueueAction",
   251  						"blockedDurationMillis": "0"
   252  					}
   253  				]
   254  				}`)
   255  
   256  	apiJSONManual := []byte(`{
   257  				"_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
   258  				"actions": [{
   259  						"_class": "hudson.model.CauseAction",
   260  						"causes": [{
   261  							"_class": "hudson.model.Cause$UserIdCause",
   262  							"shortDescription": "Started by user John Doe",
   263  							"userId": "i12345",
   264  							"userName": "John Doe"
   265  						}]
   266  					},
   267  					{
   268  						"_class": "jenkins.metrics.impl.TimeInQueueAction",
   269  						"blockedDurationMillis": "0"
   270  					}
   271  				]
   272  				}`)
   273  
   274  	apiJSONPullRequest := []byte(`{
   275  				"_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
   276  				"actions": [ {
   277  					    "_class": "hudson.model.CauseAction",
   278  					    "causes": [
   279  						{
   280  						    "_class": "jenkins.branch.BranchEventCause",
   281  						    "shortDescription": "Pull request #1511 opened"
   282  						}
   283  					    ]
   284  					}]
   285  				}`)
   286  
   287  	apiJSONResourceTrigger := []byte(`{
   288  				"_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
   289  				"actions": [ {
   290  					    "_class": "hudson.model.CauseAction",
   291  					    "causes": [
   292  							{
   293  							    "_class": "org.jenkinsci.plugins.workflow.support.steps.build.BuildUpstreamCause",
   294  							    "shortDescription": "Started by upstream project \"dummy/dummy/PR-1234\" build number 42",
   295  							    "upstreamBuild": 24,
   296  							    "upstreamProject": "dummy/dummy/PR-1234",
   297  							    "upstreamUrl": "job/dummy/job/dummy/job/PR-1234/"
   298  							}
   299  						    ]
   300  					}]
   301  				}`)
   302  
   303  	apiJSONUnknown := []byte(`{
   304  				"_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
   305  				"actions": [{
   306  						"_class": "hudson.model.CauseAction",
   307  						"causes": [{
   308  							"_class": "hudson.model.RandomThingHere",
   309  							"shortDescription": "Something"
   310  						}]
   311  					},
   312  					{
   313  						"_class": "jenkins.metrics.impl.TimeInQueueAction",
   314  						"blockedDurationMillis": "0"
   315  					}
   316  				]
   317  				}`)
   318  
   319  	tests := []struct {
   320  		name           string
   321  		apiInformation []byte
   322  		want           string
   323  	}{
   324  		{
   325  			name:           "Manual trigger",
   326  			apiInformation: apiJSONManual,
   327  			want:           "Manual",
   328  		},
   329  		{
   330  			name:           "Scheduled trigger",
   331  			apiInformation: apiJsonSchedule,
   332  			want:           "Schedule",
   333  		},
   334  		{
   335  			name:           "PullRequest trigger",
   336  			apiInformation: apiJSONPullRequest,
   337  			want:           "PullRequest",
   338  		},
   339  		{
   340  			name:           "ResourceTrigger trigger",
   341  			apiInformation: apiJSONResourceTrigger,
   342  			want:           "ResourceTrigger",
   343  		},
   344  		{
   345  			name:           "Unknown",
   346  			apiInformation: apiJSONUnknown,
   347  			want:           "Unknown",
   348  		},
   349  		{
   350  			name:           "Empty api",
   351  			apiInformation: []byte(`{}`),
   352  			want:           "Unknown",
   353  		},
   354  		{
   355  			name: "Empty action api",
   356  			apiInformation: []byte(`{
   357  				"actions": [{}]
   358  			}`),
   359  			want: "Unknown",
   360  		},
   361  	}
   362  	for _, tt := range tests {
   363  		t.Run(tt.name, func(t *testing.T) {
   364  
   365  			var apiInformation map[string]interface{}
   366  			err := json.Unmarshal(tt.apiInformation, &apiInformation)
   367  			if err != nil {
   368  				t.Fatal("could not parse json:", err)
   369  			}
   370  			j := &JenkinsConfigProvider{apiInformation: apiInformation}
   371  
   372  			assert.Equalf(t, tt.want, j.GetBuildReason(), "GetBuildReason()")
   373  		})
   374  	}
   375  }
   376  
   377  func TestJenkinsConfigProvider_getAPIInformation(t *testing.T) {
   378  
   379  	tests := []struct {
   380  		name                    string
   381  		wantHTTPErr             bool
   382  		wantHTTPStatusCodeError bool
   383  		wantHTTPJSONParseError  bool
   384  		apiInformation          map[string]interface{}
   385  		wantAPIInformation      map[string]interface{}
   386  	}{
   387  		{
   388  			name:               "success case",
   389  			apiInformation:     map[string]interface{}{},
   390  			wantAPIInformation: map[string]interface{}{"Success": "Case"},
   391  		},
   392  		{
   393  			name:               "apiInformation already set",
   394  			apiInformation:     map[string]interface{}{"API info": "set"},
   395  			wantAPIInformation: map[string]interface{}{"API info": "set"},
   396  		},
   397  		{
   398  			name:               "failed to get response",
   399  			apiInformation:     map[string]interface{}{},
   400  			wantHTTPErr:        true,
   401  			wantAPIInformation: map[string]interface{}{},
   402  		},
   403  		{
   404  			name:                    "response code != 200 http.StatusNoContent",
   405  			wantHTTPStatusCodeError: true,
   406  			apiInformation:          map[string]interface{}{},
   407  			wantAPIInformation:      map[string]interface{}{},
   408  		},
   409  		{
   410  			name:                   "parseResponseBodyJson fails",
   411  			wantHTTPJSONParseError: true,
   412  			apiInformation:         map[string]interface{}{},
   413  			wantAPIInformation:     map[string]interface{}{},
   414  		},
   415  	}
   416  	for _, tt := range tests {
   417  		t.Run(tt.name, func(t *testing.T) {
   418  			j := &JenkinsConfigProvider{
   419  				apiInformation: tt.apiInformation,
   420  			}
   421  			j.client.SetOptions(piperhttp.ClientOptions{
   422  				MaxRequestDuration:        5 * time.Second,
   423  				Token:                     "TOKEN",
   424  				TransportSkipVerification: true,
   425  				UseDefaultTransport:       true, // need to use default transport for http mock
   426  				MaxRetries:                -1,
   427  			})
   428  
   429  			defer resetEnv(os.Environ())
   430  			os.Clearenv()
   431  			os.Setenv("BUILD_URL", "https://jaas.url/job/foo/job/bar/job/main/1234/")
   432  
   433  			fakeUrl := "https://jaas.url/job/foo/job/bar/job/main/1234/api/json"
   434  			httpmock.Activate()
   435  			defer httpmock.DeactivateAndReset()
   436  			httpmock.RegisterResponder("GET", fakeUrl,
   437  				func(req *http.Request) (*http.Response, error) {
   438  					if tt.wantHTTPErr {
   439  						return nil, errors.New("this error shows up")
   440  					}
   441  					if tt.wantHTTPStatusCodeError {
   442  						return &http.Response{
   443  							Status:     "204",
   444  							StatusCode: http.StatusNoContent,
   445  							Request:    req,
   446  						}, nil
   447  					}
   448  					if tt.wantHTTPJSONParseError {
   449  						// Intentionally malformed JSON response
   450  						return httpmock.NewJsonResponse(200, "timestamp:broken")
   451  					}
   452  					return httpmock.NewStringResponse(200, "{\"Success\":\"Case\"}"), nil
   453  				},
   454  			)
   455  			j.fetchAPIInformation()
   456  			assert.Equal(t, tt.wantAPIInformation, j.apiInformation)
   457  		})
   458  	}
   459  }
   460  
   461  func TestJenkinsConfigProvider_GetLog(t *testing.T) {
   462  
   463  	tests := []struct {
   464  		name                    string
   465  		want                    []byte
   466  		wantErr                 assert.ErrorAssertionFunc
   467  		wantHTTPErr             bool
   468  		wantHTTPStatusCodeError bool
   469  	}{
   470  		{
   471  			name:    "Successfully got log file",
   472  			want:    []byte("Success!"),
   473  			wantErr: assert.NoError,
   474  		},
   475  		{
   476  			name:        "HTTP error",
   477  			want:        []byte(""),
   478  			wantErr:     assert.Error,
   479  			wantHTTPErr: true,
   480  		},
   481  		{
   482  			name:                    "Status code error",
   483  			want:                    []byte(""),
   484  			wantErr:                 assert.NoError,
   485  			wantHTTPStatusCodeError: true,
   486  		},
   487  	}
   488  	for _, tt := range tests {
   489  		t.Run(tt.name, func(t *testing.T) {
   490  			j := &JenkinsConfigProvider{}
   491  			j.client.SetOptions(piperhttp.ClientOptions{
   492  				MaxRequestDuration:        5 * time.Second,
   493  				Token:                     "TOKEN",
   494  				TransportSkipVerification: true,
   495  				UseDefaultTransport:       true, // need to use default transport for http mock
   496  				MaxRetries:                -1,
   497  			})
   498  
   499  			defer resetEnv(os.Environ())
   500  			os.Clearenv()
   501  			os.Setenv("BUILD_URL", "https://jaas.url/job/foo/job/bar/job/main/1234/")
   502  
   503  			fakeUrl := "https://jaas.url/job/foo/job/bar/job/main/1234/consoleText"
   504  			httpmock.Activate()
   505  			defer httpmock.DeactivateAndReset()
   506  			httpmock.RegisterResponder("GET", fakeUrl,
   507  				func(req *http.Request) (*http.Response, error) {
   508  					if tt.wantHTTPErr {
   509  						return nil, errors.New("this error shows up")
   510  					}
   511  					if tt.wantHTTPStatusCodeError {
   512  						return &http.Response{
   513  							Status:     "204",
   514  							StatusCode: http.StatusNoContent,
   515  							Request:    req,
   516  						}, nil
   517  					}
   518  					return httpmock.NewStringResponse(200, "Success!"), nil
   519  				},
   520  			)
   521  
   522  			got, err := j.GetLog()
   523  			if !tt.wantErr(t, err, fmt.Sprintf("GetLog()")) {
   524  				return
   525  			}
   526  			assert.Equalf(t, tt.want, got, "GetLog()")
   527  		})
   528  	}
   529  }
   530  
   531  func TestJenkinsConfigProvider_InitOrchestratorProvider(t *testing.T) {
   532  
   533  	tests := []struct {
   534  		name           string
   535  		settings       *OrchestratorSettings
   536  		apiInformation map[string]interface{}
   537  	}{
   538  		{
   539  			name:     "Init, test empty apiInformation",
   540  			settings: &OrchestratorSettings{},
   541  		},
   542  	}
   543  	for _, tt := range tests {
   544  		t.Run(tt.name, func(t *testing.T) {
   545  			j := &JenkinsConfigProvider{}
   546  			j.InitOrchestratorProvider(tt.settings)
   547  			var expected map[string]interface{}
   548  			assert.Equal(t, j.apiInformation, expected)
   549  		})
   550  	}
   551  }
   552  
   553  func TestJenkinsConfigProvider_GetChangeSet(t *testing.T) {
   554  
   555  	changeSetTwo := []byte(`{
   556  "displayName": "#531",
   557  "duration": 424269,
   558  "changeSets": [
   559          {
   560              "_class": "hudson.plugins.git.GitChangeSetList",
   561              "items": [
   562                  {
   563                      "_class": "hudson.plugins.git.GitChangeSet",
   564                      "commitId": "987654321",
   565                      "timestamp": 1655057520000
   566                  },
   567  		{
   568                      "_class": "hudson.plugins.git.GitChangeSet",
   569                      "commitId": "123456789",
   570                      "timestamp": 1656057520000
   571                  }
   572              ],
   573              "kind": "git"
   574          }
   575      ]
   576  }`)
   577  
   578  	changeSetMultiple := []byte(`{
   579  "displayName": "#531",
   580  "duration": 424269,
   581  "changeSets": [
   582      {
   583          "_class": "hudson.plugins.git.GitChangeSetList",
   584          "items": [
   585              {
   586                  "_class": "hudson.plugins.git.GitChangeSet",
   587                  "commitId": "987654321",
   588                  "timestamp": 1655057520000
   589              },
   590              {
   591                  "_class": "hudson.plugins.git.GitChangeSet",
   592                  "commitId": "123456789",
   593                  "timestamp": 1656057520000
   594              }
   595          ],
   596          "kind": "git"
   597      },
   598      {
   599          "_class": "hudson.plugins.git.GitChangeSetList",
   600          "items": [
   601              {
   602                  "_class": "hudson.plugins.git.GitChangeSet",
   603                  "commitId": "456789123",
   604                  "timestamp": 1659948036000
   605              },
   606              {
   607                  "_class": "hudson.plugins.git.GitChangeSet",
   608                  "commitId": "654717777",
   609                  "timestamp": 1660053494000
   610              }
   611          ],
   612          "kind": "git"
   613      }
   614  ]
   615  }`)
   616  
   617  	changeSetEmpty := []byte(`{
   618  "displayName": "#531",
   619  "duration": 424269,
   620  "changeSets": []
   621  }`)
   622  	changeSetNotAvailable := []byte(`{
   623  "displayName": "#531",
   624  "duration": 424269
   625  }`)
   626  	tests := []struct {
   627  		name          string
   628  		want          []ChangeSet
   629  		testChangeSet []byte
   630  	}{
   631  		{
   632  			name: "success",
   633  			want: []ChangeSet{
   634  				{CommitId: "987654321", Timestamp: "1655057520000"},
   635  				{CommitId: "123456789", Timestamp: "1656057520000"},
   636  			},
   637  			testChangeSet: changeSetTwo,
   638  		},
   639  		{
   640  			name: "success multiple",
   641  			want: []ChangeSet{
   642  				{CommitId: "987654321", Timestamp: "1655057520000"},
   643  				{CommitId: "123456789", Timestamp: "1656057520000"},
   644  				{CommitId: "456789123", Timestamp: "1659948036000"},
   645  				{CommitId: "654717777", Timestamp: "1660053494000"},
   646  			},
   647  			testChangeSet: changeSetMultiple,
   648  		},
   649  		{
   650  			name:          "failure - changeSet empty",
   651  			want:          []ChangeSet(nil),
   652  			testChangeSet: changeSetEmpty,
   653  		},
   654  		{
   655  			name:          "failure - no changeSet found",
   656  			want:          []ChangeSet(nil),
   657  			testChangeSet: changeSetNotAvailable,
   658  		},
   659  	}
   660  	for _, tt := range tests {
   661  		t.Run(tt.name, func(t *testing.T) {
   662  			var apiInformation map[string]interface{}
   663  			err := json.Unmarshal(tt.testChangeSet, &apiInformation)
   664  			if err != nil {
   665  				t.Fatal("could not parse json:", err)
   666  			}
   667  			j := &JenkinsConfigProvider{apiInformation: apiInformation}
   668  			assert.Equalf(t, tt.want, j.GetChangeSet(), "GetChangeSet()")
   669  		})
   670  	}
   671  }