Skip to content

Commit

Permalink
add list subscriptions by topic v1
Browse files Browse the repository at this point in the history
review ref
  • Loading branch information
Dai.Otsuka authored and Dai.Otsuka committed Aug 30, 2024
1 parent ee1df4c commit 5728a7c
Show file tree
Hide file tree
Showing 10 changed files with 431 additions and 113 deletions.
26 changes: 0 additions & 26 deletions app/gosns/gosns.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"time"

"github.com/google/uuid"
Expand Down Expand Up @@ -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")
Expand Down
61 changes: 0 additions & 61 deletions app/gosns/gosns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 := `<Owner>` + app.CurrentEnvironment.AccountID + `</Owner>`
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.
Expand Down
53 changes: 53 additions & 0 deletions app/gosns/list_subscriptions_by_topic.go
Original file line number Diff line number Diff line change
@@ -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

}
99 changes: 99 additions & 0 deletions app/gosns/list_subscriptions_by_topic_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
20 changes: 20 additions & 0 deletions app/models/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
13 changes: 13 additions & 0 deletions app/models/sns.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
2 changes: 1 addition & 1 deletion app/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion app/router/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
24 changes: 0 additions & 24 deletions app/sns_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Loading

0 comments on commit 5728a7c

Please sign in to comment.