Skip to content

Commit

Permalink
Add UnsubscribeV1 for JSON support
Browse files Browse the repository at this point in the history
  • Loading branch information
dhumphreys01 authored and Admiral-Piett committed Jul 11, 2024
1 parent c721136 commit d071f16
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 34 deletions.
26 changes: 0 additions & 26 deletions app/gosns/gosns.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,32 +306,6 @@ func GetSubscriptionAttributes(w http.ResponseWriter, req *http.Request) {
createErrorResponse(w, req, "SubscriptionNotFound")
}

func Unsubscribe(w http.ResponseWriter, req *http.Request) {
content := req.FormValue("ContentType")
subArn := req.FormValue("SubscriptionArn")

log.Println("Unsubscribe:", subArn)
for _, topic := range app.SyncTopics.Topics {
for i, sub := range topic.Subscriptions {
if sub.SubscriptionArn == subArn {
app.SyncTopics.Lock()

copy(topic.Subscriptions[i:], topic.Subscriptions[i+1:])
topic.Subscriptions[len(topic.Subscriptions)-1] = nil
topic.Subscriptions = topic.Subscriptions[:len(topic.Subscriptions)-1]

app.SyncTopics.Unlock()

uuid, _ := common.NewUUID()
respStruct := app.UnsubscribeResponse{"http://queue.amazonaws.com/doc/2012-11-05/", app.ResponseMetadata{RequestId: uuid}}
SendResponseBack(w, req, respStruct, content)
return
}
}
}
createErrorResponse(w, req, "SubscriptionNotFound")
}

func DeleteTopic(w http.ResponseWriter, req *http.Request) {
content := req.FormValue("ContentType")
topicArn := req.FormValue("TopicArn")
Expand Down
45 changes: 45 additions & 0 deletions app/gosns/unsubscribe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package gosns

import (
"net/http"

"github.com/google/uuid"

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

"github.com/Admiral-Piett/goaws/app"
"github.com/Admiral-Piett/goaws/app/interfaces"
log "github.com/sirupsen/logrus"
)

func UnsubscribeV1(req *http.Request) (int, interfaces.AbstractResponseBody) {
requestBody := models.NewUnsubscribeRequest()
ok := utils.REQUEST_TRANSFORMER(requestBody, req, false)
if !ok {
log.Error("Invalid Request - UnsubscribeV1")
return utils.CreateErrorResponseV1("InvalidParameterValue", false)
}

log.Infof("Unsubscribe: %s", requestBody.SubscriptionArn)
for _, topic := range app.SyncTopics.Topics {
for i, sub := range topic.Subscriptions {
if sub.SubscriptionArn == requestBody.SubscriptionArn {
app.SyncTopics.Lock()

copy(topic.Subscriptions[i:], topic.Subscriptions[i+1:])
topic.Subscriptions[len(topic.Subscriptions)-1] = nil
topic.Subscriptions = topic.Subscriptions[:len(topic.Subscriptions)-1]

app.SyncTopics.Unlock()

respStruct := models.UnsubscribeResponse{
Xmlns: models.BASE_XMLNS,
Metadata: app.ResponseMetadata{RequestId: uuid.NewString()},
}
return http.StatusOK, respStruct
}
}
}
return utils.CreateErrorResponseV1("SubscriptionNotFound", false)
}
83 changes: 83 additions & 0 deletions app/gosns/unsubscribe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package gosns

import (
"net/http"
"testing"

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

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

"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/test"
"github.com/Admiral-Piett/goaws/app/utils"
"github.com/stretchr/testify/assert"
)

func TestUnsubscribeV1_success(t *testing.T) {
conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "BaseUnitTests")
defer func() {
test.ResetApp()
utils.REQUEST_TRANSFORMER = utils.TransformRequest
}()

subArn := app.SyncTopics.Topics["unit-topic1"].Subscriptions[0].SubscriptionArn

utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
v := resultingStruct.(*models.UnsubscribeRequest)
*v = models.UnsubscribeRequest{
SubscriptionArn: subArn,
}
return true
}

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

assert.Equal(t, http.StatusOK, status)
_, ok := response.(models.UnsubscribeResponse)

subs := app.SyncTopics.Topics["unit-topic1"].Subscriptions
assert.Len(t, subs, 0)
assert.True(t, ok)
}

func TestUnsubscribeV1_invalid_request_body(t *testing.T) {
app.CurrentEnvironment = fixtures.LOCAL_ENVIRONMENT
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)
status, _ := UnsubscribeV1(r)

assert.Equal(t, http.StatusBadRequest, status)
}

func TestUnsubscribeV1_invalid_subscription_arn(t *testing.T) {
app.CurrentEnvironment = fixtures.LOCAL_ENVIRONMENT
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.UnsubscribeRequest)
*v = models.UnsubscribeRequest{
SubscriptionArn: "garbage",
}
return true
}

_, r := test.GenerateRequestInfo("POST", "/", nil, true)
status, _ := UnsubscribeV1(r)

assert.Equal(t, http.StatusBadRequest, status)
}
14 changes: 14 additions & 0 deletions app/models/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,17 @@ type ConfirmSubscriptionResponse struct {
Result SubscribeResult `xml:"ConfirmSubscriptionResult"`
Metadata app.ResponseMetadata `xml:"ResponseMetadata"`
}

