Skip to content

Commit 77719e6

Browse files
Dai.OtsukaDai.Otsuka
Dai.Otsuka
authored and
Dai.Otsuka
committed
add list subscriptions by topic v1
1 parent 2ca8cc6 commit 77719e6

File tree

10 files changed

+446
-112
lines changed

10 files changed

+446
-112
lines changed

app/gosns/gosns.go

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"net/http"
99
"strconv"
10-
"strings"
1110
"time"
1211

1312
"github.com/google/uuid"
@@ -166,31 +165,6 @@ func ListSubscriptions(w http.ResponseWriter, req *http.Request) {
166165
SendResponseBack(w, req, respStruct, content)
167166
}
168167

169-
func ListSubscriptionsByTopic(w http.ResponseWriter, req *http.Request) {
170-
content := req.FormValue("ContentType")
171-
topicArn := req.FormValue("TopicArn")
172-
173-
uriSegments := strings.Split(topicArn, ":")
174-
topicName := uriSegments[len(uriSegments)-1]
175-
176-
if topic, ok := app.SyncTopics.Topics[topicName]; ok {
177-
uuid, _ := common.NewUUID()
178-
respStruct := app.ListSubscriptionsByTopicResponse{}
179-
respStruct.Xmlns = "http://queue.amazonaws.com/doc/2012-11-05/"
180-
respStruct.Metadata.RequestId = uuid
181-
respStruct.Result.Subscriptions.Member = make([]app.TopicMemberResult, 0, 0)
182-
183-
for _, sub := range topic.Subscriptions {
184-
tar := app.TopicMemberResult{TopicArn: topic.Arn, Protocol: sub.Protocol,
185-
SubscriptionArn: sub.SubscriptionArn, Endpoint: sub.EndPoint, Owner: app.CurrentEnvironment.AccountID}
186-
respStruct.Result.Subscriptions.Member = append(respStruct.Result.Subscriptions.Member, tar)
187-
}
188-
SendResponseBack(w, req, respStruct, content)
189-
} else {
190-
createErrorResponse(w, req, "TopicNotFound")
191-
}
192-
}
193-
194168
func SetSubscriptionAttributes(w http.ResponseWriter, req *http.Request) {
195169
content := req.FormValue("ContentType")
196170
subsArn := req.FormValue("SubscriptionArn")

app/gosns/gosns_test.go

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,66 +14,6 @@ import (
1414
"github.com/Admiral-Piett/goaws/app/common"
1515
)
1616

17-
// TODO - add a subscription and I think this should work
18-
func TestListSubscriptionByTopicResponse_No_Owner(t *testing.T) {
19-
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "Local")
20-
defer func() {
21-
test.ResetApp()
22-
}()
23-
24-
// set accountID to test value so it can be populated in response
25-
app.CurrentEnvironment.AccountID = "100010001000"
26-
27-
// Create a request to pass to our handler. We don't have any query parameters for now, so we'll
28-
// pass 'nil' as the third parameter.
29-
req, err := http.NewRequest("POST", "/", nil)
30-
if err != nil {
31-
t.Fatal(err)
32-
}
33-
34-
form := url.Values{}
35-
form.Add("TopicArn", "arn:aws:sns:local:000000000000:local-topic1")
36-
req.PostForm = form
37-
38-
// Prepare existant topic
39-
topic := &app.Topic{
40-
Name: "UnitTestTopic1",
41-
Arn: "arn:aws:sns:local:100010001000:UnitTestTopic1",
42-
Subscriptions: []*app.Subscription{
43-
{
44-
TopicArn: "",
45-
Protocol: "",
46-
SubscriptionArn: "",
47-
EndPoint: "",
48-
Raw: false,
49-
FilterPolicy: &app.FilterPolicy{},
50-
},
51-
},
52-
}
53-
app.SyncTopics.Topics["UnitTestTopic1"] = topic
54-
55-
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
56-
rr := httptest.NewRecorder()
57-
handler := http.HandlerFunc(ListSubscriptionsByTopic)
58-
59-
// Our handlers satisfy http.Handler, so we can call their ServeHTTP method
60-
// directly and pass in our Request and ResponseRecorder.
61-
handler.ServeHTTP(rr, req)
62-
63-
// Check the status code is what we expect.
64-
if status := rr.Code; status != http.StatusOK {
65-
t.Errorf("handler returned wrong status code: got %v want %v",
66-
status, http.StatusOK)
67-
}
68-
69-
// Check the response body is what we expect.
70-
expected := `<Owner>` + app.CurrentEnvironment.AccountID + `</Owner>`
71-
if !strings.Contains(rr.Body.String(), expected) {
72-
t.Errorf("handler returned empty owner for subscription member: got %v want %v",
73-
rr.Body.String(), expected)
74-
}
75-
}
76-
7717
func TestListSubscriptionsResponse_No_Owner(t *testing.T) {
7818
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "Local")
7919
defer func() {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package gosns
2+
3+
import (
4+
"net/http"
5+
"strings"
6+
7+
"github.com/Admiral-Piett/goaws/app"
8+
"github.com/Admiral-Piett/goaws/app/interfaces"
9+
"github.com/Admiral-Piett/goaws/app/models"
10+
"github.com/Admiral-Piett/goaws/app/utils"
11+
"github.com/google/uuid"
12+
log "github.com/sirupsen/logrus"
13+
)
14+
15+
func ListSubscriptionsByTopicV1(req *http.Request) (int, interfaces.AbstractResponseBody) {
16+
requestBody := models.NewListSubscriptionsByTopicRequest()
17+
ok := utils.REQUEST_TRANSFORMER(requestBody, req, false)
18+
if !ok {
19+
log.Error("Invalid Request - ListSubscriptionsByTopicV1")
20+
return utils.CreateErrorResponseV1("InvalidParameterValue", false)
21+
}
22+
23+
topicArn := requestBody.TopicArn
24+
uriSegments := strings.Split(topicArn, ":")
25+
topicName := uriSegments[len(uriSegments)-1]
26+
27+
if _, ok := app.SyncTopics.Topics[topicName]; !ok {
28+
return utils.CreateErrorResponseV1("TopicNotFound", false)
29+
}
30+
31+
topic := app.SyncTopics.Topics[topicName]
32+
resultMember := make([]app.TopicMemberResult, 0)
33+
34+
for _, sub := range topic.Subscriptions {
35+
tar := app.TopicMemberResult{TopicArn: topic.Arn, Protocol: sub.Protocol,
36+
SubscriptionArn: sub.SubscriptionArn, Endpoint: sub.EndPoint, Owner: app.CurrentEnvironment.AccountID}
37+
resultMember = append(resultMember, tar)
38+
}
39+
40+
respStruct := models.ListSubscriptionsByTopicResponse{
41+
Xmlns: models.BASE_XMLNS,
42+
Result: models.ListSubscriptionsByTopicResult{
43+
Subscriptions: app.TopicSubscriptions{
44+
Member: resultMember,
45+
},
46+
},
47+
Metadata: app.ResponseMetadata{RequestId: uuid.NewString()},
48+
}
49+
return http.StatusOK, respStruct
50+
51+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package gosns
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
7+
"github.com/Admiral-Piett/goaws/app"
8+
"github.com/Admiral-Piett/goaws/app/conf"
9+
"github.com/Admiral-Piett/goaws/app/interfaces"
10+
"github.com/Admiral-Piett/goaws/app/models"
11+
"github.com/Admiral-Piett/goaws/app/test"
12+
"github.com/Admiral-Piett/goaws/app/utils"
13+
"github.com/stretchr/testify/assert"
14+
)
15+
16+
func TestListSubscriptionsByTopicV1_Not_Found(t *testing.T) {
17+
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "NoQueuesOrTopics")
18+
defer func() {
19+
test.ResetApp()
20+
utils.REQUEST_TRANSFORMER = utils.TransformRequest
21+
}()
22+
23+
utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
24+
v := resultingStruct.(*models.ListSubscriptionsByTopicRequest)
25+
*v = models.ListSubscriptionsByTopicRequest{
26+
NextToken: "",
27+
TopicArn: "not exist arn",
28+
}
29+
return true
30+
}
31+
32+
_, r := test.GenerateRequestInfo("POST", "/", nil, true)
33+
code, res := ListSubscriptionsByTopicV1(r)
34+
response, _ := res.(models.ListSubscriptionsByTopicResponse)
35+
36+
assert.Equal(t, http.StatusBadRequest, code)
37+
assert.Empty(t, response.Result.Subscriptions.Member)
38+
}
39+
40+
func TestListSubscriptionsByTopicV1_Transform_Error(t *testing.T) {
41+
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "NoQueuesOrTopics")
42+
defer func() {
43+
test.ResetApp()
44+
utils.REQUEST_TRANSFORMER = utils.TransformRequest
45+
}()
46+
47+
utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
48+
return false
49+
}
50+
51+
_, r := test.GenerateRequestInfo("POST", "/", nil, true)
52+
code, _ := ListSubscriptionsByTopicV1(r)
53+
assert.Equal(t, http.StatusBadRequest, code)
54+
}
55+
56+
func TestListSubscriptionsByTopicV1_Success_Multiple_Subscription(t *testing.T) {
57+
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "Local")
58+
defer func() {
59+
test.ResetApp()
60+
utils.REQUEST_TRANSFORMER = utils.TransformRequest
61+
}()
62+
63+
topicArn := app.SyncTopics.Topics["local-topic1"].Arn
64+
subscriptions := app.SyncTopics.Topics["local-topic1"].Subscriptions
65+
utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
66+
v := resultingStruct.(*models.ListSubscriptionsByTopicRequest)
67+
*v = models.ListSubscriptionsByTopicRequest{
68+
NextToken: "",
69+
TopicArn: topicArn,
70+
}
71+
return true
72+
}
73+
74+
_, r := test.GenerateRequestInfo("POST", "/", nil, true)
75+
code, res := ListSubscriptionsByTopicV1(r)
76+
response, _ := res.(models.ListSubscriptionsByTopicResponse)
77+
78+
assert.Equal(t, http.StatusOK, code)
79+
assert.Len(t, response.Result.Subscriptions.Member, 2)
80+
81+
memberMap := make(map[string]app.TopicMemberResult, 2)
82+
for _, member := range response.Result.Subscriptions.Member {
83+
memberMap[member.SubscriptionArn] = member
84+
}
85+
86+
member1, exists := memberMap[subscriptions[0].SubscriptionArn]
87+
assert.True(t, exists)
88+
assert.Equal(t, subscriptions[0].TopicArn, member1.TopicArn)
89+
assert.Equal(t, subscriptions[0].SubscriptionArn, member1.SubscriptionArn)
90+
assert.Equal(t, subscriptions[0].Protocol, member1.Protocol)
91+
assert.Equal(t, app.CurrentEnvironment.AccountID, member1.Owner)
92+
assert.Equal(t, subscriptions[0].EndPoint, member1.Endpoint)
93+
94+
member2, exists := memberMap[subscriptions[1].SubscriptionArn]
95+
assert.True(t, exists)
96+
assert.Equal(t, subscriptions[1].TopicArn, member2.TopicArn)
97+
assert.Equal(t, subscriptions[1].SubscriptionArn, member2.SubscriptionArn)
98+
assert.Equal(t, subscriptions[1].Protocol, member2.Protocol)
99+
assert.Equal(t, app.CurrentEnvironment.AccountID, member2.Owner)
100+
assert.Equal(t, subscriptions[1].EndPoint, member2.Endpoint)
101+
}

