From 1ef3441a0be39b6e80659577febf7fa2f0f38efb Mon Sep 17 00:00:00 2001 From: "Dai.Otsuka" Date: Mon, 3 Jun 2024 15:58:15 +0900 Subject: [PATCH] Add GetQueueUrlV1 for JSON support --- app/gosqs/get_queue_url.go | 38 ++++++++ app/gosqs/get_queue_url_test.go | 102 +++++++++++++++++++ app/gosqs/gosqs.go | 23 ----- app/models/models.go | 12 +++ app/models/responses.go | 19 ++++ app/router/router.go | 2 +- app/router/router_test.go | 2 +- app/sqs_messages.go | 11 --- smoke_tests/sqs_get_queue_url_test.go | 135 ++++++++++++++++++++++++++ 9 files changed, 308 insertions(+), 36 deletions(-) create mode 100644 app/gosqs/get_queue_url.go create mode 100644 app/gosqs/get_queue_url_test.go create mode 100644 smoke_tests/sqs_get_queue_url_test.go diff --git a/app/gosqs/get_queue_url.go b/app/gosqs/get_queue_url.go new file mode 100644 index 00000000..9c467f49 --- /dev/null +++ b/app/gosqs/get_queue_url.go @@ -0,0 +1,38 @@ +package gosqs + +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" + log "github.com/sirupsen/logrus" +) + +func GetQueueUrlV1(req *http.Request) (int, interfaces.AbstractResponseBody) { + + requestBody := models.NewGetQueueUrlRequest() + ok := utils.REQUEST_TRANSFORMER(requestBody, req, false) + if !ok { + log.Error("Invalid Request - GetQueueUrlV1") + return createErrorResponseV1(ErrInvalidParameterValue.Type) + } + + queueName := requestBody.QueueName + if _, ok := app.SyncQueues.Queues[queueName]; !ok { + log.Error("Get Queue URL:", queueName, ", queue does not exist!!!") + return createErrorResponseV1("QueueNotFound") + } + + queue := app.SyncQueues.Queues[queueName] + log.Debug("Get Queue URL:", queue.Name) + + result := models.GetQueueUrlResult{QueueUrl: queue.URL} + respStruct := models.GetQueueUrlResponse{ + Xmlns: models.BASE_XMLNS, + Result: result, + Metadata: models.BASE_RESPONSE_METADATA, + } + return http.StatusOK, respStruct +} diff --git a/app/gosqs/get_queue_url_test.go b/app/gosqs/get_queue_url_test.go new file mode 100644 index 00000000..2dc70352 --- /dev/null +++ b/app/gosqs/get_queue_url_test.go @@ -0,0 +1,102 @@ +package gosqs + +import ( + "fmt" + "net/http" + "testing" + + "github.com/Admiral-Piett/goaws/app/conf" + "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/utils" + "github.com/stretchr/testify/assert" +) + +func TestGetQueueUrlV1_success(t *testing.T) { + conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "BaseUnitTests") + + defer func() { + utils.ResetApp() + utils.REQUEST_TRANSFORMER = utils.TransformRequest + }() + + utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) { + v := resultingStruct.(*models.GetQueueUrlRequest) + *v = models.GetQueueUrlRequest{ + QueueName: "unit-queue1", + QueueOwnerAWSAccountId: "fugafuga", + } + return true + } + + _, r := utils.GenerateRequestInfo( + "POST", + "/", + nil, + true) + code, response := GetQueueUrlV1(r) + + get_queue_url_response := response.(models.GetQueueUrlResponse) + + assert.Equal(t, http.StatusOK, code) + assert.Contains(t, get_queue_url_response.Result.QueueUrl, fmt.Sprintf("%s/%s", fixtures.BASE_URL, "unit-queue1")) + +} + +func TestGetQueueUrlV1_error_no_queue(t *testing.T) { + + conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "BaseUnitTests") + + defer func() { + utils.ResetApp() + utils.REQUEST_TRANSFORMER = utils.TransformRequest + }() + + utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) { + v := resultingStruct.(*models.GetQueueUrlRequest) + *v = models.GetQueueUrlRequest{ + QueueName: "not-exist-unit-queue1", + QueueOwnerAWSAccountId: "fugafuga", + } + return true + } + + _, r := utils.GenerateRequestInfo( + "POST", + "/", + nil, + true) + code, response := GetQueueUrlV1(r) + + expected := models.ErrorResult{ + Type: "Not Found", + Code: "AWS.SimpleQueueService.NonExistentQueue", + Message: "The specified queue does not exist for this wsdl version.", + } + + assert.Equal(t, http.StatusBadRequest, code) + assert.Equal(t, response.GetResult().(models.ErrorResult), expected) +} + +func TestGetQueueUrlV1_error_request_transformer(t *testing.T) { + + conf.LoadYamlConfig("../conf/mock-data/mock-config.yaml", "BaseUnitTests") + + defer func() { + utils.ResetApp() + utils.REQUEST_TRANSFORMER = utils.TransformRequest + }() + + utils.REQUEST_TRANSFORMER = func(resultingStruct interfaces.AbstractRequestBody, req *http.Request, emptyRequestValid bool) (success bool) { + return false + } + + _, r := utils.GenerateRequestInfo( + "POST", + "/", + nil, + true) + code, _ := GetQueueUrlV1(r) + assert.Equal(t, http.StatusBadRequest, code) +} diff --git a/app/gosqs/gosqs.go b/app/gosqs/gosqs.go index 033b3179..0fc32ece 100644 --- a/app/gosqs/gosqs.go +++ b/app/gosqs/gosqs.go @@ -362,29 +362,6 @@ func DeleteQueue(w http.ResponseWriter, req *http.Request) { } } -func GetQueueUrl(w http.ResponseWriter, req *http.Request) { - // Sent response type - w.Header().Set("Content-Type", "application/xml") - // - //// Retrieve FormValues required - queueName := req.FormValue("QueueName") - if queue, ok := app.SyncQueues.Queues[queueName]; ok { - url := queue.URL - log.Println("Get Queue URL:", queueName) - // Create, encode/xml and send response - result := app.GetQueueUrlResult{QueueUrl: url} - respStruct := app.GetQueueUrlResponse{"http://queue.amazonaws.com/doc/2012-11-05/", result, app.ResponseMetadata{RequestId: "00000000-0000-0000-0000-000000000000"}} - enc := xml.NewEncoder(w) - enc.Indent(" ", " ") - if err := enc.Encode(respStruct); err != nil { - log.Printf("error: %v\n", err) - } - } else { - log.Println("Get Queue URL:", queueName, ", queue does not exist!!!") - createErrorResponse(w, req, "QueueNotFound") - } -} - func getQueueFromPath(formVal string, theUrl string) string { if formVal != "" { return formVal diff --git a/app/models/models.go b/app/models/models.go index dcba66dc..6efd1501 100644 --- a/app/models/models.go +++ b/app/models/models.go @@ -242,6 +242,18 @@ func (r *SendMessageRequest) SetAttributesFromForm(values url.Values) { } } +// Get Queue Url Request +func NewGetQueueUrlRequest() *GetQueueUrlRequest { + return &GetQueueUrlRequest{} +} + +type GetQueueUrlRequest struct { + QueueName string `json:"QueueName"` + QueueOwnerAWSAccountId string `json:"QueueOwnerAWSAccountId"` // NOTE: not implemented +} + +func (r *GetQueueUrlRequest) SetAttributesFromForm(values url.Values) {} + func NewSetQueueAttributesRequest() *SetQueueAttributesRequest { return &SetQueueAttributesRequest{} } diff --git a/app/models/responses.go b/app/models/responses.go index a3f999d8..157f69bf 100644 --- a/app/models/responses.go +++ b/app/models/responses.go @@ -224,6 +224,25 @@ func (r DeleteMessageResponse) GetRequestId() string { return r.Metadata.RequestId } +/*** Get Queue Url Response */ +type GetQueueUrlResult struct { + QueueUrl string `xml:"QueueUrl,omitempty"` +} + +type GetQueueUrlResponse struct { + Xmlns string `xml:"xmlns,attr,omitempty"` + Result GetQueueUrlResult `xml:"GetQueueUrlResult"` + Metadata app.ResponseMetadata `xml:"ResponseMetadata,omitempty"` +} + +func (r GetQueueUrlResponse) GetResult() interface{} { + return r.Result +} + +func (r GetQueueUrlResponse) GetRequestId() string { + return r.Metadata.RequestId +} + type SetQueueAttributesResponse struct { Xmlns string `xml:"xmlns,attr,omitempty"` Metadata app.ResponseMetadata `xml:"ResponseMetadata,omitempty"` diff --git a/app/router/router.go b/app/router/router.go index ae8fc821..049db0ce 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -71,6 +71,7 @@ var routingTableV1 = map[string]func(r *http.Request) (int, interfaces.AbstractR "ReceiveMessage": sqs.ReceiveMessageV1, "ChangeMessageVisibility": sqs.ChangeMessageVisibilityV1, "DeleteMessage": sqs.DeleteMessageV1, + "GetQueueUrl": sqs.GetQueueUrlV1, "PurgeQueue": sqs.PurgeQueueV1, } @@ -78,7 +79,6 @@ var routingTable = map[string]http.HandlerFunc{ // SQS "SendMessageBatch": sqs.SendMessageBatch, "DeleteMessageBatch": sqs.DeleteMessageBatch, - "GetQueueUrl": sqs.GetQueueUrl, "DeleteQueue": sqs.DeleteQueue, // SNS diff --git a/app/router/router_test.go b/app/router/router_test.go index e53f1956..8f79a2b1 100644 --- a/app/router/router_test.go +++ b/app/router/router_test.go @@ -268,13 +268,13 @@ func TestActionHandler_v0_xml(t *testing.T) { "ReceiveMessage": sqs.ReceiveMessageV1, "DeleteMessage": sqs.DeleteMessageV1, "ChangeMessageVisibility": sqs.ChangeMessageVisibilityV1, + "GetQueueUrl": sqs.GetQueueUrlV1, "PurgeQueue": sqs.PurgeQueueV1, } routingTable = map[string]http.HandlerFunc{ // SQS "SendMessageBatch": sqs.SendMessageBatch, "DeleteMessageBatch": sqs.DeleteMessageBatch, - "GetQueueUrl": sqs.GetQueueUrl, "DeleteQueue": sqs.DeleteQueue, // SNS diff --git a/app/sqs_messages.go b/app/sqs_messages.go index 976bfec0..10fb0e01 100644 --- a/app/sqs_messages.go +++ b/app/sqs_messages.go @@ -59,17 +59,6 @@ type SendMessageBatchResponse struct { Metadata ResponseMetadata `xml:"ResponseMetadata,omitempty"` } -/*** Get Queue Url Response */ -type GetQueueUrlResult struct { - QueueUrl string `xml:"QueueUrl,omitempty"` -} - -type GetQueueUrlResponse struct { - Xmlns string `xml:"xmlns,attr,omitempty"` - Result GetQueueUrlResult `xml:"GetQueueUrlResult"` - Metadata ResponseMetadata `xml:"ResponseMetadata,omitempty"` -} - type SetQueueAttributesResponse struct { Xmlns string `xml:"xmlns,attr,omitempty"` Metadata ResponseMetadata `xml:"ResponseMetadata,omitempty"` diff --git a/smoke_tests/sqs_get_queue_url_test.go b/smoke_tests/sqs_get_queue_url_test.go new file mode 100644 index 00000000..1d075729 --- /dev/null +++ b/smoke_tests/sqs_get_queue_url_test.go @@ -0,0 +1,135 @@ +package smoke_tests + +import ( + "context" + "encoding/xml" + "fmt" + "net/http" + "testing" + + af "github.com/Admiral-Piett/goaws/app/fixtures" + "github.com/Admiral-Piett/goaws/app/models" + "github.com/Admiral-Piett/goaws/app/utils" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/sqs" + "github.com/gavv/httpexpect/v2" + "github.com/stretchr/testify/assert" +) + +func Test_GetQueueUrlV1_json_success_retrieve_queue_url(t *testing.T) { + + server := generateServer() + defer func() { + server.Close() + utils.ResetResources() + }() + + sdkConfig, _ := config.LoadDefaultConfig(context.TODO()) + sdkConfig.BaseEndpoint = aws.String(server.URL) + sqsClient := sqs.NewFromConfig(sdkConfig) + sqsClient.CreateQueue(context.TODO(), &sqs.CreateQueueInput{ + QueueName: &af.QueueName, + }) + + getQueueUrlOutput, _ := sqsClient.GetQueueUrl(context.TODO(), &sqs.GetQueueUrlInput{ + QueueName: &af.QueueName, + }) + assert.Contains(t, string(*getQueueUrlOutput.QueueUrl), fmt.Sprintf("%s/%s", af.BASE_URL, af.QueueName)) +} + +func Test_GetQueueUrlV1_json_error_not_found_queue(t *testing.T) { + + server := generateServer() + defer func() { + server.Close() + utils.ResetResources() + }() + + sdkConfig, _ := config.LoadDefaultConfig(context.TODO()) + sdkConfig.BaseEndpoint = aws.String(server.URL) + sqsClient := sqs.NewFromConfig(sdkConfig) + + getQueueUrlOutput, err := sqsClient.GetQueueUrl(context.TODO(), &sqs.GetQueueUrlInput{ + QueueName: &af.QueueName}) + + assert.Contains(t, err.Error(), "400") + assert.Contains(t, err.Error(), "AWS.SimpleQueueService.NonExistentQueue") + assert.Contains(t, err.Error(), "The specified queue does not exist for this wsdl version.") + assert.Nil(t, getQueueUrlOutput) +} + +func Test_GetQueueUrlV1_xml_success_retrieve_queue_url(t *testing.T) { + server := generateServer() + defer func() { + server.Close() + utils.ResetResources() + }() + + sdkConfig, _ := config.LoadDefaultConfig(context.TODO()) + sdkConfig.BaseEndpoint = aws.String(server.URL) + sqsClient := sqs.NewFromConfig(sdkConfig) + sqsClient.CreateQueue(context.TODO(), &sqs.CreateQueueInput{ + QueueName: &af.QueueName, + }) + + e := httpexpect.Default(t, server.URL) + + getQueueUrlRequestBodyXML := struct { + Action string `xml:"Action"` + QueueName string `xml:"QueueName"` + QueueOwnerAWSAccountId string `xml:"QueueOwnerAWSAccountId"` + Version string `xml:"Version"` + }{ + Action: "GetQueueUrl", + QueueName: af.QueueName, + QueueOwnerAWSAccountId: "hogehoge", + Version: "2012-11-05", + } + + r := e.POST("/"). + WithForm(getQueueUrlRequestBodyXML). + Expect(). + Status(http.StatusOK). + Body().Raw() + + r1 := models.GetQueueUrlResponse{} + xml.Unmarshal([]byte(r), &r1) + + assert.Contains(t, string(r1.Result.QueueUrl), fmt.Sprintf("%s/%s", af.BASE_URL, af.QueueName)) +} + +func Test_GetQueueUrlV1_xml_error_not_found_queue(t *testing.T) { + server := generateServer() + defer func() { + server.Close() + utils.ResetResources() + }() + + e := httpexpect.Default(t, server.URL) + + getQueueUrlRequestBodyXML := struct { + Action string `xml:"Action"` + QueueName string `xml:"QueueName"` + QueueOwnerAWSAccountId string `xml:"QueueOwnerAWSAccountId"` + Version string `xml:"Version"` + }{ + Action: "GetQueueUrl", + QueueName: af.QueueName, + QueueOwnerAWSAccountId: "hogehoge", + Version: "2012-11-05", + } + + r := e.POST("/"). + WithForm(getQueueUrlRequestBodyXML). + Expect(). + Status(http.StatusBadRequest). + Body().Raw() + + r1 := models.ErrorResponse{} + xml.Unmarshal([]byte(r), &r1) + + assert.Contains(t, r1.Result.Type, "Not Found") + assert.Contains(t, r1.Result.Code, "AWS.SimpleQueueService.NonExistentQueue") + assert.Contains(t, r1.Result.Message, "The specified queue does not exist for this wsdl version.") +}