/*** Delete Subscription ***/
type UnsubscribeResponse struct {
Xmlns string `xml:"xmlns,attr"`
Metadata app.ResponseMetadata `xml:"ResponseMetadata"`
}

func (r UnsubscribeResponse) GetResult() interface{} {
return nil
}

func (r UnsubscribeResponse) GetRequestId() string {
return r.Metadata.RequestId
}
10 changes: 10 additions & 0 deletions app/models/sns.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,13 @@ type SubscriptionAttributes struct {
//ReplayPolicy string `json:"ReplayPolicy" schema:"ReplayPolicy"`
//ReplayStatus string `json:"ReplayStatus" schema:"ReplayStatus"`
}

func NewUnsubscribeRequest() *UnsubscribeRequest {
return &UnsubscribeRequest{}
}

type UnsubscribeRequest struct {
SubscriptionArn string `json:"SubscriptionArn" schema:"SubscriptionArn"`
}

func (r *UnsubscribeRequest) 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 @@ -79,6 +79,7 @@ var routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractR
// SNS
"CreateTopic": sns.CreateTopicV1,
"Subscribe": sns.SubscribeV1,
"Unsubscribe": sns.UnsubscribeV1,
}

var routingTable = map[string]http.HandlerFunc{
Expand All @@ -93,7 +94,6 @@ var routingTable = map[string]http.HandlerFunc{
"GetSubscriptionAttributes": sns.GetSubscriptionAttributes,
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopic,
"ListSubscriptions": sns.ListSubscriptions,
"Unsubscribe": sns.Unsubscribe,
"Publish": sns.Publish,

// SNS Internal
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 @@ -271,6 +271,7 @@ func TestActionHandler_v0_xml(t *testing.T) {
// SNS
"CreateTopic": sns.CreateTopicV1,
"Subscribe": sns.SubscribeV1,
"Unsubscribe": sns.UnsubscribeV1,
}
routingTable = map[string]http.HandlerFunc{
// SQS
Expand All @@ -284,7 +285,6 @@ func TestActionHandler_v0_xml(t *testing.T) {
"GetSubscriptionAttributes": sns.GetSubscriptionAttributes,
"ListSubscriptionsByTopic": sns.ListSubscriptionsByTopic,
"ListSubscriptions": sns.ListSubscriptions,
"Unsubscribe": sns.Unsubscribe,
"Publish": sns.Publish,

// SNS Internal
Expand Down
6 changes: 0 additions & 6 deletions app/sns_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,6 @@ type PublishResponse struct {
Metadata ResponseMetadata `xml:"ResponseMetadata"`
}

/*** Unsubscribe ***/
type UnsubscribeResponse struct {
Xmlns string `xml:"xmlns,attr"`
Metadata ResponseMetadata `xml:"ResponseMetadata"`
}

/*** Delete Topic ***/
type DeleteTopicResponse struct {
Xmlns string `xml:"xmlns,attr"`
Expand Down
79 changes: 79 additions & 0 deletions smoke_tests/sns_unsubscribe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package smoke_tests

import (
"context"
"net/http"
"testing"

"github.com/aws/aws-sdk-go-v2/config"

"github.com/Admiral-Piett/goaws/app/conf"
"github.com/Admiral-Piett/goaws/app/test"

"github.com/gavv/httpexpect/v2"

"github.com/Admiral-Piett/goaws/app"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/sns"
"github.com/stretchr/testify/assert"
)

func Test_Unsubscribe_json(t *testing.T) {
server := generateServer()
defaultEnv := app.CurrentEnvironment
conf.LoadYamlConfig("../app/conf/mock-data/mock-config.yaml", "BaseUnitTests")
defer func() {
server.Close()
test.ResetResources()
app.CurrentEnvironment = defaultEnv
}()

sdkConfig, _ := config.LoadDefaultConfig(context.TODO())
sdkConfig.BaseEndpoint = aws.String(server.URL)
snsClient := sns.NewFromConfig(sdkConfig)

subArn := app.SyncTopics.Topics["unit-topic1"].Subscriptions[0].SubscriptionArn
response, err := snsClient.Unsubscribe(context.TODO(), &sns.UnsubscribeInput{
SubscriptionArn: &subArn,
})

assert.Nil(t, err)
assert.NotNil(t, response)

app.SyncTopics.Lock()
defer app.SyncTopics.Unlock()

subscriptions := app.SyncTopics.Topics["unit-topic1"].Subscriptions
assert.Len(t, subscriptions, 0)
}

func Test_Unsubscribe_xml(t *testing.T) {
server := generateServer()
defaultEnv := app.CurrentEnvironment
conf.LoadYamlConfig("../app/conf/mock-data/mock-config.yaml", "BaseUnitTests")
defer func() {
server.Close()
test.ResetResources()
app.CurrentEnvironment = defaultEnv
}()

e := httpexpect.Default(t, server.URL)

subArn := app.SyncTopics.Topics["unit-topic1"].Subscriptions[0].SubscriptionArn
requestBody := struct {
Action string `xml:"Action"`
SubscriptionArn string `schema:"SubscriptionArn"`
}{
Action: "Unsubscribe",
SubscriptionArn: subArn,
}

e.POST("/").
WithForm(requestBody).
Expect().
Status(http.StatusOK).
Body().Raw()

subscriptions := app.SyncTopics.Topics["unit-topic1"].Subscriptions
assert.Len(t, subscriptions, 0)
}

0 comments on commit d071f16

Please sign in to comment.