From 5728a7cd8e2e94341cae2e8d4c351beb21081d7e Mon Sep 17 00:00:00 2001 From: "Dai.Otsuka" Date: Wed, 14 Aug 2024 16:58:40 +0900 Subject: [PATCH] add list subscriptions by topic v1 review ref --- app/gosns/gosns.go | 26 -- app/gosns/gosns_test.go | 61 ----- app/gosns/list_subscriptions_by_topic.go | 53 ++++ app/gosns/list_subscriptions_by_topic_test.go | 99 +++++++ app/models/responses.go | 20 ++ app/models/sns.go | 13 + app/router/router.go | 2 +- app/router/router_test.go | 2 +- app/sns_messages.go | 24 -- .../sns_list_subscriptions_by_topic_test.go | 244 ++++++++++++++++++ 10 files changed, 431 insertions(+), 113 deletions(-) create mode 100644 app/gosns/list_subscriptions_by_topic.go create mode 100644 app/gosns/list_subscriptions_by_topic_test.go create mode 100644 smoke_tests/sns_list_subscriptions_by_topic_test.go diff --git a/app/gosns/gosns.go b/app/gosns/gosns.go index 1a3d3b11..93474392 100644 --- a/app/gosns/gosns.go +++ b/app/gosns/gosns.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "net/http" - "strings" "time" "github.com/google/uuid" @@ -145,31 +144,6 @@ func ConfirmSubscription(w http.ResponseWriter, req *http.Request) { } -func ListSubscriptionsByTopic(w http.ResponseWriter, req *http.Request) { - content := req.FormValue("ContentType") - topicArn := req.FormValue("TopicArn") - - uriSegments := strings.Split(topicArn, ":") - topicName := uriSegments[len(uriSegments)-1] - - if topic, ok := app.SyncTopics.Topics[topicName]; ok { - uuid, _ := common.NewUUID() - respStruct := app.ListSubscriptionsByTopicResponse{} - respStruct.Xmlns = "http://queue.amazonaws.com/doc/2012-11-05/" - respStruct.Metadata.RequestId = uuid - respStruct.Result.Subscriptions.Member = make([]app.TopicMemberResult, 0, 0) - - for _, sub := range topic.Subscriptions { - tar := app.TopicMemberResult{TopicArn: topic.Arn, Protocol: sub.Protocol, - SubscriptionArn: sub.SubscriptionArn, Endpoint: sub.EndPoint, Owner: app.CurrentEnvironment.AccountID} - respStruct.Result.Subscriptions.Member = append(respStruct.Result.Subscriptions.Member, tar) - } - SendResponseBack(w, req, respStruct, content) - } else { - createErrorResponse(w, req, "TopicNotFound") - } -} - func SetSubscriptionAttributes(w http.ResponseWriter, req *http.Request) { content := req.FormValue("ContentType") subsArn := req.FormValue("SubscriptionArn") diff --git a/app/gosns/gosns_test.go b/app/gosns/gosns_test.go index 1a6f7c76..9032e4cd 100644 --- a/app/gosns/gosns_test.go +++ b/app/gosns/gosns_test.go @@ -7,73 +7,12 @@ import ( "strings" "testing" - "github.com/Admiral-Piett/goaws/app/conf" "github.com/Admiral-Piett/goaws/app/test" "github.com/Admiral-Piett/goaws/app" "github.com/Admiral-Piett/goaws/app/common" ) -// TODO - add a subscription and I think this should work -func TestListSubscriptionByTopicResponse_No_Owner(t *testing.T) { - conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "Local") - defer func() { - test.ResetApp() - }() - - // set accountID to test value so it can be populated in response - app.CurrentEnvironment.AccountID = "100010001000" - - // Create a request to pass to our handler. We don't have any query parameters for now, so we'll - // pass 'nil' as the third parameter. - req, err := http.NewRequest("POST", "/", nil) - if err != nil { - t.Fatal(err) - } - - form := url.Values{} - form.Add("TopicArn", "arn:aws:sns:local:000000000000:local-topic1") - req.PostForm = form - - // Prepare existant topic - topic := &app.Topic{ - Name: "UnitTestTopic1", - Arn: "arn:aws:sns:local:100010001000:UnitTestTopic1", - Subscriptions: []*app.Subscription{ - { - TopicArn: "", - Protocol: "", - SubscriptionArn: "", - EndPoint: "", - Raw: false, - FilterPolicy: &app.FilterPolicy{}, - }, - }, - } - app.SyncTopics.Topics["UnitTestTopic1"] = topic - - // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. - rr := httptest.NewRecorder() - handler := http.HandlerFunc(ListSubscriptionsByTopic) - - // Our handlers satisfy http.Handler, so we can call their ServeHTTP method - // directly and pass in our Request and ResponseRecorder. - handler.ServeHTTP(rr, req) - - // Check the status code is what we expect. - if status := rr.Code; status != http.StatusOK { - t.Errorf("handler returned wrong status code: got %v want %v", - status, http.StatusOK) - } - - // Check the response body is what we expect. - expected := `` + app.CurrentEnvironment.AccountID + `` - if !strings.Contains(rr.Body.String(), expected) { - t.Errorf("handler returned empty owner for subscription member: got %v want %v", - rr.Body.String(), expected) - } -} - func TestSetSubscriptionAttributesHandler_FilterPolicy_POST_Success(t *testing.T) { // Create a request to pass to our handler. We don't have any query parameters for now, so we'll // pass 'nil' as the third parameter. diff --git a/app/gosns/list_subscriptions_by_topic.go b/app/gosns/list_subscriptions_by_topic.go new file mode 100644 index 00000000..9e8984fd --- /dev/null +++ b/app/gosns/list_subscriptions_by_topic.go @@ -0,0 +1,53 @@ +package gosns + +import ( + "net/http" + "strings" + + "github.com/Admiral-Piett/goaws/app" + "github.com/Admiral-Piett/goaws/app/interfaces" + "github.com/Admiral-Piett/goaws/app/models" + "github.com/Admiral-Piett/goaws/app/utils" + "github.com/google/uuid" + log "github.com/sirupsen/logrus" +) + +func ListSubscriptionsByTopicV1(req *http.Request) (int, interfaces.AbstractResponseBody) { + requestBody := models.NewListSubscriptionsByTopicRequest() + ok := utils.REQUEST_TRANSFORMER(requestBody, req, false) + if !ok { + log.Error("Invalid Request - ListSubscriptionsByTopicV1") + return utils.CreateErrorResponseV1("InvalidParameterValue", false) + } + + topicArn := requestBody.TopicArn + uriSegments := strings.Split(topicArn, ":") + topicName := uriSegments[len(uriSegments)-1] + var topic app.Topic + + if value, ok := app.SyncTopics.Topics[topicName]; ok { + topic = *value + } else { + return utils.CreateErrorResponseV1("TopicNotFound", false) + } + + resultMember := make([]models.TopicMemberResult, 0) + + for _, sub := range topic.Subscriptions { + tar := models.TopicMemberResult{TopicArn: topic.Arn, Protocol: sub.Protocol, + SubscriptionArn: sub.SubscriptionArn, Endpoint: sub.EndPoint, Owner: app.CurrentEnvironment.AccountID} + resultMember = append(resultMember, tar) + } + + respStruct := models.ListSubscriptionsByTopicResponse{ + Xmlns: models.BASE_XMLNS, + Result: models.ListSubscriptionsByTopicResult{ + Subscriptions: models.TopicSubscriptions{ + Member: resultMember, + }, + }, + Metadata: app.ResponseMetadata{RequestId: uuid.NewString()}, + } + return http.StatusOK, respStruct + +} diff --git a/app/gosns/list_subscriptions_by_topic_test.go b/app/gosns/list_subscriptions_by_topic_test.go new file mode 100644 index 00000000..91753dce --- /dev/null +++ b/app/gosns/list_subscriptions_by_topic_test.go @@ -0,0 +1,99 @@ +package gosns + +import ( + "net/http" + "testing" + + "github.com/Admiral-Piett/goaws/app" + "github.com/Admiral-Piett/goaws/app/conf" + "github.com/Admiral-Piett/goaws/app/interfaces" + "github.com/Admiral-Piett/goaws/app/models" + "github.com/Admiral-Piett/goaws/app/test" + "github.com/Admiral-Piett/goaws/app/utils" + "github.com/stretchr/testify/assert" +) + +func TestListSubscriptionsByTopicV1_Not_Found(t *testing.T) { + conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "NoQueuesOrTopics") + defer func() { + test.ResetApp() + utils.REQUEST_TRANSFORMER = utils.TransformRequest + }() + + utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) { + v := resultingStruct.(*models.ListSubscriptionsByTopicRequest) + *v = models.ListSubscriptionsByTopicRequest{ + NextToken: "", + TopicArn: "not exist arn", + } + return true + } + + _, r := test.GenerateRequestInfo("POST", "/", nil, true) + code, res := ListSubscriptionsByTopicV1(r) + response, _ := res.(models.ListSubscriptionsByTopicResponse) + + assert.Equal(t, http.StatusBadRequest, code) + assert.Empty(t, response.Result.Subscriptions.Member) +} + +func TestListSubscriptionsByTopicV1_Transform_Error(t *testing.T) { + conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "NoQueuesOrTopics") + defer func() { + test.ResetApp() + utils.REQUEST_TRANSFORMER = utils.TransformRequest + }() + + utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) { + return false + } + + _, r := test.GenerateRequestInfo("POST", "/", nil, true) + code, _ := ListSubscriptionsByTopicV1(r) + assert.Equal(t, http.StatusBadRequest, code) +} + +func TestListSubscriptionsByTopicV1_Success_Multiple_Subscription(t *testing.T) { + conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "Local") + defer func() { + test.ResetApp() + utils.REQUEST_TRANSFORMER = utils.TransformRequest + }() + + topicArn := app.SyncTopics.Topics["local-topic1"].Arn + subscriptions := app.SyncTopics.Topics["local-topic1"].Subscriptions + utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) { + v := resultingStruct.(*models.ListSubscriptionsByTopicRequest) + *v = models.ListSubscriptionsByTopicRequest{ + NextToken: "", + TopicArn: topicArn, + } + return true + } + + _, r := test.GenerateRequestInfo("POST", "/", nil, true) + code, res := ListSubscriptionsByTopicV1(r) + response, _ := res.(models.ListSubscriptionsByTopicResponse) + + assert.Equal(t, http.StatusOK, code) + assert.Len(t, response.Result.Subscriptions.Member, 2) + + expectedMember := []models.TopicMemberResult{ + { + TopicArn: subscriptions[0].TopicArn, + SubscriptionArn: subscriptions[0].SubscriptionArn, + Protocol: subscriptions[0].Protocol, + Owner: app.CurrentEnvironment.AccountID, + Endpoint: subscriptions[0].EndPoint, + }, + { + TopicArn: subscriptions[1].TopicArn, + SubscriptionArn: subscriptions[1].SubscriptionArn, + Protocol: subscriptions[1].Protocol, + Owner: app.CurrentEnvironment.AccountID, + Endpoint: subscriptions[1].EndPoint, + }, + } + + assert.ElementsMatch(t, expectedMember, response.Result.Subscriptions.Member) +} diff --git a/app/models/responses.go b/app/models/responses.go index 52371566..6bac9ca9 100644 --- a/app/models/responses.go +++ b/app/models/responses.go @@ -522,3 +522,23 @@ func (r GetSubscriptionAttributesResponse) GetResult() interface{} { func (r GetSubscriptionAttributesResponse) GetRequestId() string { return r.Metadata.RequestId } + +/*** List Subscriptions By Topic Response */ +type ListSubscriptionsByTopicResult struct { + NextToken string `xml:"NextToken"` // not implemented + Subscriptions TopicSubscriptions `xml:"Subscriptions"` +} + +type ListSubscriptionsByTopicResponse struct { + Xmlns string `xml:"xmlns,attr"` + Result ListSubscriptionsByTopicResult `xml:"ListSubscriptionsByTopicResult"` + Metadata app.ResponseMetadata `xml:"ResponseMetadata"` +} + +func (r ListSubscriptionsByTopicResponse) GetResult() interface{} { + return r.Result +} + +func (r ListSubscriptionsByTopicResponse) GetRequestId() string { + return r.Metadata.RequestId +} diff --git a/app/models/sns.go b/app/models/sns.go index 1f7647ba..021b0184 100644 --- a/app/models/sns.go +++ b/app/models/sns.go @@ -271,3 +271,16 @@ type GetSubscriptionAttributesRequest struct { } func (r *GetSubscriptionAttributesRequest) SetAttributesFromForm(values url.Values) {} + +// List Subscriptions By Topic + +func NewListSubscriptionsByTopicRequest() *ListSubscriptionsByTopicRequest { + return &ListSubscriptionsByTopicRequest{} +} + +type ListSubscriptionsByTopicRequest struct { + NextToken string `json:"NextToken" schema:"NextToken"` // not implemented + TopicArn string `json:"TopicArn" schema:"TopicArn"` +} + +func (r *ListSubscriptionsByTopicRequest) SetAttributesFromForm(values url.Values) {} diff --git a/app/router/router.go b/app/router/router.go index 0514a5a9..bc38b741 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -87,12 +87,12 @@ var routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractR "DeleteTopic": sns.DeleteTopicV1, "ListSubscriptions": sns.ListSubscriptionsV1, "GetSubscriptionAttributes": sns.GetSubscriptionAttributesV1, + "ListSubscriptionsByTopic": sns.ListSubscriptionsByTopicV1, } var routingTable = map[string]http.HandlerFunc{ // SNS "SetSubscriptionAttributes": sns.SetSubscriptionAttributes, - "ListSubscriptionsByTopic": sns.ListSubscriptionsByTopic, // SNS Internal "ConfirmSubscription": sns.ConfirmSubscription, diff --git a/app/router/router_test.go b/app/router/router_test.go index b1f0af0b..354cde52 100644 --- a/app/router/router_test.go +++ b/app/router/router_test.go @@ -279,12 +279,12 @@ func TestActionHandler_v0_xml(t *testing.T) { "DeleteTopic": sns.DeleteTopicV1, "ListSubscriptions": sns.ListSubscriptionsV1, "GetSubscriptionAttributes": sns.GetSubscriptionAttributesV1, + "ListSubscriptionsByTopic": sns.ListSubscriptionsByTopicV1, } routingTable = map[string]http.HandlerFunc{ // SNS "SetSubscriptionAttributes": sns.SetSubscriptionAttributes, - "ListSubscriptionsByTopic": sns.ListSubscriptionsByTopic, // SNS Internal "ConfirmSubscription": sns.ConfirmSubscription, diff --git a/app/sns_messages.go b/app/sns_messages.go index 7ec83f36..7925ddd1 100644 --- a/app/sns_messages.go +++ b/app/sns_messages.go @@ -5,27 +5,3 @@ type SetSubscriptionAttributesResponse struct { Xmlns string `xml:"xmlns,attr"` Metadata ResponseMetadata `xml:"ResponseMetadata"` } - -/*** List Subscriptions By Topic Response */ - -type TopicMemberResult struct { - TopicArn string `xml:"TopicArn"` - Protocol string `xml:"Protocol"` - SubscriptionArn string `xml:"SubscriptionArn"` - Owner string `xml:"Owner"` - Endpoint string `xml:"Endpoint"` -} - -type TopicSubscriptions struct { - Member []TopicMemberResult `xml:"member"` -} - -type ListSubscriptionsByTopicResult struct { - Subscriptions TopicSubscriptions `xml:"Subscriptions"` -} - -type ListSubscriptionsByTopicResponse struct { - Xmlns string `xml:"xmlns,attr"` - Result ListSubscriptionsByTopicResult `xml:"ListSubscriptionsByTopicResult"` - Metadata ResponseMetadata `xml:"ResponseMetadata"` -} diff --git a/smoke_tests/sns_list_subscriptions_by_topic_test.go b/smoke_tests/sns_list_subscriptions_by_topic_test.go new file mode 100644 index 00000000..764f258a --- /dev/null +++ b/smoke_tests/sns_list_subscriptions_by_topic_test.go @@ -0,0 +1,244 @@ +package smoke_tests + +import ( + "context" + "encoding/xml" + "net/http" + "testing" + + "github.com/Admiral-Piett/goaws/app" + af "github.com/Admiral-Piett/goaws/app/fixtures" + "github.com/Admiral-Piett/goaws/app/models" + "github.com/Admiral-Piett/goaws/app/test" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/sns" + "github.com/aws/aws-sdk-go-v2/service/sns/types" + "github.com/aws/aws-sdk-go-v2/service/sqs" + "github.com/gavv/httpexpect/v2" + "github.com/stretchr/testify/assert" +) + +func Test_ListSubscriptionsByTopic_Success_Multiple_Subscriptions(t *testing.T) { + server := generateServer() + defer func() { + server.Close() + test.ResetResources() + }() + + sdkConfig, _ := config.LoadDefaultConfig(context.TODO()) + sdkConfig.BaseEndpoint = aws.String(server.URL) + snsClient := sns.NewFromConfig(sdkConfig) + sqsClient := sqs.NewFromConfig(sdkConfig) + + createQueueResponse1, _ := sqsClient.CreateQueue(context.TODO(), &sqs.CreateQueueInput{ + QueueName: &af.QueueName, + }) + + createQueueResponse2, _ := sqsClient.CreateQueue(context.TODO(), &sqs.CreateQueueInput{ + QueueName: aws.String("new-queue-2"), + }) + + getQueueAttributesOutput1, _ := sqsClient.GetQueueAttributes(context.TODO(), &sqs.GetQueueAttributesInput{ + QueueUrl: createQueueResponse1.QueueUrl, + }) + + getQueueAttributesOutput2, _ := sqsClient.GetQueueAttributes(context.TODO(), &sqs.GetQueueAttributesInput{ + QueueUrl: createQueueResponse2.QueueUrl, + }) + + protocol := aws.String("sqs") + topicName := "new-topic-1" + createTopicResponse, _ := snsClient.CreateTopic(context.TODO(), &sns.CreateTopicInput{ + Name: &topicName, + }) + + subscribeResponse1, _ := snsClient.Subscribe(context.TODO(), &sns.SubscribeInput{ + Protocol: protocol, + TopicArn: createTopicResponse.TopicArn, + Attributes: map[string]string{}, + Endpoint: aws.String(getQueueAttributesOutput1.Attributes["QueueArn"]), + ReturnSubscriptionArn: true, + }) + + subscribeResponse2, _ := snsClient.Subscribe(context.TODO(), &sns.SubscribeInput{ + Protocol: protocol, + TopicArn: createTopicResponse.TopicArn, + Attributes: map[string]string{}, + Endpoint: aws.String(getQueueAttributesOutput2.Attributes["QueueArn"]), + ReturnSubscriptionArn: true, + }) + + listSubscriptionsByTopicOutput, _ := snsClient.ListSubscriptionsByTopic(context.TODO(), &sns.ListSubscriptionsByTopicInput{ + TopicArn: createTopicResponse.TopicArn, + }) + + assert.NotNil(t, listSubscriptionsByTopicOutput) + assert.Len(t, listSubscriptionsByTopicOutput.Subscriptions, 2) + + subscriptionMap := make(map[string]types.Subscription, 2) + for _, subscription := range listSubscriptionsByTopicOutput.Subscriptions { + subscriptionMap[*subscription.SubscriptionArn] = subscription + } + + subscription1, exists := subscriptionMap[*subscribeResponse1.SubscriptionArn] + assert.True(t, exists) + assert.Equal(t, createTopicResponse.TopicArn, subscription1.TopicArn) + assert.Equal(t, *subscribeResponse1.SubscriptionArn, *subscription1.SubscriptionArn) + assert.Equal(t, *protocol, *(subscription1.Protocol)) + assert.Equal(t, app.CurrentEnvironment.AccountID, *(subscription1.Owner)) + assert.Equal(t, getQueueAttributesOutput1.Attributes["QueueArn"], *(subscription1.Endpoint)) + + subscription2, exists := subscriptionMap[*subscribeResponse2.SubscriptionArn] + assert.True(t, exists) + assert.Equal(t, createTopicResponse.TopicArn, subscription2.TopicArn) + assert.Equal(t, subscribeResponse2.SubscriptionArn, subscription2.SubscriptionArn) + assert.Equal(t, *protocol, *(subscription2.Protocol)) + assert.Equal(t, app.CurrentEnvironment.AccountID, *(subscription2.Owner)) + assert.Equal(t, getQueueAttributesOutput2.Attributes["QueueArn"], *(subscription2.Endpoint)) +} + +func Test_ListSubscriptionsByTopic_Json_Not_Found(t *testing.T) { + server := generateServer() + defer func() { + server.Close() + test.ResetResources() + }() + + sdkConfig, _ := config.LoadDefaultConfig(context.TODO()) + sdkConfig.BaseEndpoint = aws.String(server.URL) + snsClient := sns.NewFromConfig(sdkConfig) + + listSubscriptionsByTopicOutput, err := snsClient.ListSubscriptionsByTopic(context.TODO(), &sns.ListSubscriptionsByTopicInput{ + TopicArn: aws.String("not exist arn"), + }) + + assert.Nil(t, listSubscriptionsByTopicOutput) + assert.Contains(t, err.Error(), "AWS.SimpleNotificationService.NonExistentTopic") +} + +func Test_ListSubscriptionsByTopic_Xml_Success_Multiple_Subscriptions(t *testing.T) { + + server := generateServer() + defer func() { + server.Close() + test.ResetResources() + }() + + sdkConfig, _ := config.LoadDefaultConfig(context.TODO()) + sdkConfig.BaseEndpoint = aws.String(server.URL) + snsClient := sns.NewFromConfig(sdkConfig) + sqsClient := sqs.NewFromConfig(sdkConfig) + + createQueueResponse1, _ := sqsClient.CreateQueue(context.TODO(), &sqs.CreateQueueInput{ + QueueName: &af.QueueName, + }) + + createQueueResponse2, _ := sqsClient.CreateQueue(context.TODO(), &sqs.CreateQueueInput{ + QueueName: aws.String("new-queue-2"), + }) + + getQueueAttributesOutput1, _ := sqsClient.GetQueueAttributes(context.TODO(), &sqs.GetQueueAttributesInput{ + QueueUrl: createQueueResponse1.QueueUrl, + }) + + getQueueAttributesOutput2, _ := sqsClient.GetQueueAttributes(context.TODO(), &sqs.GetQueueAttributesInput{ + QueueUrl: createQueueResponse2.QueueUrl, + }) + + protocol := aws.String("sqs") + topicName := "new-topic-1" + createTopicResponse, _ := snsClient.CreateTopic(context.TODO(), &sns.CreateTopicInput{ + Name: &topicName, + }) + + subscribeResponse1, _ := snsClient.Subscribe(context.TODO(), &sns.SubscribeInput{ + Protocol: protocol, + TopicArn: createTopicResponse.TopicArn, + Attributes: map[string]string{}, + Endpoint: aws.String(getQueueAttributesOutput1.Attributes["QueueArn"]), + ReturnSubscriptionArn: true, + }) + + subscribeResponse2, _ := snsClient.Subscribe(context.TODO(), &sns.SubscribeInput{ + Protocol: protocol, + TopicArn: createTopicResponse.TopicArn, + Attributes: map[string]string{}, + Endpoint: aws.String(getQueueAttributesOutput2.Attributes["QueueArn"]), + ReturnSubscriptionArn: true, + }) + + requestBody := struct { + Action string `xml:"Action"` + TopicArn string `xml:"TopicArn"` + Version string `xml:"Version"` + }{ + Action: "ListSubscriptionsByTopic", + TopicArn: *createTopicResponse.TopicArn, + Version: "2012-11-05", + } + e := httpexpect.Default(t, server.URL) + + r := e.POST("/"). + WithForm(requestBody). + Expect(). + Status(http.StatusOK). + Body().Raw() + + listSubscriptionsByTopicResponse := models.ListSubscriptionsByTopicResponse{} + xml.Unmarshal([]byte(r), &listSubscriptionsByTopicResponse) + + assert.NotNil(t, listSubscriptionsByTopicResponse) + assert.Len(t, listSubscriptionsByTopicResponse.Result.Subscriptions.Member, 2) + + expectedMember := []models.TopicMemberResult{ + { + TopicArn: *createTopicResponse.TopicArn, + SubscriptionArn: *subscribeResponse1.SubscriptionArn, + Protocol: *protocol, + Owner: app.CurrentEnvironment.AccountID, + Endpoint: getQueueAttributesOutput1.Attributes["QueueArn"], + }, + { + TopicArn: *createTopicResponse.TopicArn, + SubscriptionArn: *subscribeResponse2.SubscriptionArn, + Protocol: *protocol, + Owner: app.CurrentEnvironment.AccountID, + Endpoint: getQueueAttributesOutput2.Attributes["QueueArn"], + }, + } + + assert.ElementsMatch(t, expectedMember, listSubscriptionsByTopicResponse.Result.Subscriptions.Member) +} + +func Test_ListSubscriptionsByTopic_Xml_Not_Found(t *testing.T) { + + server := generateServer() + defer func() { + server.Close() + test.ResetResources() + }() + + e := httpexpect.Default(t, server.URL) + + requestBody := struct { + Action string `xml:"Action"` + TopicArn string `xml:"TopicArn"` + Version string `xml:"Version"` + }{ + Action: "ListSubscriptionsByTopic", + TopicArn: "not exist arn", + Version: "2012-11-05", + } + + r := e.POST("/"). + WithForm(requestBody). + Expect(). + Status(http.StatusBadRequest). + Body().Raw() + + listSubscriptionsByTopicResponse := models.ListSubscriptionsByTopicResponse{} + xml.Unmarshal([]byte(r), &listSubscriptionsByTopicResponse) + assert.Empty(t, listSubscriptionsByTopicResponse.Result.Subscriptions.Member) + +}