Skip to content

Commit

Permalink
added confirm subscription
Browse files Browse the repository at this point in the history
update

udpate

fixed

update
  • Loading branch information
Dai.Otsuka authored and Admiral-Piett committed Sep 20, 2024
1 parent e54a44f commit 7e5d809
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 91 deletions.
40 changes: 40 additions & 0 deletions app/gosns/confirm_subscription.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package gosns

import (
"net/http"

"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 ConfirmSubscriptionV1(req *http.Request) (int, interfaces.AbstractResponseBody) {
requestBody := models.NewConfirmSubscriptionRequest()
ok := utils.REQUEST_TRANSFORMER(requestBody, req, false)
if !ok {
log.Error("Invalid Request - ConfirmSubscriptionV1")
return utils.CreateErrorResponseV1("InvalidParameterValue", false)
}
topicArn := requestBody.TopicArn
confirmToken := requestBody.Token
var pendingConfirm pendingConfirm

if pending, ok := TOPIC_DATA[topicArn]; !ok {
return utils.CreateErrorResponseV1("SubscriptionNotFound", false)
} else {
pendingConfirm = *pending
}

if pendingConfirm.token != confirmToken {
return utils.CreateErrorResponseV1("SubscriptionNotFound", false)
}
respStruct := models.ConfirmSubscriptionResponse{
Xmlns: models.BASE_XMLNS,
Result: models.ConfirmSubscriptionResult{SubscriptionArn: pendingConfirm.subArn},
Metadata: app.ResponseMetadata{RequestId: uuid.NewString()},
}
return http.StatusOK, respStruct
}
125 changes: 125 additions & 0 deletions app/gosns/confirm_subscription_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package gosns

import (
"net/http"
"testing"

"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 TestConfirmSubscriptionV1_Success(t *testing.T) {
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "BaseUnitTests")
defer func() {
test.ResetApp()
utils.REQUEST_TRANSFORMER = utils.TransformRequest
TOPIC_DATA = make(map[string]*pendingConfirm)
}()

topicArn := "test-topic-arn"
confirmToken := "test-token"
subscriptionArn := "test-sub-arn"

utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
v := resultingStruct.(*models.ConfirmSubscriptionRequest)
*v = models.ConfirmSubscriptionRequest{
TopicArn: topicArn,
Token: confirmToken,
}
return true
}
// set pending subscription
TOPIC_DATA[topicArn] = &pendingConfirm{
subArn: subscriptionArn,
token: confirmToken,
}

_, r := test.GenerateRequestInfo("POST", "/", nil, true)
code, response := ConfirmSubscriptionV1(r)

result := response.GetResult().(models.ConfirmSubscriptionResult)
assert.Equal(t, http.StatusOK, code)
assert.Equal(t, subscriptionArn, result.SubscriptionArn)
}

func TestConfirmSubscriptionV1_NotFoundSubscription(t *testing.T) {
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "NoQueuesOrTopics")
defer func() {
test.ResetApp()
utils.REQUEST_TRANSFORMER = utils.TransformRequest
TOPIC_DATA = make(map[string]*pendingConfirm)
}()

topicArn := "test-topic-arn"
confirmToken := "test-token"

utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
v := resultingStruct.(*models.ConfirmSubscriptionRequest)
*v = models.ConfirmSubscriptionRequest{
TopicArn: topicArn,
Token: confirmToken,
}
return true
}
_, r := test.GenerateRequestInfo("POST", "/", nil, true)
code, response := ConfirmSubscriptionV1(r)
result := response.GetResult().(models.ErrorResult)
assert.Equal(t, http.StatusNotFound, code)
assert.Contains(t, result.Message, "The specified subscription does not exist for this wsdl version.")
}

func TestConfirmSubscriptionV1_MismatchToken(t *testing.T) {

conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "BaseUnitTests")
defer func() {
test.ResetApp()
utils.REQUEST_TRANSFORMER = utils.TransformRequest
TOPIC_DATA = make(map[string]*pendingConfirm)
}()

topicArn := "test-topic-arn"
confirmToken := "test-token"
subscriptionArn := "test-sub-arn"

utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
v := resultingStruct.(*models.ConfirmSubscriptionRequest)
*v = models.ConfirmSubscriptionRequest{
TopicArn: topicArn,
Token: "dummy",
}
return true
}

// set dummy subscription
TOPIC_DATA[topicArn] = &pendingConfirm{
subArn: subscriptionArn,
token: confirmToken,
}

_, r := test.GenerateRequestInfo("POST", "/", nil, true)
code, response := ConfirmSubscriptionV1(r)
result := response.GetResult().(models.ErrorResult)
assert.Equal(t, http.StatusNotFound, code)
assert.Contains(t, result.Message, "The specified subscription does not exist for this wsdl version.")
}

func TestConfirmSubscriptionV1_TransformerError(t *testing.T) {
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "BaseUnitTests")
defer func() {
test.ResetApp()
utils.REQUEST_TRANSFORMER = utils.TransformRequest
TOPIC_DATA = make(map[string]*pendingConfirm)
}()

utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
return false
}

_, r := test.GenerateRequestInfo("POST", "/", nil, true)
code, _ := ConfirmSubscriptionV1(r)
assert.Equal(t, http.StatusBadRequest, code)
}
16 changes: 0 additions & 16 deletions app/gosns/gosns.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"net/http"
"time"

"github.com/google/uuid"

"github.com/Admiral-Piett/goaws/app/models"

"bytes"
Expand Down Expand Up @@ -129,20 +127,6 @@ func formatSignature(msg *app.SNSMessage) (formated string, err error) {
return
}

func ConfirmSubscription(w http.ResponseWriter, req *http.Request) {
topicArn := req.Form.Get("TopicArn")
confirmToken := req.Form.Get("Token")
pendingConfirm := TOPIC_DATA[topicArn]
if pendingConfirm.token == confirmToken {
respStruct := models.ConfirmSubscriptionResponse{"http://queue.amazonaws.com/doc/2012-11-05/", models.SubscribeResult{SubscriptionArn: pendingConfirm.subArn}, app.ResponseMetadata{RequestId: uuid.NewString()}}

SendResponseBack(w, req, respStruct, "application/xml")
} else {
createErrorResponse(w, req, "SubArnNotFound")
}

}

