mirror of https://github.com/dapr/cli.git
Add UTs for publish and invoke (#477)
* Refactor publish, invoke and add tests * remove process from interface * address review comments * rename invoke methods.
This commit is contained in:
parent
24ca35d78b
commit
e2e592943f
|
@ -6,10 +6,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/dapr/cli/pkg/invoke"
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -24,16 +22,11 @@ var InvokeCmd = &cobra.Command{
|
|||
Use: "invoke",
|
||||
Short: "Invokes a Dapr app with an optional payload (deprecated, use invokePost)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
response, err := invoke.Post(invokeAppID, invokeAppMethod, invokePayload)
|
||||
err := invokePost(invokeAppID, invokeAppMethod, invokePayload)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stdout, fmt.Sprintf("Error invoking app %s: %s", invokeAppID, err))
|
||||
return
|
||||
// exit with error
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if response != "" {
|
||||
fmt.Println(response)
|
||||
}
|
||||
|
||||
print.SuccessStatusEvent(os.Stdout, "App invoked successfully")
|
||||
},
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/dapr/cli/pkg/invoke"
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -14,11 +14,12 @@ var invokeGetCmd = &cobra.Command{
|
|||
Use: "invokeGet",
|
||||
Short: "Issue HTTP GET to Dapr app",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
response, err := invoke.Get(invokeAppID, invokeAppMethod)
|
||||
client := standalone.NewClient()
|
||||
response, err := client.InvokeGet(invokeAppID, invokeAppMethod)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stdout, fmt.Sprintf("Error invoking app %s: %s", invokeAppID, err))
|
||||
|
||||
return
|
||||
print.FailureStatusEvent(os.Stdout, fmt.Sprintf("error invoking app %s: %s", invokeAppID, err))
|
||||
// exit with error
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if response != "" {
|
||||
|
|
|
@ -9,8 +9,8 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/dapr/cli/pkg/invoke"
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -18,21 +18,30 @@ var invokePostCmd = &cobra.Command{
|
|||
Use: "invokePost",
|
||||
Short: "Issue HTTP POST to Dapr app with an optional payload",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
response, err := invoke.Post(invokeAppID, invokeAppMethod, invokePayload)
|
||||
err := invokePost(invokeAppID, invokeAppMethod, invokePayload)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stdout, fmt.Sprintf("Error invoking app %s: %s", invokeAppID, err))
|
||||
|
||||
return
|
||||
// exit with error
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if response != "" {
|
||||
fmt.Println(response)
|
||||
}
|
||||
|
||||
print.SuccessStatusEvent(os.Stdout, fmt.Sprintf("HTTP Post to method %s invoked successfully", invokeAppMethod))
|
||||
},
|
||||
}
|
||||
|
||||
func invokePost(invokeAppID, invokeAppMethod, invokePayload string) error {
|
||||
client := standalone.NewClient()
|
||||
response, err := client.InvokePost(invokeAppID, invokeAppMethod, invokePayload)
|
||||
if err != nil {
|
||||
er := fmt.Errorf("error invoking app %s: %s", invokeAppID, err)
|
||||
print.FailureStatusEvent(os.Stdout, er.Error())
|
||||
return er
|
||||
}
|
||||
|
||||
if response != "" {
|
||||
fmt.Println(response)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
invokePostCmd.Flags().StringVarP(&invokeAppID, "app-id", "a", "", "the app id to invoke")
|
||||
invokePostCmd.Flags().StringVarP(&invokeAppMethod, "method", "m", "", "the method to invoke")
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/dapr/cli/pkg/print"
|
||||
"github.com/dapr/cli/pkg/publish"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -24,10 +24,11 @@ var PublishCmd = &cobra.Command{
|
|||
Use: "publish",
|
||||
Short: "Publish an event to multiple consumers",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := publish.SendPayloadToTopic(publishTopic, publishPayload, pubsubName)
|
||||
client := standalone.NewClient()
|
||||
err := client.Publish(publishTopic, publishPayload, pubsubName)
|
||||
if err != nil {
|
||||
print.FailureStatusEvent(os.Stdout, fmt.Sprintf("Error publishing topic %s: %s", publishTopic, err))
|
||||
return
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
print.SuccessStatusEvent(os.Stdout, "Event published successfully")
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/dapr/cli/pkg/api"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMakeMetadataGetEndpoint(t *testing.T) {
|
||||
actual := makeMetadataGetEndpoint(9999)
|
||||
assert.Equal(t, fmt.Sprintf("http://127.0.0.1:9999/v%s/metadata", api.RuntimeAPIVersion), actual, "expected strings to match")
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package standalone
|
||||
|
||||
type DaprProcess interface {
|
||||
List() ([]ListOutput, error)
|
||||
}
|
||||
|
||||
type daprProcess struct {
|
||||
}
|
||||
|
||||
// Client is the interface the wraps all the methods exposed by the Dapr CLI.
|
||||
type Client interface {
|
||||
// InvokeGet is used to invoke a method on a Dapr application with GET verb.
|
||||
InvokeGet(appID, method string) (string, error)
|
||||
// InvokePost is used to invoke a method on a Dapr application with POST verb.
|
||||
InvokePost(appID, method, payload string) (string, error)
|
||||
// Publish is used to publish event to a topic in a pubsub.
|
||||
Publish(topic, payload, pubsubName string) error
|
||||
}
|
||||
|
||||
type Standalone struct {
|
||||
process DaprProcess
|
||||
}
|
||||
|
||||
func NewClient() Client {
|
||||
return &Standalone{process: &daprProcess{}}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package invoke
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -12,12 +12,11 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/dapr/cli/pkg/api"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
)
|
||||
|
||||
// Get invokes the application via HTTP GET.
|
||||
func Get(appID, method string) (string, error) {
|
||||
list, err := standalone.List()
|
||||
// InvokeGet invokes the application via HTTP GET.
|
||||
func (s *Standalone) InvokeGet(appID, method string) (string, error) {
|
||||
list, err := s.process.List()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -38,9 +37,9 @@ func Get(appID, method string) (string, error) {
|
|||
return "", fmt.Errorf("app ID %s not found", appID)
|
||||
}
|
||||
|
||||
// Post invokes the application via HTTP POST.
|
||||
func Post(appID, method, payload string) (string, error) {
|
||||
list, err := standalone.List()
|
||||
// InvokePost invokes the application via HTTP POST.
|
||||
func (s *Standalone) InvokePost(appID, method, payload string) (string, error) {
|
||||
list, err := s.process.List()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -62,7 +61,7 @@ func Post(appID, method, payload string) (string, error) {
|
|||
return "", fmt.Errorf("app ID %s not found", appID)
|
||||
}
|
||||
|
||||
func makeEndpoint(lo standalone.ListOutput, method string) string {
|
||||
func makeEndpoint(lo ListOutput, method string) string {
|
||||
return fmt.Sprintf("http://127.0.0.1:%s/v%s/invoke/%s/method/%s", fmt.Sprintf("%v", lo.HTTPPort), api.RuntimeAPIVersion, lo.AppID, method)
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInvoke(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
errorExpected bool
|
||||
errString string
|
||||
appID string
|
||||
method string
|
||||
lo ListOutput
|
||||
listErr error
|
||||
expectedPath string
|
||||
postResponse string
|
||||
resp string
|
||||
}{
|
||||
{
|
||||
name: "list apps error",
|
||||
errorExpected: true,
|
||||
errString: assert.AnError.Error(),
|
||||
listErr: assert.AnError,
|
||||
},
|
||||
{
|
||||
name: "appID not found",
|
||||
errorExpected: true,
|
||||
appID: "invalid",
|
||||
errString: "app ID invalid not found",
|
||||
lo: ListOutput{
|
||||
AppID: "testapp",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "appID found successful invoke empty response",
|
||||
appID: "testapp",
|
||||
method: "test",
|
||||
lo: ListOutput{
|
||||
AppID: "testapp",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "appID found successful invoke",
|
||||
appID: "testapp",
|
||||
method: "test",
|
||||
lo: ListOutput{
|
||||
AppID: "testapp",
|
||||
},
|
||||
expectedPath: "/v1.0/invoke/testapp/method/test",
|
||||
postResponse: "test payload",
|
||||
resp: "successful invoke",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name+" get", func(t *testing.T) {
|
||||
ts, port := getTestServer(tc.expectedPath, tc.resp)
|
||||
ts.Start()
|
||||
defer ts.Close()
|
||||
tc.lo.HTTPPort = port
|
||||
client := &Standalone{
|
||||
process: &mockDaprProcess{
|
||||
Lo: []ListOutput{
|
||||
tc.lo,
|
||||
},
|
||||
Err: tc.listErr,
|
||||
},
|
||||
}
|
||||
res, err := client.InvokeGet(tc.appID, tc.method)
|
||||
if tc.errorExpected {
|
||||
assert.Error(t, err, "expected an error")
|
||||
assert.Equal(t, tc.errString, err.Error(), "expected error strings to match")
|
||||
} else {
|
||||
assert.NoError(t, err, "expected no error")
|
||||
assert.Equal(t, tc.resp, res, "expected response to match")
|
||||
}
|
||||
})
|
||||
t.Run(tc.name+" post", func(t *testing.T) {
|
||||
ts, port := getTestServer(tc.expectedPath, tc.resp)
|
||||
ts.Start()
|
||||
defer ts.Close()
|
||||
tc.lo.HTTPPort = port
|
||||
client := &Standalone{
|
||||
process: &mockDaprProcess{
|
||||
Lo: []ListOutput{tc.lo},
|
||||
Err: tc.listErr,
|
||||
},
|
||||
}
|
||||
res, err := client.InvokePost(tc.appID, tc.method, "test payload")
|
||||
if tc.errorExpected {
|
||||
assert.Error(t, err, "expected an error")
|
||||
assert.Equal(t, tc.errString, err.Error(), "expected error strings to match")
|
||||
} else {
|
||||
assert.NoError(t, err, "expected no error")
|
||||
assert.Equal(t, tc.postResponse, res, "expected response to match")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -41,6 +41,10 @@ type runData struct {
|
|||
appCmd string
|
||||
}
|
||||
|
||||
func (d *daprProcess) List() ([]ListOutput, error) {
|
||||
return List()
|
||||
}
|
||||
|
||||
// List outputs all the applications.
|
||||
func List() ([]ListOutput, error) {
|
||||
list := []ListOutput{}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package publish
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -12,11 +12,10 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/dapr/cli/pkg/api"
|
||||
"github.com/dapr/cli/pkg/standalone"
|
||||
)
|
||||
|
||||
// SendPayloadToTopic publishes the topic.
|
||||
func SendPayloadToTopic(topic, payload, pubsubName string) error {
|
||||
// Publish publishes payload to topic in pubsub referenced by pubsubName.
|
||||
func (s *Standalone) Publish(topic, payload, pubsubName string) error {
|
||||
if topic == "" {
|
||||
return errors.New("topic is missing")
|
||||
}
|
||||
|
@ -24,7 +23,7 @@ func SendPayloadToTopic(topic, payload, pubsubName string) error {
|
|||
return errors.New("pubsubName is missing")
|
||||
}
|
||||
|
||||
l, err := standalone.List()
|
||||
l, err := s.process.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -43,19 +42,18 @@ func SendPayloadToTopic(topic, payload, pubsubName string) error {
|
|||
url := fmt.Sprintf("http://localhost:%s/v%s/publish/%s/%s", fmt.Sprintf("%v", daprHTTPPort), api.RuntimeAPIVersion, pubsubName, topic)
|
||||
// nolint: gosec
|
||||
r, err := http.Post(url, "application/json", bytes.NewBuffer(b))
|
||||
|
||||
if r != nil {
|
||||
defer r.Body.Close()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected status code %d on publishing to %s in %s", r.StatusCode, topic, pubsubName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDaprHTTPPort(list []standalone.ListOutput) (int, error) {
|
||||
func getDaprHTTPPort(list []ListOutput) (int, error) {
|
||||
for i := 0; i < len(list); i++ {
|
||||
if list[i].AppID != "" {
|
||||
return list[i].HTTPPort, nil
|
|
@ -0,0 +1,96 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPublish(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
pubsubName string
|
||||
payload string
|
||||
topic string
|
||||
lo ListOutput
|
||||
listErr error
|
||||
expectedPath string
|
||||
postResponse string
|
||||
resp string
|
||||
errorExpected bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "test empty topic",
|
||||
payload: "test",
|
||||
pubsubName: "test",
|
||||
errString: "topic is missing",
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "test empty pubsubName",
|
||||
payload: "test",
|
||||
topic: "test",
|
||||
errString: "pubsubName is missing",
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "test list error",
|
||||
payload: "test",
|
||||
topic: "test",
|
||||
pubsubName: "test",
|
||||
listErr: assert.AnError,
|
||||
errString: assert.AnError.Error(),
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "test empty appID in list output",
|
||||
payload: "test",
|
||||
topic: "test",
|
||||
pubsubName: "test",
|
||||
lo: ListOutput{
|
||||
// empty appID
|
||||
Command: "test",
|
||||
},
|
||||
errString: "couldn't find a running Dapr instance",
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "successful call",
|
||||
pubsubName: "testPubsubName",
|
||||
topic: "testTopic",
|
||||
payload: "test payload",
|
||||
expectedPath: "/v1.0/publish/testPubsubName/testTopic",
|
||||
postResponse: "test payload",
|
||||
lo: ListOutput{
|
||||
AppID: "notempty",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ts, port := getTestServer(tc.expectedPath, tc.resp)
|
||||
ts.Start()
|
||||
defer ts.Close()
|
||||
tc.lo.HTTPPort = port
|
||||
client := &Standalone{
|
||||
process: &mockDaprProcess{
|
||||
Lo: []ListOutput{tc.lo},
|
||||
Err: tc.listErr,
|
||||
},
|
||||
}
|
||||
err := client.Publish(tc.topic, tc.payload, tc.pubsubName)
|
||||
if tc.errorExpected {
|
||||
assert.Error(t, err, "expected an error")
|
||||
assert.Equal(t, tc.errString, err.Error(), "expected error strings to match")
|
||||
} else {
|
||||
assert.NoError(t, err, "expected no error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
type mockDaprProcess struct {
|
||||
Lo []ListOutput
|
||||
Err error
|
||||
}
|
||||
|
||||
func (m *mockDaprProcess) List() ([]ListOutput, error) {
|
||||
return m.Lo, m.Err
|
||||
}
|
||||
|
||||
func getTestServer(expectedPath, resp string) (*httptest.Server, int) {
|
||||
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(
|
||||
w http.ResponseWriter, r *http.Request) {
|
||||
if r.RequestURI != expectedPath {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
if r.Method == http.MethodPost {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(r.Body)
|
||||
w.Write(buf.Bytes())
|
||||
} else if r.Method == http.MethodGet {
|
||||
w.Write([]byte(resp))
|
||||
}
|
||||
}))
|
||||
|
||||
return ts, ts.Listener.Addr().(*net.TCPAddr).Port
|
||||
}
|
Loading…
Reference in New Issue