Skip to content

Commit

Permalink
Add CreateTopicV1 for JSON support
Browse files Browse the repository at this point in the history
  • Loading branch information
kojisaikiAtSony authored and Admiral-Piett committed Sep 20, 2024
1 parent 740700f commit 00ecbda
Show file tree
Hide file tree
Showing 13 changed files with 674 additions and 81 deletions.
48 changes: 48 additions & 0 deletions app/gosns/create_topic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package gosns

import (
"fmt"
"net/http"

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

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

topicName := requestBody.Name
topicArn := ""
if _, ok := app.SyncTopics.Topics[topicName]; ok {
topicArn = app.SyncTopics.Topics[topicName].Arn
} else {
topicArn = fmt.Sprintf("arn:aws:sns:%s:%s:%s", app.CurrentEnvironment.Region, app.CurrentEnvironment.AccountID, topicName)

log.Info("Creating Topic:", topicName)
topic := &app.Topic{Name: topicName, Arn: topicArn}
topic.Subscriptions = make([]*app.Subscription, 0)
app.SyncTopics.Lock()
app.SyncTopics.Topics[topicName] = topic
app.SyncTopics.Unlock()
}

uuid, _ := common.NewUUID()
respStruct := models.CreateTopicResponse{
Xmlns: models.BASE_XMLNS,
Result: models.CreateTopicResult{
TopicArn: topicArn,
},
Metadata: app.ResponseMetadata{RequestId: uuid},
}

return http.StatusOK, respStruct
}
106 changes: 106 additions & 0 deletions app/gosns/create_topic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package gosns

import (
"net/http"
"testing"

"github.com/Admiral-Piett/goaws/app"
"github.com/Admiral-Piett/goaws/app/fixtures"
"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 TestCreateTopicV1_success(t *testing.T) {
app.CurrentEnvironment = fixtures.LOCAL_ENVIRONMENT
defer func() {
test.ResetApp()
utils.REQUEST_TRANSFORMER = utils.TransformRequest
}()

targetTopicName := "new-topic-1"
request_success := models.CreateTopicRequest{
Name: targetTopicName,
}
utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
v := resultingStruct.(*models.CreateTopicRequest)
*v = request_success
return true
}

// No topic yet
assert.Equal(t, 0, len(app.SyncTopics.Topics))

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

// Result
assert.Equal(t, http.StatusOK, status)
createTopicResponse, ok := response.(models.CreateTopicResponse)
assert.True(t, ok)
assert.Contains(t, createTopicResponse.Result.TopicArn, "arn:aws:sns:")
assert.Contains(t, createTopicResponse.Result.TopicArn, targetTopicName)
// 1 topic there
assert.Equal(t, 1, len(app.SyncTopics.Topics))
}

func TestCreateTopicV1_existant_topic(t *testing.T) {
app.CurrentEnvironment = fixtures.LOCAL_ENVIRONMENT
defer func() {
test.ResetApp()
utils.REQUEST_TRANSFORMER = utils.TransformRequest
}()

targetTopicName := "new-topic-1"

// Same topic name with existant topic
request_success := models.CreateTopicRequest{
Name: targetTopicName,
}
utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) {
v := resultingStruct.(*models.CreateTopicRequest)
*v = request_success
return true
}

// Prepare existant topic
targetTopicArn := "arn:aws:sns:us-east-1:123456789012:" + targetTopicName
topic := &app.Topic{
Name: targetTopicName,
Arn: targetTopicArn,
}
app.SyncTopics.Topics[targetTopicName] = topic
assert.Equal(t, 1, len(app.SyncTopics.Topics))

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

// Result
assert.Equal(t, http.StatusOK, status)
createTopicResponse, ok := response.(models.CreateTopicResponse)
assert.True(t, ok)
assert.Equal(t, targetTopicArn, createTopicResponse.Result.TopicArn) // Same with existant topic
// No additional topic
assert.Equal(t, 1, len(app.SyncTopics.Topics))
}

func TestCreateTopicV1_request_transformer_error(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)
code, _ := CreateTopicV1(r)

assert.Equal(t, http.StatusBadRequest, code)
}
21 changes: 0 additions & 21 deletions app/gosns/gosns.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,27 +103,6 @@ func ListTopics(w http.ResponseWriter, req *http.Request) {
SendResponseBack(w, req, respStruct, content)
}

