Skip to content

Commit 8cb3b5a

Browse files
authored
Merge pull request #538 from kosli-dev/3845-doublehost-to-multiple-entries
Extend CLI doublehost trick to support multiple entries
2 parents 5fe91a4 + 1278ecb commit 8cb3b5a

3 files changed

Lines changed: 114 additions & 65 deletions

File tree

cmd/kosli/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ func init() {
2424

2525
func main() {
2626
var err error
27-
if isDoubledHost() {
27+
if isMultiHost() {
2828
var output string
29-
output, err = runDoubledHost(os.Args)
29+
output, err = runMultiHost(os.Args)
3030
fmt.Print(output)
3131
} else {
3232
var cmd *cobra.Command
Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,18 @@ import (
2727
"github.com/spf13/cobra"
2828
)
2929

30-
func isDoubledHost() bool {
31-
// Returns true iff the CLI execution is doubled-host, doubled-api-token
32-
opts := getDoubledOpts()
33-
return len(opts.hosts) == 2 && len(opts.apiTokens) == 2
30+
func isMultiHost() bool {
31+
// Returns true iff the CLI execution is multi-host, multi-api-token
32+
opts := getMultiOpts()
33+
return len(opts.hosts) > 1 && len(opts.apiTokens) > 1 && len(opts.hosts) == len(opts.apiTokens)
3434
}
3535

36-
func runDoubledHost(args []string) (string, error) {
37-
// Calls "innerMain" twice:
36+
func runMultiHost(args []string) (string, error) {
37+
// Calls "innerMain" at least twice:
3838
// - with the 0th host/api-token (primary)
39-
// - with the 1st host/api-token (subsidiary)
39+
// - with the n-th host/api-token (subsidiary)
4040

41-
opts := getDoubledOpts()
41+
opts := getMultiOpts()
4242

4343
argsAppendHostApiTokenFlags := func(n int) []string {
4444
// Return args appended with the [n]th host/api-token.
@@ -52,26 +52,30 @@ func runDoubledHost(args []string) (string, error) {
5252
args0 := argsAppendHostApiTokenFlags(0)
5353
output0, err0 := runBufferedInnerMain(args0)
5454

55-
args1 := argsAppendHostApiTokenFlags(1)
56-
output1, err1 := runBufferedInnerMain(args1)
57-
58-
// Return subsidiary-call's output in debug mode only.
5955
stdOut := output0
60-
if opts.debug && output1 != "" {
61-
stdOut += fmt.Sprintf("\n[debug] [%s]", opts.hosts[1])
62-
stdOut += fmt.Sprintf("\n%s", output1)
63-
}
64-
65-
// Make origin of subsidiary-call failure clear.
6656
var errorMessage string
57+
6758
if err0 != nil {
6859
errorMessage += err0.Error()
6960
}
70-
if err1 != nil {
71-
errorMessage += fmt.Sprintf("\n[%s]", opts.hosts[1])
72-
errorMessage += fmt.Sprintf("\n%s", err1.Error())
73-
}
7461

62+
for i:=1; i < len(opts.hosts); i++ {
63+
argsN := argsAppendHostApiTokenFlags(i)
64+
outputN, errN := runBufferedInnerMain(argsN)
65+
66+
// Return subsidiary-call's output in debug mode only.
67+
if opts.debug && outputN != "" {
68+
stdOut += fmt.Sprintf("\n[debug] [%s]", opts.hosts[i])
69+
stdOut += fmt.Sprintf("\n%s", outputN)
70+
}
71+
72+
// Make origin of subsidiary-call failure clear.
73+
if errN != nil {
74+
errorMessage += fmt.Sprintf("\n[%s]", opts.hosts[i])
75+
errorMessage += fmt.Sprintf("\n%s", errN.Error())
76+
}
77+
}
78+
7579
var err error
7680
if errorMessage != "" {
7781
err = errors.New(errorMessage)
@@ -113,21 +117,21 @@ func runBufferedInnerMain(args []string) (string, error) {
113117
return fmt.Sprint(&buffer), err
114118
}
115119

116-
type DoubledOpts struct {
120+
type MultiOpts struct {
117121
hosts []string
118122
apiTokens []string
119123
debug bool
120124
}
121125

122-
func getDoubledOpts() DoubledOpts {
123-
// Return a DoubledOpts struct with:
126+
func getMultiOpts() MultiOpts {
127+
// Return a MultiOpts struct with:
124128
// - hosts set to H, split on comma, where H is the normal value of KOSLI_HOST/--host
125129
// - apiTokens set to A, split on comma, where A is the normal value of KOSLI_API_TOKEN/--api-token
126130
//
127-
// For any error, return DoubleOpts{} which will have
131+
// For any error, return MultiOpts{} which will have
128132
// - hosts == nil, so len(hosts) == 0
129133
// - apiTokens == nil, so len(apiTokens) == 0
130-
// so isDoubledHost() will return false.
134+
// so isMultiHost() will return false.
131135

132136
// There is a logger.Error(..) call at the end of main. Restore it to
133137
// the original global logger so the error messages actually appear.
@@ -142,7 +146,7 @@ func getDoubledOpts() DoubledOpts {
142146
// Create a cmd object. Note: newRootCmd(out, args) does _not_ use its args parameter.
143147
cmd, err := newRootCmd(logger.Out, logger.ErrOut, nil)
144148
if err != nil {
145-
return DoubledOpts{}
149+
return MultiOpts{}
146150
}
147151

148152
// Ensure cmd.Execute() prints nothing, even for a [kosli] call
@@ -170,10 +174,10 @@ func getDoubledOpts() DoubledOpts {
170174
// Genuine error
171175
// Eg kosli unknownCommand ...
172176
// Eg kosli status --unknown-flag
173-
return DoubledOpts{}
177+
return MultiOpts{}
174178
}
175179

176-
return DoubledOpts{
180+
return MultiOpts{
177181
hosts: strings.Split(global.Host, ","),
178182
apiTokens: strings.Split(global.ApiToken, ","),
179183
debug: global.Debug,
Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ import (
1010
"github.com/stretchr/testify/suite"
1111
)
1212

13-
type DoubledHostTestSuite struct {
13+
type MultiHostTestSuite struct {
1414
suite.Suite
1515
}
1616

1717
const localHost = "http://localhost:8001"
1818
const apiToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
1919
const orgName = "docs-cmd-test-user"
2020

21-
func (suite *DoubledHostTestSuite) TestIsDoubledHost() {
21+
func (suite *MultiHostTestSuite) TestIsMultiHost() {
2222

2323
for _, t := range []struct {
2424
name string
@@ -35,28 +35,35 @@ func (suite *DoubledHostTestSuite) TestIsDoubledHost() {
3535
want: true,
3636
},
3737
{
38-
name: "False when one host",
38+
name: "True when three hosts and three api-tokens",
39+
args: []string{"status"},
40+
host: fmt.Sprintf("%s,%s,%s", localHost, localHost, localHost),
41+
apiToken: fmt.Sprintf("%s,%s,%s", apiToken, apiToken, apiToken),
42+
want: true,
43+
},
44+
{
45+
name: "False when one host and two api-tokens",
3946
args: []string{"status"},
4047
host: localHost,
4148
apiToken: fmt.Sprintf("%s,%s", apiToken, apiToken),
4249
want: false,
4350
},
4451
{
45-
name: "False when three hosts",
52+
name: "False when three hosts and two api-tokens",
4653
args: []string{"status"},
4754
host: fmt.Sprintf("%s,%s,%s", localHost, localHost, localHost),
4855
apiToken: fmt.Sprintf("%s,%s", apiToken, apiToken),
4956
want: false,
5057
},
5158
{
52-
name: "False when one api-token",
59+
name: "False when one api-token and two hostnames",
5360
args: []string{"status"},
5461
host: fmt.Sprintf("%s,%s", localHost, localHost),
5562
apiToken: apiToken,
5663
want: false,
5764
},
5865
{
59-
name: "False when three api-tokens",
66+
name: "False when three api-tokens and two hostnames",
6067
args: []string{"status"},
6168
host: fmt.Sprintf("%s,%s", localHost, localHost),
6269
apiToken: fmt.Sprintf("%s,%s,%s", apiToken, apiToken, apiToken),
@@ -85,21 +92,21 @@ func (suite *DoubledHostTestSuite) TestIsDoubledHost() {
8592

8693
defer func(original []string) { os.Args = original }(os.Args)
8794
os.Args = args
88-
actual := isDoubledHost()
95+
actual := isMultiHost()
8996

90-
assert.Equal(suite.Suite.T(), t.want, actual, fmt.Sprintf("TestIsDoubledHost: %s\n\texpected: '%v'\n\t--actual: '%v'\n", t.name, t.want, actual))
97+
assert.Equal(suite.Suite.T(), t.want, actual, fmt.Sprintf("TestIsMultiHost: %s\n\texpected: '%v'\n\t--actual: '%v'\n", t.name, t.want, actual))
9198
})
9299
}
93100
}
94101

95-
func (suite *DoubledHostTestSuite) TestRunDoubledHost() {
102+
func (suite *MultiHostTestSuite) TestRunDoubledHost() {
96103

97-
doubledHost := fmt.Sprintf("--host=%s,%s", localHost, localHost)
104+
MultiHost := fmt.Sprintf("--host=%s,%s", localHost, localHost)
98105
doubledApiToken := fmt.Sprintf("--api-token=%s,%s", apiToken, apiToken)
99106
org := fmt.Sprintf("--org=%s", orgName)
100107

101108
doubledArgs := func(args []string) []string {
102-
return append(args, doubledHost, doubledApiToken, org)
109+
return append(args, MultiHost, doubledApiToken, org)
103110
}
104111

105112
for _, t := range []struct {
@@ -109,33 +116,16 @@ func (suite *DoubledHostTestSuite) TestRunDoubledHost() {
109116
err error
110117
}{
111118
{
112-
name: "only returns primary call output when both calls succeed",
119+
name: "only returns primary call output when both (2) calls succeed",
113120
args: doubledArgs([]string{"kosli", "status"}),
114121
stdOut: []string{"OK", ""},
115122
err: error(nil),
116123
},
117-
// {
118-
// name: "in debug mode also returns secondary call output",
119-
// args: doubledArgs([]string{"kosli", "status", "--debug"}),
120-
// stdOut: StatusDebugLines(),
121-
// err: error(nil),
122-
// },
123-
// {
124-
// name: "--help prints output once",
125-
// args: doubledArgs([]string{"kosli", "status", "--help"}),
126-
// stdOut: HelpStatusLines(),
127-
// err: error(nil),
128-
// },
129-
// {
130-
// name: "bad-flag never gets to call runDoubledHost() because isDoubledHost() returns false",
131-
// args: doubledArgs([]string{"kosli", "status", "--bad-flag"}),
132-
// stdOut: BadFlagLines(),
133-
// err: error(nil),
134-
// },
124+
135125
} {
136126
defer func(original []string) { os.Args = original }(os.Args)
137127
os.Args = t.args
138-
output, err := runDoubledHost(t.args)
128+
output, err := runMultiHost(t.args)
139129

140130
assert.Equal(suite.Suite.T(), t.err, err, fmt.Sprintf("TestRunDoubleHost: %s\n\texpected: '%v'\n\t--actual: '%v'\n", t.name, t.err, err))
141131

@@ -145,8 +135,44 @@ func (suite *DoubledHostTestSuite) TestRunDoubledHost() {
145135
}
146136
}
147137

148-
func TestDoubledHostTestSuite(t *testing.T) {
149-
suite.Run(t, new(DoubledHostTestSuite))
138+
func (suite *MultiHostTestSuite) TestRunTripledHost() {
139+
140+
multiHost := fmt.Sprintf("--host=%s,%s,%s", localHost, localHost, localHost)
141+
multiApiToken := fmt.Sprintf("--api-token=%s,%s,%s", apiToken, apiToken, apiToken)
142+
org := fmt.Sprintf("--org=%s", orgName)
143+
144+
tripledArgs := func(args []string) []string {
145+
return append(args, multiHost, multiApiToken, org)
146+
}
147+
148+
for _, t := range []struct {
149+
name string
150+
args []string
151+
stdOut []string
152+
err error
153+
}{
154+
{
155+
name: "only returns primary call output when all three calls succeed",
156+
args: tripledArgs([]string{"kosli", "status"}),
157+
stdOut: []string{"OK", ""},
158+
err: error(nil),
159+
},
160+
161+
} {
162+
defer func(original []string) { os.Args = original }(os.Args)
163+
os.Args = t.args
164+
output, err := runMultiHost(t.args)
165+
166+
assert.Equal(suite.Suite.T(), t.err, err, fmt.Sprintf("TestRunTripledHost: %s\n\texpected: '%v'\n\t--actual: '%v'\n", t.name, t.err, err))
167+
168+
lines := strings.Split(output, "\n")
169+
d := diff(t.stdOut, lines)
170+
assert.Equal(suite.Suite.T(), "", d, fmt.Sprintf("TestRunTripledHost: %s\n%s\n", t.name, d))
171+
}
172+
}
173+
174+
func TestMultiHostTestSuite(t *testing.T) {
175+
suite.Run(t, new(MultiHostTestSuite))
150176
}
151177

152178
// func StatusDebugLines() []string {
@@ -234,3 +260,22 @@ func charAt(s string, n int) string {
234260
}
235261
return fmt.Sprintf("%v", c)
236262
}
263+
264+
// {
265+
// name: "in debug mode also returns secondary call output",
266+
// args: doubledArgs([]string{"kosli", "status", "--debug"}),
267+
// stdOut: StatusDebugLines(),
268+
// err: error(nil),
269+
// },
270+
// {
271+
// name: "--help prints output once",
272+
// args: doubledArgs([]string{"kosli", "status", "--help"}),
273+
// stdOut: HelpStatusLines(),
274+
// err: error(nil),
275+
// },
276+
// {
277+
// name: "bad-flag never gets to call runMultiHost() because isMultiHost() returns false",
278+
// args: doubledArgs([]string{"kosli", "status", "--bad-flag"}),
279+
// stdOut: BadFlagLines(),
280+
// err: error(nil),
281+
// },

0 commit comments

Comments
 (0)