Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

Commit 136d2fb

Browse files
authored
submission id used to detect lost runs (#347)
Closes a timing window when tests run quickly, and get cleaned out from the DSS before the client can get the final run status. Using the submission ID to query the RAS for that final status. * submission id used to detect lost runs * tidy up the submitter handling potentially lost runs * submission id is remembered so we can use it to check for lost runs Signed-off-by: Mike Cobbett <77053+techcobweb@users.noreply.github.com>
1 parent 2074086 commit 136d2fb

File tree

10 files changed

+220
-76
lines changed

10 files changed

+220
-76
lines changed

pkg/launcher/jvmLauncher.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"strconv"
1313
"strings"
1414

15+
"github.com/google/uuid"
16+
1517
"github.com/galasa-dev/cli/pkg/api"
1618
"github.com/galasa-dev/cli/pkg/embedded"
1719
galasaErrors "github.com/galasa-dev/cli/pkg/errors"
@@ -301,6 +303,7 @@ func (launcher *JvmLauncher) SubmitTestRun(
301303
localTest.testRun.SetTrace(isTraceEnabled)
302304
localTest.testRun.SetType(requestType)
303305
localTest.testRun.SetName(localTest.runId)
306+
localTest.testRun.SetSubmissionId(uuid.New().String())
304307

305308
// The test run we started can be returned to the submitter.
306309
testRuns.Runs = append(testRuns.Runs, *localTest.testRun)
@@ -527,6 +530,15 @@ func (launcher *JvmLauncher) GetRunsById(runId string) (*galasaapi.Run, error) {
527530
return run, err
528531
}
529532

533+
// Gets a run based on the submission ID of that run.
534+
// For local runs, the submission ID is the same as the test run id.
535+
func (launcher *JvmLauncher) GetRunsBySubmissionId(submissionId string, groupId string) (*galasaapi.Run, error) {
536+
log.Printf("JvmLauncher: GetRunsBySubmissionId entered. runId=%s", submissionId)
537+
538+
log.Printf("JvmLauncher: Local runs cannot find tests based on submission ID")
539+
return nil, nil
540+
}
541+
530542
func createRunFromLocalTest(localTest *LocalTest) (*galasaapi.Run, error) {
531543

532544
var run = galasaapi.NewRun()

pkg/launcher/launcher.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ type Launcher interface {
3535
// GetRunsById gets the Run information for the run with a specific run identifier
3636
GetRunsById(runId string) (*galasaapi.Run, error)
3737

38+
// Gets a run based on the submission ID of that run.
39+
GetRunsBySubmissionId(submissionId string, groupId string) (*galasaapi.Run, error)
40+
3841
// GetStreams gets a list of streams available on this launcher
3942
GetStreams() ([]string, error)
4043

pkg/launcher/launcherMock.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package launcher
77

88
import (
99
"fmt"
10+
"strconv"
1011
"strings"
1112

1213
"github.com/galasa-dev/cli/pkg/galasaapi"
@@ -28,16 +29,18 @@ type LaunchParameters struct {
2829
}
2930

3031
type MockLauncher struct {
31-
allTestRuns *galasaapi.TestRuns
32-
nextRunId int
33-
launches []LaunchParameters
32+
allTestRuns *galasaapi.TestRuns
33+
nextRunId int
34+
launches []LaunchParameters
35+
submissionId int
3436
}
3537

3638
func NewMockLauncher() *MockLauncher {
3739
launcher := new(MockLauncher)
3840
launcher.allTestRuns = newEmptyTestRun()
3941
launcher.allTestRuns.Runs = make([]galasaapi.TestRun, 0)
4042
launcher.nextRunId = 100
43+
launcher.submissionId = 0
4144
return launcher
4245
}
4346

@@ -71,7 +74,7 @@ func (launcher *MockLauncher) SubmitTestRun(
7174
stream string,
7275
obrFromPortfolio string,
7376
isTraceEnabled bool,
74-
GherkinURL string,
77+
GherkinURL string,
7578
GherkinFeature string,
7679
overrides map[string]interface{},
7780
) (*galasaapi.TestRuns, error) {
@@ -93,6 +96,7 @@ func (launcher *MockLauncher) SubmitTestRun(
9396

9497
newTestRun := galasaapi.NewTestRun()
9598
newTestRun.SetGroup(groupName)
99+
newTestRun.SetSubmissionId(strconv.Itoa(launcher.submissionId))
96100

97101
classNameParts := strings.Split(className, "/")
98102
bundleName := classNameParts[0]
@@ -123,6 +127,11 @@ func (launcher *MockLauncher) GetRunsById(runId string) (*galasaapi.Run, error)
123127
return &galasaapi.Run{}, nil
124128
}
125129

130+
// Gets a run based on the submission ID of that run.
131+
func (launcher *MockLauncher) GetRunsBySubmissionId(submissionId string, groupId string) (*galasaapi.Run, error) {
132+
return &galasaapi.Run{}, nil
133+
}
134+
126135
// GetStreams gets a list of streams available on this launcher
127136
func (launcher *MockLauncher) GetStreams() ([]string, error) {
128137
return make([]string, 0), nil

pkg/launcher/remoteLauncher.go

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"io"
1212
"log"
1313
"net/http"
14+
"strconv"
1415
"strings"
1516

1617
"github.com/galasa-dev/cli/pkg/api"
@@ -36,7 +37,7 @@ func NewRemoteLauncher(commsClient api.APICommsClient) *RemoteLauncher {
3637

3738
// A comms client that communicates with the API server in a Galasa service.
3839
launcher.commsClient = commsClient
39-
40+
4041
return launcher
4142
}
4243

@@ -125,6 +126,60 @@ func (launcher *RemoteLauncher) GetRunsById(runId string) (*galasaapi.Run, error
125126
return rasRun, err
126127
}
127128

129+
// Gets the latest run based on the submission ID of that run.
130+
// For local runs, the submission ID is the same as the test run id.
131+
func (launcher *RemoteLauncher) GetRunsBySubmissionId(submissionId string, groupId string) (*galasaapi.Run, error) {
132+
log.Printf("RemoteLauncher: GetRunsBySubmissionId entered. runId=%v groupId=%v", submissionId, groupId)
133+
var err error
134+
var rasRun *galasaapi.Run
135+
var restApiVersion string
136+
137+
restApiVersion, err = embedded.GetGalasactlRestApiVersion()
138+
139+
if err == nil {
140+
var runData *galasaapi.RunResults
141+
142+
err = launcher.commsClient.RunAuthenticatedCommandWithRateLimitRetries(func(apiClient *galasaapi.APIClient) error {
143+
var err error
144+
var httpResponse *http.Response
145+
var context context.Context = nil
146+
147+
apicall := apiClient.ResultArchiveStoreAPIApi.GetRasSearchRuns(context).ClientApiVersion(restApiVersion).
148+
IncludeCursor("true").
149+
SubmissionId(submissionId).Group(groupId).Sort("from:desc")
150+
151+
runData, httpResponse, err = apicall.Execute()
152+
153+
var statusCode int
154+
if httpResponse != nil {
155+
defer httpResponse.Body.Close()
156+
statusCode = httpResponse.StatusCode
157+
}
158+
159+
if err != nil {
160+
err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_QUERY_RUNS_FAILED, err.Error())
161+
} else {
162+
if statusCode != http.StatusOK {
163+
httpError := "\nhttp response status code: " + strconv.Itoa(statusCode)
164+
errString := httpError
165+
err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_QUERY_RUNS_FAILED, errString)
166+
} else {
167+
168+
log.Printf("HTTP status was OK")
169+
170+
if runData.GetAmountOfRuns() > 0 {
171+
runs := runData.GetRuns()
172+
rasRun = &runs[0]
173+
}
174+
175+
}
176+
}
177+
return err
178+
})
179+
}
180+
return rasRun, err
181+
}
182+
128183
func (launcher *RemoteLauncher) GetStreams() ([]string, error) {
129184

130185
var streams []string
@@ -179,14 +234,14 @@ func (launcher *RemoteLauncher) GetTestCatalog(stream string) (TestCatalog, erro
179234
if err == nil {
180235
var cpsResponse *http.Response
181236
err = launcher.commsClient.RunAuthenticatedCommandWithRateLimitRetries(func(apiClient *galasaapi.APIClient) error {
182-
cpsProperty, cpsResponse, err = apiClient.ConfigurationPropertyStoreAPIApi.QueryCpsNamespaceProperties(context.TODO(), "framework").Prefix("test.stream."+stream).Suffix("location").ClientApiVersion(restApiVersion).Execute()
183-
237+
cpsProperty, cpsResponse, err = apiClient.ConfigurationPropertyStoreAPIApi.QueryCpsNamespaceProperties(context.TODO(), "framework").Prefix("test.stream." + stream).Suffix("location").ClientApiVersion(restApiVersion).Execute()
238+
184239
var statusCode int
185240
if cpsResponse != nil {
186241
defer cpsResponse.Body.Close()
187242
statusCode = cpsResponse.StatusCode
188243
}
189-
244+
190245
if err != nil {
191246
err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_PROPERTY_GET_FAILED, stream, err)
192247
} else if len(cpsProperty) < 1 {
@@ -196,7 +251,7 @@ func (launcher *RemoteLauncher) GetTestCatalog(stream string) (TestCatalog, erro
196251
})
197252

198253
if err == nil {
199-
streamLocation :=cpsProperty[0].Data.Value
254+
streamLocation := cpsProperty[0].Data.Value
200255
catalogString := new(strings.Builder)
201256
var resp *http.Response
202257
resp, err = http.Get(*streamLocation)

pkg/launcher/remoteLauncher_test.go

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ func TestGetTestCatalogHttpErrorGetsReported(t *testing.T) {
124124
}))
125125
defer server.Close()
126126

127-
128127
mockFactory := utils.NewMockFactory()
129128
apiServerUrl := server.URL
130129
apiClient := api.InitialiseAPI(apiServerUrl)
@@ -134,11 +133,11 @@ func TestGetTestCatalogHttpErrorGetsReported(t *testing.T) {
134133
mockFileSystem := mockFactory.GetFileSystem()
135134
mockEnvironment := mockFactory.GetEnvironment()
136135
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
137-
mockFileSystem.WriteTextFile(mockGalasaHome.GetUrlFolderPath() + "/bootstrap.properties", "")
136+
mockFileSystem.WriteTextFile(mockGalasaHome.GetUrlFolderPath()+"/bootstrap.properties", "")
138137

139138
bootstrap := ""
140-
maxAttempts := 3
141-
retryBackoffSeconds := 1
139+
maxAttempts := 3
140+
retryBackoffSeconds := 1
142141

143142
commsClient, _ := api.NewAPICommsClient(bootstrap, maxAttempts, float64(retryBackoffSeconds), mockFactory, mockGalasaHome)
144143

@@ -153,56 +152,56 @@ func TestGetTestCatalogHttpErrorGetsReported(t *testing.T) {
153152
func TestGetRunsByGroupWithInvalidBearerTokenGetsNewTokenOk(t *testing.T) {
154153
groupId := "group1"
155154

156-
initialLoginOperation := utils.NewHttpInteraction("/auth/tokens", http.MethodPost)
157-
initialLoginOperation.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
158-
writer.Header().Set("Content-Type", "application/json")
159-
writer.WriteHeader(http.StatusCreated)
155+
initialLoginOperation := utils.NewHttpInteraction("/auth/tokens", http.MethodPost)
156+
initialLoginOperation.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
157+
writer.Header().Set("Content-Type", "application/json")
158+
writer.WriteHeader(http.StatusCreated)
160159

161160
mockResponse := fmt.Sprintf(`{"jwt": "%s", "refresh_token": "abc"}`, mockExpiredJwt)
162-
writer.Write([]byte(mockResponse))
163-
}
161+
writer.Write([]byte(mockResponse))
162+
}
164163

165-
unauthorizedGetRunsInteraction := utils.NewHttpInteraction("/runs/" + groupId, http.MethodGet)
166-
unauthorizedGetRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
167-
writer.Header().Set("Content-Type", "application/json")
168-
writer.WriteHeader(http.StatusUnauthorized)
169-
writer.Write([]byte(`{ "error_message": "Invalid bearer token provided!" }`))
170-
}
164+
unauthorizedGetRunsInteraction := utils.NewHttpInteraction("/runs/"+groupId, http.MethodGet)
165+
unauthorizedGetRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
166+
writer.Header().Set("Content-Type", "application/json")
167+
writer.WriteHeader(http.StatusUnauthorized)
168+
writer.Write([]byte(`{ "error_message": "Invalid bearer token provided!" }`))
169+
}
171170

172171
newLoginInteraction := utils.NewHttpInteraction("/auth/tokens", http.MethodPost)
173-
newLoginInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
174-
writer.Header().Set("Content-Type", "application/json")
175-
writer.WriteHeader(http.StatusCreated)
172+
newLoginInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
173+
writer.Header().Set("Content-Type", "application/json")
174+
writer.WriteHeader(http.StatusCreated)
176175

177176
newJwt := createValidMockJwt()
178177
fmt.Println(newJwt)
179178
mockResponse := fmt.Sprintf(`{"jwt": "%s", "refresh_token": "abc"}`, newJwt)
180-
writer.Write([]byte(mockResponse))
181-
}
179+
writer.Write([]byte(mockResponse))
180+
}
182181

183-
getRunsInteraction := utils.NewHttpInteraction("/runs/" + groupId, http.MethodGet)
184-
getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
185-
writer.Header().Set("Content-Type", "application/json")
186-
writer.WriteHeader(http.StatusOK)
182+
getRunsInteraction := utils.NewHttpInteraction("/runs/"+groupId, http.MethodGet)
183+
getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) {
184+
writer.Header().Set("Content-Type", "application/json")
185+
writer.WriteHeader(http.StatusOK)
187186

188187
mockRun := galasaapi.NewTestRun()
189188

190189
mockRuns := galasaapi.NewTestRuns()
191-
mockRuns.Runs = []galasaapi.TestRun{ *mockRun }
190+
mockRuns.Runs = []galasaapi.TestRun{*mockRun}
192191
mockRunsBytes, _ := json.Marshal(mockRuns)
193192

194-
writer.Write(mockRunsBytes)
195-
}
193+
writer.Write(mockRunsBytes)
194+
}
196195

197-
interactions := []utils.HttpInteraction{
196+
interactions := []utils.HttpInteraction{
198197
initialLoginOperation,
199-
unauthorizedGetRunsInteraction,
198+
unauthorizedGetRunsInteraction,
200199
newLoginInteraction,
201200
getRunsInteraction,
202-
}
201+
}
203202

204-
server := utils.NewMockHttpServer(t, interactions)
205-
defer server.Server.Close()
203+
server := utils.NewMockHttpServer(t, interactions)
204+
defer server.Server.Close()
206205

207206
mockFactory := utils.NewMockFactory()
208207

@@ -212,16 +211,16 @@ func TestGetRunsByGroupWithInvalidBearerTokenGetsNewTokenOk(t *testing.T) {
212211
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
213212
mockTimeService := mockFactory.GetTimeService()
214213
jwtCache := auth.NewJwtCache(mockFileSystem, mockGalasaHome, mockTimeService)
215-
216-
mockFileSystem.WriteTextFile(mockGalasaHome.GetUrlFolderPath() + "/galasactl.properties", "GALASA_TOKEN=my:token")
217-
mockFileSystem.WriteTextFile(mockGalasaHome.GetUrlFolderPath() + "/bootstrap.properties", "")
214+
215+
mockFileSystem.WriteTextFile(mockGalasaHome.GetUrlFolderPath()+"/galasactl.properties", "GALASA_TOKEN=my:token")
216+
mockFileSystem.WriteTextFile(mockGalasaHome.GetUrlFolderPath()+"/bootstrap.properties", "")
218217

219218
authenticator := auth.NewAuthenticator(apiServerUrl, mockFileSystem, mockGalasaHome, mockTimeService, mockEnvironment, jwtCache)
220219
mockFactory.Authenticator = authenticator
221220

222221
bootstrap := ""
223-
maxAttempts := 3
224-
retryBackoffSeconds := 1
222+
maxAttempts := 3
223+
retryBackoffSeconds := 1
225224

226225
commsClient, _ := api.NewAPICommsClient(bootstrap, maxAttempts, float64(retryBackoffSeconds), mockFactory, mockGalasaHome)
227226

pkg/runs/jsonReporter_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func TestJsonReportWorks(t *testing.T) {
2929
Tests: []TestMethod{{Method: "method1", Result: "passed"}, {Method: "method2", Result: "passed"}},
3030
GherkinUrl: "file:///my.feature",
3131
GherkinFeature: "my",
32+
SubmissionId: "123",
3233
}
3334

3435
finishedRunsMap := make(map[string]*TestRun, 1)
@@ -79,7 +80,8 @@ func TestJsonReportWorks(t *testing.T) {
7980
],
8081
"GherkinUrl":"file:///my.feature",
8182
"GherkinFeature":"my",
82-
"group":""
83+
"group":"",
84+
"submissionId":"123"
8385
}
8486
]
8587
}`

pkg/runs/runTypes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type TestRun struct {
2020
GherkinUrl string `yaml:"gherkin"`
2121
GherkinFeature string `yaml:"feature"`
2222
Group string `yaml:"group" json:"group"`
23+
SubmissionId string `yaml:"submissionId" json:"submissionId"`
2324
RunId string `yaml:"runId,omitempty" json:"runId,omitempty"`
2425
}
2526

0 commit comments

Comments
 (0)