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

Commit 5d58ee5

Browse files
authored
Merge pull request #233 from galasa-dev/mcobbett-1813-support-remote-CPS-supply-jwt
CLI supplies a JWT to a local launched test if framework.config.store bootstrap value starts with galasacps
2 parents d48761a + ec9f55a commit 5d58ee5

File tree

7 files changed

+128
-66
lines changed

7 files changed

+128
-66
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,4 +619,20 @@ The docker image has the `galasactl` tool on the path of the docker image when i
619619
So, invoke the `galasactl` without installing on your local machine, using the docker image like this:
620620
```
621621
docker run harbor.galasa.dev/galasadev/galasa-cli-amd64:main galasactl --version
622-
```
622+
```
623+
624+
## Running a test locally, but using shared configuration properties on a remote Galasa server
625+
This configuration is supported. An ecosystem can be set up with CPS (configuration properties store) properties.
626+
627+
The galasactl tool can be configured to communicate with that CPS.
628+
629+
To do this, assuming `https://myhost/api/bootstrap` can be used to
630+
communicate with the remote server, add the following to your `bootstrap.properties` file,
631+
```
632+
# Tell the galasactl tool that local tests should use the REST API to get shared configuration properties from a remote server.
633+
# https://myhost/api is the location of the Galasa REST API endpoints.
634+
framework.config.store=galasacps://myhost/api
635+
framework.extra.bundles=dev.galasa.cps.rest
636+
```
637+
638+
The user must perform a `galasactl auth login` to the same ecosystem before trying to launch a local test.

docs/generated/errors-list.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ The `galasactl` tool can generate the following errors:
137137
- GAL1141E: Unable to compile the regex pattern for Galasa Property field '{}'. Reason: '{}'
138138
- GAL1142E: The {} field value, '{}', provided does not match formatting requirements. The {} field value must start with a character in the 'a-z' or 'A-Z' range, followed by any characters in the 'a'-'z', 'A'-'Z', '0'-'9', '.' (period), '-' (dash) or '_' (underscore) ranges only.
139139
- GAL1143E: Could not query run results. Server returned a non-200 code ({})
140+
- GAL1144E: Could not use url '{}' to retrieve the contents of the test catalog from stream '{}'. Http error from the Galasa server is '{}'
140141
- GAL1225E: Failed to open file '{}' cause: {}. Check that this file exists, and that you have read permissions.
141142
- GAL1226E: Internal failure. Contents of gzip could be read, but not decoded. New gzip reader failed: file: {} error: {}
142143
- GAL1227E: Internal failure. Contents of gzip could not be decoded. {} error: {}