app/models/responses.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,3 +461,24 @@ func (r DeleteTopicResponse) GetResult() interface{} {
461461
func (r DeleteTopicResponse) GetRequestId() string {
462462
return r.Metadata.RequestId
463463
}
464+
465+
/*** List Subscriptions By Topic Response */
466+
467+
type ListSubscriptionsByTopicResult struct {
468+
NextToken string `xml:"NextToken"` // not implemented
469+
Subscriptions app.TopicSubscriptions `xml:"Subscriptions"`
470+
}
471+
472+
type ListSubscriptionsByTopicResponse struct {
473+
Xmlns string `xml:"xmlns,attr"`
474+
Result ListSubscriptionsByTopicResult `xml:"ListSubscriptionsByTopicResult"`
475+
Metadata app.ResponseMetadata `xml:"ResponseMetadata"`
476+
}
477+
478+
func (r ListSubscriptionsByTopicResponse) GetResult() interface{} {
479+
return r.Result
480+
}
481+
482+
func (r ListSubscriptionsByTopicResponse) GetRequestId() string {
483+
return r.Metadata.RequestId
484+
}

app/models/sns.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,16 @@ type DeleteTopicRequest struct {
248248
}
249249

250250
func (r *DeleteTopicRequest) SetAttributesFromForm(values url.Values) {}
251+
252+
// List Subscriptions By Topic
253+
254+
func NewListSubscriptionsByTopicRequest() *ListSubscriptionsByTopicRequest {
255+
return &ListSubscriptionsByTopicRequest{}
256+
}
257+
258+
type ListSubscriptionsByTopicRequest struct {
259+
NextToken string `json:"NextToken" schema:"NextToken"` // not implemented
260+
TopicArn string `json:"TopicArn" schema:"TopicArn"`
261+
}
262+
263+
func (r *ListSubscriptionsByTopicRequest) SetAttributesFromForm(values url.Values) {}

app/router/router.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,19 @@ var routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractR
7979
"DeleteMessageBatch": sqs.DeleteMessageBatchV1,
8080

8181
// SNS
82-
"Subscribe": sns.SubscribeV1,
83-
"Unsubscribe": sns.UnsubscribeV1,
84-
"Publish": sns.PublishV1,
85-
"ListTopics": sns.ListTopicsV1,
86-
"CreateTopic": sns.CreateTopicV1,
87-
"DeleteTopic": sns.DeleteTopicV1,
82+
"Subscribe": sns.SubscribeV1,
83+
"Unsubscribe": sns.UnsubscribeV1,
84+
"Publish": sns.PublishV1,
85+
"ListTopics": sns.ListTopicsV1,
86+
"CreateTopic": sns.CreateTopicV1,
87+
"DeleteTopic": sns.DeleteTopicV1,
88+
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopicV1,
8889
}
8990