// NOTE: The use case for this is to use GoAWS to call some external system with the message payload. Essentially
// it is a localized subscription to some non-AWS endpoint.
func callEndpoint(endpoint string, subArn string, msg app.SNSMessage, raw bool) error {
Expand Down
18 changes: 15 additions & 3 deletions app/models/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,21 @@ func (r SubscribeResponse) GetRequestId() string {

/*** ConfirmSubscriptionResponse ***/
type ConfirmSubscriptionResponse struct {
Xmlns string `xml:"xmlns,attr"`
Result SubscribeResult `xml:"ConfirmSubscriptionResult"`
Metadata app.ResponseMetadata `xml:"ResponseMetadata"`
Xmlns string `xml:"xmlns,attr"`
Result ConfirmSubscriptionResult `xml:"ConfirmSubscriptionResult"`
Metadata app.ResponseMetadata `xml:"ResponseMetadata"`
}

type ConfirmSubscriptionResult struct {
SubscriptionArn string `xml:"SubscriptionArn"`
}

func (r ConfirmSubscriptionResponse) GetResult() interface{} {
return r.Result
}

func (r ConfirmSubscriptionResponse) GetRequestId() string {
return r.Metadata.RequestId
}

/*** Delete Subscription ***/
Expand Down
14 changes: 14 additions & 0 deletions app/models/sns.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,17 @@ type ListSubscriptionsByTopicRequest struct {
}

func (r *ListSubscriptionsByTopicRequest) SetAttributesFromForm(values url.Values) {}

// Confirm Subscription V1

func NewConfirmSubscriptionRequest() *ConfirmSubscriptionRequest {
return &ConfirmSubscriptionRequest{}
}

type ConfirmSubscriptionRequest struct {
AuthenticateOnUnsubscribe bool `json:"AuthenticateOnUnsubscribe" schema:"AuthenticateOnUnsubscribe"` // not implemented
TopicArn string `json:"TopicArn" schema:"TopicArn"`
Token string `json:"Token" schema:"Token"`
}

func (r *ConfirmSubscriptionRequest) SetAttributesFromForm(values url.Values) {}
16 changes: 4 additions & 12 deletions app/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,9 @@ var routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractR
"GetSubscriptionAttributes": sns.GetSubscriptionAttributesV1,
"SetSubscriptionAttributes": sns.SetSubscriptionAttributesV1,
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopicV1,
}

var routingTable = map[string]http.HandlerFunc{
// SNS Internal
"ConfirmSubscription": sns.ConfirmSubscription,
"ConfirmSubscription": sns.ConfirmSubscriptionV1,
}

func health(w http.ResponseWriter, req *http.Request) {
Expand All @@ -115,15 +113,9 @@ func actionHandler(w http.ResponseWriter, req *http.Request) {
encodeResponse(w, req, statusCode, responseBody)
return
}
fn, ok := routingTable[action]
if !ok {
log.Println("Bad Request - Action:", action)
w.WriteHeader(http.StatusBadRequest)
io.WriteString(w, "Bad Request")
return
}

http.HandlerFunc(fn).ServeHTTP(w, req)
log.Println("Bad Request - Action:", action)
w.WriteHeader(http.StatusBadRequest)
io.WriteString(w, "Bad Request")
}

func pemHandler(w http.ResponseWriter, req *http.Request) {
Expand Down
60 changes: 0 additions & 60 deletions app/router/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import (

"github.com/Admiral-Piett/goaws/app/interfaces"

sns "github.com/Admiral-Piett/goaws/app/gosns"

sqs "github.com/Admiral-Piett/goaws/app/gosqs"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -251,61 +249,3 @@ func TestActionHandler_v1_xml(t *testing.T) {
xml.Unmarshal(w.Body.Bytes(), &tmp)
assert.Equal(t, mocks.BaseResponse{Message: "response-body"}, tmp)
}

func TestActionHandler_v0_xml(t *testing.T) {
defer func() {
routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractResponseBody){
// SQS
"CreateQueue": sqs.CreateQueueV1,
"ListQueues": sqs.ListQueuesV1,
"GetQueueAttributes": sqs.GetQueueAttributesV1,
"SetQueueAttributes": sqs.SetQueueAttributesV1,
"SendMessage": sqs.SendMessageV1,
"ReceiveMessage": sqs.ReceiveMessageV1,
"DeleteMessage": sqs.DeleteMessageV1,
"ChangeMessageVisibility": sqs.ChangeMessageVisibilityV1,
"GetQueueUrl": sqs.GetQueueUrlV1,
"PurgeQueue": sqs.PurgeQueueV1,
"DeleteQueue": sqs.DeleteQueueV1,
"SendMessageBatch": sqs.SendMessageBatchV1,
"DeleteMessageBatch": sqs.DeleteMessageBatchV1,

// SNS
"Subscribe": sns.SubscribeV1,
"Unsubscribe": sns.UnsubscribeV1,
"Publish": sns.PublishV1,
"ListTopics": sns.ListTopicsV1,
"CreateTopic": sns.CreateTopicV1,
"DeleteTopic": sns.DeleteTopicV1,
"ListSubscriptions": sns.ListSubscriptionsV1,
"GetSubscriptionAttributes": sns.GetSubscriptionAttributesV1,
"SetSubscriptionAttributes": sns.SetSubscriptionAttributesV1,
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopicV1,
}

routingTable = map[string]http.HandlerFunc{
// SNS Internal
"ConfirmSubscription": sns.ConfirmSubscription,
}
}()

mockCalled := false
mockFunction := func(w http.ResponseWriter, req *http.Request) {
mockCalled = true
w.WriteHeader(http.StatusOK)
}
routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractResponseBody){}
routingTable = map[string]http.HandlerFunc{
"CreateQueue": mockFunction,
}

w, r := test.GenerateRequestInfo("POST", "/url", nil, false)
form := url.Values{}
form.Add("Action", "CreateQueue")
r.PostForm = form

actionHandler(w, r)

assert.True(t, mockCalled)
assert.Equal(t, http.StatusOK, w.Code)
}

0 comments on commit 7e5d809

Please sign in to comment.