pkg/auth/authLogin.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func Login(apiServerUrl string, fileSystem files.FileSystem, galasaHome utils.Ga
2828
var jwt string
2929
jwt, err = GetJwtFromRestApi(apiServerUrl, authProperties)
3030
if err == nil {
31-
err = WriteBearerTokenJsonFile(fileSystem, galasaHome, jwt)
31+
err = utils.WriteBearerTokenJsonFile(fileSystem, galasaHome, jwt)
3232
}
3333
}
3434
return err
@@ -93,14 +93,14 @@ func GetBearerToken(
9393
timeService utils.TimeService,
9494
env utils.Environment,
9595
) (string, error) {
96-
bearerToken, err := GetBearerTokenFromTokenJsonFile(fileSystem, galasaHome, timeService)
96+
bearerToken, err := utils.GetBearerTokenFromTokenJsonFile(fileSystem, galasaHome, timeService)
9797
if err != nil {
9898
// Attempt to log in
9999
log.Printf("Logging in to the Galasa Ecosystem at '%s'", apiServerUrl)
100100
err = Login(apiServerUrl, fileSystem, galasaHome, env)
101101
if err == nil {
102102
log.Printf("Logged in to the Galasa Ecosystem at '%s' OK", apiServerUrl)
103-
bearerToken, err = GetBearerTokenFromTokenJsonFile(fileSystem, galasaHome, timeService)
103+
bearerToken, err = utils.GetBearerTokenFromTokenJsonFile(fileSystem, galasaHome, timeService)
104104
}
105105
}
106106
return bearerToken, err

pkg/launcher/jvmLauncher.go

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -240,44 +240,57 @@ func (launcher *JvmLauncher) SubmitTestRun(
240240
}
241241

242242
if err == nil {
243-
var (
244-
cmd string
245-
args []string
246-
)
247-
cmd, args, err = getCommandSyntax(
248-
launcher.bootstrapProps,
249-
launcher.galasaHome,
250-
launcher.fileSystem, launcher.javaHome, obrs,
251-
*testClassToLaunch, launcher.cmdParams.RemoteMaven, launcher.cmdParams.LocalMaven,
252-
launcher.cmdParams.TargetGalasaVersion, overridesFilePath,
253-
gherkinURL,
254-
isTraceEnabled,
255-
launcher.cmdParams.IsDebugEnabled,
256-
launcher.cmdParams.DebugPort,
257-
launcher.cmdParams.DebugMode,
258-
)
243+
244+
var jwt = ""
245+
if launcher.isCPSRemote() {
246+
// Though this is a local test run being launched, the CPS will be remote on an ecosystem via REST.
247+
// If the config store value doesn't start wiht that, then it's not a remote CPS, so we don't need the JWT.
248+
log.Printf("framework.config.store bootstrap property indicates a remote CPS will be used. So we need a valid JWT.\n")
249+
jwt, err = utils.GetBearerTokenFromTokenJsonFile(launcher.fileSystem, launcher.galasaHome, launcher.timeService)
250+
}
251+
259252
if err == nil {
260-
log.Printf("Launching command '%s' '%v'\n", cmd, args)
261-
localTest := NewLocalTest(launcher.timeService, launcher.fileSystem, launcher.processFactory)
262-
err = localTest.launch(cmd, args)
263253

254+
var (
255+
cmd string
256+
args []string
257+
)
258+
cmd, args, err = getCommandSyntax(
259+
launcher.bootstrapProps,
260+
launcher.galasaHome,
261+
launcher.fileSystem, launcher.javaHome, obrs,
262+
*testClassToLaunch, launcher.cmdParams.RemoteMaven, launcher.cmdParams.LocalMaven,
263+
launcher.cmdParams.TargetGalasaVersion, overridesFilePath,
264+
gherkinURL,
265+
isTraceEnabled,
266+
launcher.cmdParams.IsDebugEnabled,
267+
launcher.cmdParams.DebugPort,
268+
launcher.cmdParams.DebugMode,
269+
jwt,
270+
)
264271
if err == nil {
265-
// The JVM process started. Store away its' details
266-
launcher.localTests = append(launcher.localTests, localTest)
267-
268-
localTest.testRun = new(galasaapi.TestRun)
269-
if testClassToLaunch.OSGiBundleName != "" {
270-
localTest.testRun.SetBundleName(testClassToLaunch.OSGiBundleName)
272+
log.Printf("Launching command '%s' '%v'\n", cmd, args)
273+
localTest := NewLocalTest(launcher.timeService, launcher.fileSystem, launcher.processFactory)
274+
err = localTest.launch(cmd, args)
275+
276+
if err == nil {
277+
// The JVM process started. Store away its' details
278+
launcher.localTests = append(launcher.localTests, localTest)
279+
280+
localTest.testRun = new(galasaapi.TestRun)
281+
if testClassToLaunch.OSGiBundleName != "" {
282+
localTest.testRun.SetBundleName(testClassToLaunch.OSGiBundleName)
283+
}
284+
localTest.testRun.SetStream(stream)
285+
localTest.testRun.SetGroup(groupName)
286+
localTest.testRun.SetRequestor(requestor)
287+
localTest.testRun.SetTrace(isTraceEnabled)
288+
localTest.testRun.SetType(requestType)
289+
localTest.testRun.SetName(localTest.runId)
290+
291+
// The test run we started can be returned to the submitter.
292+
testRuns.Runs = append(testRuns.Runs, *localTest.testRun)
271293
}
272-
localTest.testRun.SetStream(stream)
273-
localTest.testRun.SetGroup(groupName)
274-
localTest.testRun.SetRequestor(requestor)
275-
localTest.testRun.SetTrace(isTraceEnabled)
276-
localTest.testRun.SetType(requestType)
277-
localTest.testRun.SetName(localTest.runId)
278-
279-
// The test run we started can be returned to the submitter.
280-
testRuns.Runs = append(testRuns.Runs, *localTest.testRun)
281294
}
282295
}
283296
}
@@ -288,6 +301,15 @@ func (launcher *JvmLauncher) SubmitTestRun(
288301
return testRuns, err
289302
}
290303

304+
// isCPSRemote - decide whether the config store used by tests is remote or not.
305+
// If it is remote, we are going to have to get a valid JWT to use.
306+
func (launcher *JvmLauncher) isCPSRemote() bool {
307+
isRemote := false
308+
configStoreProp := launcher.bootstrapProps["framework.config.store"]
309+
isRemote = strings.HasPrefix(configStoreProp, "galasacps")
310+
return isRemote
311+
}
312+
291313
func defaultLocalMavenIfNotSet(localMaven string, fileSystem files.FileSystem) (string, error) {
292314
var err error
293315
returnMavenPath := ""
@@ -598,6 +620,7 @@ func getCommandSyntax(
598620
isDebugEnabled bool,
599621
debugPort uint32,
600622
debugMode string,
623+
jwt string,
601624
) (string, []string, error) {
602625

603626
var cmd string = ""
@@ -685,6 +708,10 @@ func getCommandSyntax(
685708
args = append(args, "--trace")
686709
}
687710

711+
// If there is a jwt, pass it through.
712+
if jwt != "" {
713+
args = append(args, "-DGALASA_JWT="+jwt)
714+
}
688715
}
689716

690717
return cmd, args, err

pkg/launcher/jvmLauncher_test.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ var (
5050
}`
5151
)
5252

53+
const (
54+
BLANK_JWT = ""
55+
)
56+
5357
func NewMockLauncherParams() (
5458
props.JavaProperties,
5559
*utils.MockEnv,
@@ -510,6 +514,7 @@ func TestCommandIncludesTraceWhenTraceIsEnabled(t *testing.T) {
510514
"", // No Gherkin URL supplied
511515
isTraceEnabled,
512516
isDebugEnabled, debugPort, debugMode,
517+
BLANK_JWT,
513518
)
514519

515520
assert.NotNil(t, cmd)
@@ -545,7 +550,7 @@ func TestCommandDoesNotIncludeTraceWhenTraceIsDisabled(t *testing.T) {
545550
overridesFilePath,
546551
"", // No Gherkin URL supplied
547552
isTraceEnabled,
548-
isDebugEnabled, debugPort, debugMode,
553+
isDebugEnabled, debugPort, debugMode, BLANK_JWT,
549554
)
550555

551556
assert.NotNil(t, cmd)
@@ -583,6 +588,7 @@ func TestCommandSyntaxContainsJavaHomeUnixSlashes(t *testing.T) {
583588
"", // No Gherkin URL supplied
584589
isTraceEnabled,
585590
isDebugEnabled, debugPort, debugMode,
591+
BLANK_JWT,
586592
)
587593

588594
assert.NotNil(t, cmd)
@@ -622,6 +628,7 @@ func TestCommandSyntaxContainsJavaHomeWindowsSlashes(t *testing.T) {
622628
"", // No Gherkin URL supplied
623629
isTraceEnabled,
624630
isDebugEnabled, debugPort, debugMode,
631+
BLANK_JWT,
625632
)
626633

627634
assert.NotNil(t, cmd)
@@ -696,6 +703,7 @@ func TestCommandIncludesGALASA_HOMESystemProperty(t *testing.T) {
696703
isDebugEnabled,
697704
debugPort,
698705
debugMode,
706+
BLANK_JWT,
699707
)
700708

701709
assert.NotNil(t, cmd)
@@ -732,6 +740,7 @@ func TestCommandIncludesFlagsFromBootstrapProperties(t *testing.T) {
732740
"", // No Gherkin URL supplied
733741
isTraceEnabled,
734742
isDebugEnabled, debugPort, debugMode,
743+
BLANK_JWT,
735744
)
736745

737746
assert.NotNil(t, cmd)
@@ -770,6 +779,7 @@ func TestCommandIncludesTwoFlagsFromBootstrapProperties(t *testing.T) {
770779
"", // No Gherkin URL supplied
771780
isTraceEnabled,
772781
isDebugEnabled, debugPort, debugMode,
782+
BLANK_JWT,
773783
)
774784

775785
assert.NotNil(t, cmd)
@@ -808,6 +818,7 @@ func TestCommandIncludesDefaultDebugPortAndMode(t *testing.T) {
808818
"", // No Gherkin URL supplied
809819
isTraceEnabled,
810820
isDebugEnabled, debugPort, debugMode,
821+
BLANK_JWT,
811822
)
812823

813824
assert.NotNil(t, command)
@@ -847,6 +858,7 @@ func TestCommandDrawsValidDebugPortFromBootstrap(t *testing.T) {
847858
"", // No Gherkin URL supplied
848859
isTraceEnabled,
849860
isDebugEnabled, debugPort, debugMode,
861+
BLANK_JWT,
850862
)
851863

852864
assert.NotNil(t, command)
@@ -886,6 +898,7 @@ func TestCommandDrawsInvalidDebugPortFromBootstrap(t *testing.T) {
886898
"", // No Gherkin URL supplied
887899
isTraceEnabled,
888900
isDebugEnabled, debugPort, debugMode,
901+
BLANK_JWT,
889902
)
890903

891904
assert.NotNil(t, err)
@@ -925,6 +938,7 @@ func TestCommandDrawsValidDebugModeFromBootstrap(t *testing.T) {
925938
"", // No Gherkin URL supplied
926939
isTraceEnabled,
927940
isDebugEnabled, debugPort, debugMode,
941+
BLANK_JWT,
928942
)
929943

930944
assert.NotNil(t, command)
@@ -970,6 +984,7 @@ func TestCommandDrawsInvalidDebugModeFromBootstrap(t *testing.T) {
970984
"", // No Gherkin URL supplied
971985
isTraceEnabled,
972986
isDebugEnabled, debugPort, debugMode,
987+
BLANK_JWT,
973988
)
974989

975990
assert.NotNil(t, err)
@@ -1007,6 +1022,7 @@ func TestCommandDrawsValidDebugModeListenFromCommandLine(t *testing.T) {
10071022
"", // No Gherkin URL supplied
10081023
isTraceEnabled,
10091024
isDebugEnabled, debugPort, debugMode,
1025+
BLANK_JWT,
10101026
)
10111027

10121028
assert.NotNil(t, command)
@@ -1050,6 +1066,7 @@ func TestCommandDrawsValidDebugModeAttachFromCommandLine(t *testing.T) {
10501066
"", // No Gherkin URL supplied
10511067
isTraceEnabled,
10521068
isDebugEnabled, debugPort, debugMode,
1069+
BLANK_JWT,
10531070
)
10541071

10551072
assert.NotNil(t, command)
@@ -1093,6 +1110,7 @@ func TestCommandDrawsInvalidDebugModeFromCommandLine(t *testing.T) {
10931110
"", // No Gherkin URL supplied
10941111
isTraceEnabled,
10951112
isDebugEnabled, debugPort, debugMode,
1113+
BLANK_JWT,
10961114
)
10971115

10981116
assert.NotNil(t, err)
@@ -1132,6 +1150,7 @@ func TestLocalMavenNotSetDefaults(t *testing.T) {
11321150
"", // No Gherkin URL supplied
11331151
isTraceEnabled,
11341152
isDebugEnabled, debugPort, debugMode,
1153+
BLANK_JWT,
11351154
)
11361155

11371156
// Then...
@@ -1172,6 +1191,7 @@ func TestLocalMavenSet(t *testing.T) {
11721191
"", // No Gherkin URL supplied
11731192
isTraceEnabled,
11741193
isDebugEnabled, debugPort, debugMode,
1194+
BLANK_JWT,
11751195
)
11761196

11771197
// Then...
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* SPDX-License-Identifier: EPL-2.0
55
*/
6-
package auth
6+
package utils
77

88
import (
99
"encoding/json"
@@ -12,7 +12,6 @@ import (
1212
"time"
1313

1414
"github.com/galasa-dev/cli/pkg/files"
15-
"github.com/galasa-dev/cli/pkg/utils"
1615
"github.com/golang-jwt/jwt/v5"
1716

1817
galasaErrors "github.com/galasa-dev/cli/pkg/errors"
@@ -31,7 +30,7 @@ const (
3130
// {
3231
// "jwt": "<bearer-token-here>"
3332
// }
34-
func WriteBearerTokenJsonFile(fileSystem files.FileSystem, galasaHome utils.GalasaHome, jwt string) error {
33+
func WriteBearerTokenJsonFile(fileSystem files.FileSystem, galasaHome GalasaHome, jwt string) error {
3534
bearerTokenFilePath := filepath.Join(galasaHome.GetNativeFolderPath(), "bearer-token.json")
3635

3736
log.Printf("Writing bearer token to file '%s'", bearerTokenFilePath)
@@ -47,7 +46,7 @@ func WriteBearerTokenJsonFile(fileSystem files.FileSystem, galasaHome utils.Gala
4746
}
4847

4948
// Gets the JWT from the bearer-token.json file if it exists, errors if the file does not exist or if the token is invalid
50-
func GetBearerTokenFromTokenJsonFile(fileSystem files.FileSystem, galasaHome utils.GalasaHome, timeService utils.TimeService) (string, error) {
49+
func GetBearerTokenFromTokenJsonFile(fileSystem files.FileSystem, galasaHome GalasaHome, timeService TimeService) (string, error) {
5150
var err error = nil
5251
var bearerToken string = ""
5352
var bearerTokenJsonContents string = ""
@@ -81,7 +80,7 @@ func GetBearerTokenFromTokenJsonFile(fileSystem files.FileSystem, galasaHome uti
8180
}
8281

8382
// Checks whether a given bearer token is valid or not, returning true if it is valid and false otherwise
84-
func IsBearerTokenValid(bearerTokenString string, timeService utils.TimeService) bool {
83+
func IsBearerTokenValid(bearerTokenString string, timeService TimeService) bool {
8584
var err error = nil
8685
var bearerToken *jwt.Token
8786

0 commit comments

Comments
 (0)