9091
var routingTable = map[string]http.HandlerFunc{
9192
// SNS
9293
"SetSubscriptionAttributes": sns.SetSubscriptionAttributes,
9394
"GetSubscriptionAttributes": sns.GetSubscriptionAttributes,
94-
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopic,
9595
"ListSubscriptions": sns.ListSubscriptions,
9696

9797
// SNS Internal

app/router/router_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,19 +271,19 @@ func TestActionHandler_v0_xml(t *testing.T) {
271271
"DeleteMessageBatch": sqs.DeleteMessageBatchV1,
272272

273273
// SNS
274-
"Subscribe": sns.SubscribeV1,
275-
"Unsubscribe": sns.UnsubscribeV1,
276-
"Publish": sns.PublishV1,
277-
"ListTopics": sns.ListTopicsV1,
278-
"CreateTopic": sns.CreateTopicV1,
279-
"DeleteTopic": sns.DeleteTopicV1,
274+
"Subscribe": sns.SubscribeV1,
275+
"Unsubscribe": sns.UnsubscribeV1,
276+
"Publish": sns.PublishV1,
277+
"ListTopics": sns.ListTopicsV1,
278+
"CreateTopic": sns.CreateTopicV1,
279+
"DeleteTopic": sns.DeleteTopicV1,
280+
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopicV1,
280281
}
281282

282283
routingTable = map[string]http.HandlerFunc{
283284
// SNS
284285
"SetSubscriptionAttributes": sns.SetSubscriptionAttributes,
285286
"GetSubscriptionAttributes": sns.GetSubscriptionAttributes,
286-
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopic,
287287
"ListSubscriptions": sns.ListSubscriptions,
288288

289289
// SNS Internal

app/sns_messages.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,3 @@ type ListSubscriptionsResponse struct {
4949
Result ListSubscriptionsResult `xml:"ListSubscriptionsResult"`
5050
Metadata ResponseMetadata `xml:"ResponseMetadata"`
5151
}
52-
53-
/*** List Subscriptions By Topic Response */
54-
55-
type ListSubscriptionsByTopicResult struct {
56-
Subscriptions TopicSubscriptions `xml:"Subscriptions"`
57-
}
58-
59-
type ListSubscriptionsByTopicResponse struct {
60-
Xmlns string `xml:"xmlns,attr"`
61-
Result ListSubscriptionsByTopicResult `xml:"ListSubscriptionsByTopicResult"`
62-
Metadata ResponseMetadata `xml:"ResponseMetadata"`
63-
}

0 commit comments

Comments
 (0)