Skip to content

Commit 0b79fa5

Browse files
authored
Merge pull request #69 from kaleido-io/apiclient
Add apiclient command line tools
2 parents fcfb473 + 14833d1 commit 0b79fa5

32 files changed

+1417
-14
lines changed

.vscode/settings.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"go.formatFlags": ["-s"],
33
"go.lintTool": "golangci-lint",
44
"cSpell.words": [
5+
"apiclient",
56
"APIID",
67
"apitypes",
78
"badurl",
@@ -54,6 +55,7 @@
5455
"leveldb",
5556
"loadbalanced",
5657
"logrus",
58+
"metricsmocks",
5759
"mtxs",
5860
"NATS",
5961
"Nowarn",
@@ -77,7 +79,6 @@
7779
"tekuri",
7880
"tmconfig",
7981
"tmmsgs",
80-
"metricsmocks",
8182
"Tracef",
8283
"txcommon",
8384
"txcommonmocks",

Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ lint: ${LINT}
2020
GOGC=20 $(LINT) run -v --timeout 5m
2121

2222
${MOCKERY}:
23-
$(VGO) install github.com/vektra/mockery/cmd/mockery@latest
23+
$(VGO) install github.com/vektra/mockery/v2@latest
2424
${LINT}:
25-
$(VGO) install github.com/golangci/golangci-lint/cmd/[email protected].0
25+
$(VGO) install github.com/golangci/golangci-lint/cmd/[email protected].3
2626

2727

2828
define makemock
@@ -42,6 +42,7 @@ $(eval $(call makemock, internal/persistence, TransactionPersistence, persiste
4242
$(eval $(call makemock, internal/ws, WebSocketChannels, wsmocks))
4343
$(eval $(call makemock, internal/ws, WebSocketServer, wsmocks))
4444
$(eval $(call makemock, internal/events, Stream, eventsmocks))
45+
$(eval $(call makemock, internal/apiclient, FFTMClient, apiclientmocks))
4546

4647
go-mod-tidy: .ALWAYS
4748
$(VGO) mod tidy

cmd/client.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright © 2023 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package cmd
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
"github.com/hyperledger/firefly-common/pkg/config"
24+
"github.com/hyperledger/firefly-common/pkg/httpserver"
25+
"github.com/hyperledger/firefly-transaction-manager/internal/apiclient"
26+
"github.com/hyperledger/firefly-transaction-manager/internal/tmconfig"
27+
"github.com/spf13/cobra"
28+
)
29+
30+
var url string
31+
var nameRegex string
32+
var ignoreNotFound bool
33+
34+
func ClientCommand() *cobra.Command {
35+
return buildClientCommand(createClient)
36+
}
37+
38+
func buildClientCommand(clientFactory func() apiclient.FFTMClient) *cobra.Command {
39+
clientCmd := &cobra.Command{
40+
Use: "client <subcommand>",
41+
Short: "Make API requests to a blockchain connector instance",
42+
}
43+
defaultURL := fmt.Sprintf("http://%s:%s", tmconfig.APIConfig.GetString(httpserver.HTTPConfAddress), tmconfig.APIConfig.GetString(httpserver.HTTPConfPort))
44+
45+
clientCmd.PersistentFlags().BoolVarP(&ignoreNotFound, "ignore-not-found", "", false, "Does not return an error if the resource is not found. Useful for idempotent delete functions.")
46+
clientCmd.PersistentFlags().StringVarP(&url, "url", "", defaultURL, "The URL of the blockchain connector")
47+
48+
clientCmd.AddCommand(clientEventStreamsCommand(clientFactory))
49+
clientCmd.AddCommand(clientListenersCommand(clientFactory))
50+
51+
return clientCmd
52+
}
53+
54+
func createClient() apiclient.FFTMClient {
55+
cfg := config.RootSection("fftm_client")
56+
apiclient.InitConfig(cfg)
57+
if url != "" {
58+
cfg.Set("url", url)
59+
}
60+
return apiclient.NewFFTMClient(context.Background(), cfg)
61+
}
62+
63+
func init() {
64+
tmconfig.Reset()
65+
}

cmd/client_eventstreams.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright © 2023 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package cmd
18+
19+
import (
20+
"github.com/hyperledger/firefly-transaction-manager/internal/apiclient"
21+
"github.com/spf13/cobra"
22+
)
23+
24+
var eventStreamID string
25+
26+
func clientEventStreamsCommand(clientFactory func() apiclient.FFTMClient) *cobra.Command {
27+
clientEventStreamsCmd := &cobra.Command{
28+
Use: "eventstreams <subcommand>",
29+
Short: "Make API requests to an blockchain connector instance",
30+
}
31+
clientEventStreamsCmd.AddCommand(clientEventStreamsListCommand(clientFactory))
32+
clientEventStreamsCmd.AddCommand(clientEventStreamsDeleteCommand(clientFactory))
33+
return clientEventStreamsCmd
34+
}

cmd/client_eventstreams_delete.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright © 2023 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package cmd
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"strings"
23+
24+
"github.com/hyperledger/firefly-transaction-manager/internal/apiclient"
25+
"github.com/spf13/cobra"
26+
)
27+
28+
func clientEventStreamsDeleteCommand(clientFactory func() apiclient.FFTMClient) *cobra.Command {
29+
clientEventStreamsDeleteCmd := &cobra.Command{
30+
Use: "delete",
31+
Short: "Delete event streams",
32+
Long: "",
33+
RunE: func(cmd *cobra.Command, args []string) error {
34+
client := clientFactory()
35+
if eventStreamID == "" && nameRegex == "" {
36+
return fmt.Errorf("eventstream or name flag must be set")
37+
}
38+
if eventStreamID != "" && nameRegex != "" {
39+
return fmt.Errorf("eventstream and name flags cannot be combined")
40+
}
41+
if eventStreamID != "" {
42+
err := client.DeleteEventStream(context.Background(), eventStreamID)
43+
if err != nil {
44+
if !(strings.Contains(err.Error(), "FF21046") && ignoreNotFound) {
45+
return err
46+
}
47+
}
48+
}
49+
if nameRegex != "" {
50+
err := client.DeleteEventStreamsByName(context.Background(), nameRegex)
51+
if err != nil {
52+
return err
53+
}
54+
}
55+
return nil
56+
},
57+
}
58+
clientEventStreamsDeleteCmd.Flags().StringVarP(&eventStreamID, "eventstream", "", "", "The ID of the event stream")
59+
clientEventStreamsDeleteCmd.Flags().StringVarP(&nameRegex, "name", "", "", "A regular expression for matching the event stream name")
60+
return clientEventStreamsDeleteCmd
61+
}
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright © 2023 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package cmd
18+
19+
import (
20+
"fmt"
21+
"testing"
22+
23+
"github.com/hyperledger/firefly-transaction-manager/internal/apiclient"
24+
"github.com/hyperledger/firefly-transaction-manager/mocks/apiclientmocks"
25+
"github.com/stretchr/testify/assert"
26+
"github.com/stretchr/testify/mock"
27+
)
28+
29+
func TestEventStreamsDeleteByID(t *testing.T) {
30+
mc := apiclientmocks.NewFFTMClient(t)
31+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
32+
cmd.SetArgs([]string{"eventstreams", "delete", "--eventstream", "f9506df2-5473-4fd4-9cfb-f835656eaaa7"})
33+
mc.On("DeleteEventStream", mock.Anything, "f9506df2-5473-4fd4-9cfb-f835656eaaa7").Return(nil)
34+
err := cmd.Execute()
35+
assert.NoError(t, err)
36+
mc.AssertExpectations(t)
37+
}
38+
39+
func TestEventStreamsDeleteByName(t *testing.T) {
40+
mc := apiclientmocks.NewFFTMClient(t)
41+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
42+
cmd.SetArgs([]string{"eventstreams", "delete", "--name", "foo"})
43+
mc.On("DeleteEventStreamsByName", mock.Anything, "foo").Return(nil)
44+
err := cmd.Execute()
45+
assert.NoError(t, err)
46+
mc.AssertExpectations(t)
47+
}
48+
49+
func TestEventStreamsDeleteNoID(t *testing.T) {
50+
mc := apiclientmocks.NewFFTMClient(t)
51+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
52+
cmd.SetArgs([]string{"eventstreams", "delete"})
53+
err := cmd.Execute()
54+
assert.Regexp(t, "eventstream or name flag must be set", err)
55+
}
56+
57+
func TestEventStreamsDeleteIDandName(t *testing.T) {
58+
mc := apiclientmocks.NewFFTMClient(t)
59+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
60+
cmd.SetArgs([]string{"eventstreams", "delete", "--eventstream", "f9506df2-5473-4fd4-9cfb-f835656eaaa7", "--name", "foo"})
61+
err := cmd.Execute()
62+
assert.Regexp(t, "eventstream and name flags cannot be combined", err)
63+
}
64+
65+
func TestEventStreamsDeleteByNameError(t *testing.T) {
66+
mc := apiclientmocks.NewFFTMClient(t)
67+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
68+
cmd.SetArgs([]string{"eventstreams", "delete", "--name", "foo"})
69+
mc.On("DeleteEventStreamsByName", mock.Anything, "foo").Return(fmt.Errorf("pop"))
70+
err := cmd.Execute()
71+
assert.Regexp(t, "pop", err)
72+
mc.AssertExpectations(t)
73+
}
74+
75+
func TestEventStreamsDeleteByIDError(t *testing.T) {
76+
mc := apiclientmocks.NewFFTMClient(t)
77+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
78+
cmd.SetArgs([]string{"eventstreams", "delete", "--eventstream", "f9506df2-5473-4fd4-9cfb-f835656eaaa7"})
79+
mc.On("DeleteEventStream", mock.Anything, "f9506df2-5473-4fd4-9cfb-f835656eaaa7").Return(fmt.Errorf("pop"))
80+
err := cmd.Execute()
81+
assert.Regexp(t, "pop", err)
82+
mc.AssertExpectations(t)
83+
}

cmd/client_eventstreams_list.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright © 2023 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package cmd
18+
19+
import (
20+
"context"
21+
"encoding/json"
22+
"fmt"
23+
24+
"github.com/hyperledger/firefly-transaction-manager/internal/apiclient"
25+
"github.com/spf13/cobra"
26+
)
27+
28+
func clientEventStreamsListCommand(clientFactory func() apiclient.FFTMClient) *cobra.Command {
29+
clientEventStreamsListCmd := &cobra.Command{
30+
Use: "list",
31+
Short: "List event streams",
32+
Long: "",
33+
RunE: func(cmd *cobra.Command, args []string) error {
34+
client := clientFactory()
35+
eventStreams, err := client.GetEventStreams(context.Background())
36+
if err != nil {
37+
return err
38+
}
39+
json, _ := json.MarshalIndent(eventStreams, "", " ")
40+
fmt.Println(string(json))
41+
return nil
42+
},
43+
}
44+
return clientEventStreamsListCmd
45+
}

cmd/client_eventstreams_list_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright © 2023 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package cmd
18+
19+
import (
20+
"fmt"
21+
"testing"
22+
23+
"github.com/hyperledger/firefly-transaction-manager/internal/apiclient"
24+
"github.com/hyperledger/firefly-transaction-manager/mocks/apiclientmocks"
25+
"github.com/hyperledger/firefly-transaction-manager/pkg/apitypes"
26+
"github.com/stretchr/testify/assert"
27+
"github.com/stretchr/testify/mock"
28+
)
29+
30+
func TestEventStreamsList(t *testing.T) {
31+
mc := apiclientmocks.NewFFTMClient(t)
32+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
33+
cmd.SetArgs([]string{"eventstreams", "list"})
34+
mc.On("GetEventStreams", mock.Anything).Return([]apitypes.EventStream{}, nil)
35+
err := cmd.Execute()
36+
assert.NoError(t, err)
37+
mc.AssertExpectations(t)
38+
}
39+
40+
func TestEventStreamsListError(t *testing.T) {
41+
mc := apiclientmocks.NewFFTMClient(t)
42+
cmd := buildClientCommand(func() apiclient.FFTMClient { return mc })
43+
cmd.SetArgs([]string{"eventstreams", "list"})
44+
mc.On("GetEventStreams", mock.Anything).Return(nil, fmt.Errorf("pop"))
45+
err := cmd.Execute()
46+
assert.Regexp(t, "pop", err)
47+
mc.AssertExpectations(t)
48+
}

0 commit comments

Comments
 (0)