func CreateTopic(w http.ResponseWriter, req *http.Request) {
content := req.FormValue("ContentType")
topicName := req.FormValue("Name")
topicArn := ""
if _, ok := app.SyncTopics.Topics[topicName]; ok {
topicArn = app.SyncTopics.Topics[topicName].Arn
} else {
topicArn = "arn:aws:sns:" + app.CurrentEnvironment.Region + ":" + app.CurrentEnvironment.AccountID + ":" + topicName

log.Println("Creating Topic:", topicName)
topic := &app.Topic{Name: topicName, Arn: topicArn}
topic.Subscriptions = make([]*app.Subscription, 0, 0)
app.SyncTopics.Lock()
app.SyncTopics.Topics[topicName] = topic
app.SyncTopics.Unlock()
}
uuid, _ := common.NewUUID()
respStruct := app.CreateTopicResponse{"http://queue.amazonaws.com/doc/2012-11-05/", app.CreateTopicResult{TopicArn: topicArn}, app.ResponseMetadata{RequestId: uuid}}
SendResponseBack(w, req, respStruct, content)
}

func signMessage(privkey *rsa.PrivateKey, snsMsg *app.SNSMessage) (string, error) {
fs, err := formatSignature(snsMsg)
if err != nil {
Expand Down
103 changes: 68 additions & 35 deletions app/gosns/gosns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

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

"github.com/Admiral-Piett/goaws/app"
"github.com/Admiral-Piett/goaws/app/common"
Expand Down Expand Up @@ -44,42 +45,11 @@ func TestListTopicshandler_POST_NoTopics(t *testing.T) {
}
}

func TestCreateTopicshandler_POST_CreateTopics(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.
req, err := http.NewRequest("POST", "/", nil)
if err != nil {
t.Fatal(err)
}

form := url.Values{}
form.Add("Action", "CreateTopic")
form.Add("Name", "UnitTestTopic1")
req.PostForm = form

// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(CreateTopic)

// 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 := "UnitTestTopic1"
if !strings.Contains(rr.Body.String(), expected) {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}

func TestPublishhandler_POST_SendMessage(t *testing.T) {
defer func() {
test.ResetApp()
}()

// 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)
Expand All @@ -92,6 +62,13 @@ func TestPublishhandler_POST_SendMessage(t *testing.T) {
form.Add("Message", "TestMessage1")
req.PostForm = form

// Prepare existant topic
topic := &app.Topic{
Name: "UnitTestTopic1",
Arn: "arn:aws:sns:local:000000000000:UnitTestTopic1",
}
app.SyncTopics.Topics["UnitTestTopic1"] = topic

// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Publish)
Expand Down Expand Up @@ -258,6 +235,10 @@ func TestPublishHandler_POST_FilterPolicyPassesTheMessage(t *testing.T) {
}

func TestPublish_No_Queue_Error_handler_POST_Success(t *testing.T) {
defer func() {
test.ResetApp()
}()

// 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)
Expand All @@ -270,6 +251,13 @@ func TestPublish_No_Queue_Error_handler_POST_Success(t *testing.T) {
form.Add("Message", "TestMessage1")
req.PostForm = form

// Prepare existant topic
topic := &app.Topic{
Name: "UnitTestTopic1",
Arn: "arn:aws:sns:local:000000000000:UnitTestTopic1",
}
app.SyncTopics.Topics["UnitTestTopic1"] = topic

// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Publish)
Expand Down Expand Up @@ -313,6 +301,23 @@ func TestListSubscriptionByTopicResponse_No_Owner(t *testing.T) {
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)
Expand Down Expand Up @@ -355,6 +360,23 @@ func TestListSubscriptionsResponse_No_Owner(t *testing.T) {
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(ListSubscriptions)
Expand Down Expand Up @@ -395,6 +417,13 @@ func TestDeleteTopichandler_POST_Success(t *testing.T) {
form.Add("Message", "TestMessage1")
req.PostForm = form

// Prepare existant topic
topic := &app.Topic{
Name: "local-topic1",
Arn: "arn:aws:sns:local:000000000000:local-topic1",
}
app.SyncTopics.Topics["local-topic1"] = topic

// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(DeleteTopic)
Expand All @@ -421,6 +450,10 @@ func TestDeleteTopichandler_POST_Success(t *testing.T) {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}

// Target topic should be disappeared
_, ok := app.SyncTopics.Topics["local-topic1"]
assert.False(t, ok)
}

func TestGetSubscriptionAttributesHandler_POST_Success(t *testing.T) {
Expand Down
19 changes: 19 additions & 0 deletions app/models/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,25 @@ func (r DeleteQueueResponse) GetRequestId() string {
return r.Metadata.RequestId
}

/*** Create Topic Response */
type CreateTopicResult struct {
TopicArn string `xml:"TopicArn"`
}

type CreateTopicResponse struct {
Xmlns string `xml:"xmlns,attr"`
Result CreateTopicResult `xml:"CreateTopicResult"`
Metadata app.ResponseMetadata `xml:"ResponseMetadata"`
}

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

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

/*** Create Subscription ***/
type SubscribeResult struct {
SubscriptionArn string `xml:"SubscriptionArn"`
Expand Down
Loading

0 comments on commit 00ecbda

Please sign in to comment.