TEST_F(QueueOperationTest, TestCreateAndDeleteQueue)
{
    CreateQueueRequest createQueueRequest;
    createQueueRequest.SetQueueName(BuildResourceName(BASE_SIMPLE_QUEUE_NAME));

    CreateQueueOutcome createQueueOutcome;
    bool shouldContinue = true;
    while (shouldContinue)
    {
        createQueueOutcome = sqsClient->CreateQueue(createQueueRequest);
        if (createQueueOutcome.IsSuccess()) break;
        if (createQueueOutcome.GetError().GetErrorType() == SQSErrors::QUEUE_DELETED_RECENTLY)
        {
            std::this_thread::sleep_for(std::chrono::seconds(10));
        }
        else
        {
            FAIL() << "Unexpected error response: " << createQueueOutcome.GetError().GetMessage();
        }
    }

    Aws::String queueUrl = createQueueOutcome.GetResult().GetQueueUrl();

    ASSERT_TRUE(queueUrl.find(createQueueRequest.GetQueueName()) != Aws::String::npos);

    createQueueRequest.AddAttributes(QueueAttributeName::VisibilityTimeout, "50");

    createQueueOutcome = sqsClient->CreateQueue(createQueueRequest);
    ASSERT_FALSE(createQueueOutcome.IsSuccess());
    SQSErrors error = createQueueOutcome.GetError().GetErrorType();
    EXPECT_TRUE(SQSErrors::QUEUE_NAME_EXISTS == error || SQSErrors::QUEUE_DELETED_RECENTLY == error);


    // This call in eventually consistent (sometimes over 1 min), so try it a few times
    for (int attempt = 0; ; attempt++)
    {
        ListQueuesRequest listQueueRequest;
        listQueueRequest.WithQueueNamePrefix(BuildResourcePrefix());

        ListQueuesOutcome listQueuesOutcome = sqsClient->ListQueues(listQueueRequest);
        if (listQueuesOutcome.IsSuccess())
        {
            ListQueuesResult listQueuesResult = listQueuesOutcome.GetResult();
            if (listQueuesResult.GetQueueUrls().size() == 1)
            {
                EXPECT_EQ(queueUrl, listQueuesResult.GetQueueUrls()[0]);
                EXPECT_TRUE(listQueuesResult.GetResponseMetadata().GetRequestId().length() > 0);
                break; // success!
            }
        }
        if (attempt >= 10) FAIL();
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    DeleteQueueRequest deleteQueueRequest;
    deleteQueueRequest.WithQueueUrl(queueUrl);

    DeleteQueueOutcome deleteQueueOutcome = sqsClient->DeleteQueue(deleteQueueRequest);
    ASSERT_TRUE(deleteQueueOutcome.IsSuccess());
}
TEST_F(QueueOperationTest, TestQueueAttributes)
{
    CreateQueueRequest createQueueRequest;
    createQueueRequest.SetQueueName(BuildResourceName(BASE_ATTRIBUTES_QUEUE_NAME));
    createQueueRequest.AddAttributes(QueueAttributeName::DelaySeconds, "45");

    CreateQueueOutcome createQueueOutcome = sqsClient->CreateQueue(createQueueRequest);
    ASSERT_TRUE(createQueueOutcome.IsSuccess());
    Aws::String queueUrl = createQueueOutcome.GetResult().GetQueueUrl();
    ASSERT_TRUE(queueUrl.find(createQueueRequest.GetQueueName()) != Aws::String::npos);

    GetQueueAttributesRequest queueAttributesRequest;
    queueAttributesRequest.AddAttributeNames(QueueAttributeName::DelaySeconds).WithQueueUrl(queueUrl);
    GetQueueAttributesOutcome queueAttributesOutcome = sqsClient->GetQueueAttributes(queueAttributesRequest);
    ASSERT_TRUE(queueAttributesOutcome.IsSuccess());
    EXPECT_EQ("45", queueAttributesOutcome.GetResult().GetAttributes().find(QueueAttributeName::DelaySeconds)->second);

    SetQueueAttributesRequest setQueueAttributesRequest;
    setQueueAttributesRequest.AddAttributes(QueueAttributeName::VisibilityTimeout, "42").WithQueueUrl(queueUrl);
    SetQueueAttributesOutcome setQueueAttributesOutcome = sqsClient->SetQueueAttributes(setQueueAttributesRequest);
    ASSERT_TRUE(setQueueAttributesOutcome.IsSuccess());

    queueAttributesRequest.AddAttributeNames(QueueAttributeName::VisibilityTimeout).WithQueueUrl(queueUrl);
    queueAttributesOutcome = sqsClient->GetQueueAttributes(queueAttributesRequest);
    ASSERT_TRUE(queueAttributesOutcome.IsSuccess());
    EXPECT_EQ("45", queueAttributesOutcome.GetResult().GetAttributes().find(QueueAttributeName::DelaySeconds)->second);
    EXPECT_EQ("42", queueAttributesOutcome.GetResult().GetAttributes().find(QueueAttributeName::VisibilityTimeout)->second);

    DeleteQueueRequest deleteQueueRequest;
    deleteQueueRequest.WithQueueUrl(queueUrl);

    DeleteQueueOutcome deleteQueueOutcome = sqsClient->DeleteQueue(deleteQueueRequest);
    ASSERT_TRUE(deleteQueueOutcome.IsSuccess());
}
TEST_F(QueueOperationTest, TestListDeadLetterSourceQueues)
{
    CreateQueueRequest createQueueRequest;
    createQueueRequest.SetQueueName(DEAD_LETTER_SOURCE_QUEUE_NAME);

    CreateQueueOutcome createQueueOutcome = sqsClient->CreateQueue(createQueueRequest);
    ASSERT_TRUE(createQueueOutcome.IsSuccess());
    Aws::String queueUrl = createQueueOutcome.GetResult().GetQueueUrl();

    createQueueRequest.SetQueueName(DEAD_LETTER_QUEUE_NAME);
    createQueueOutcome = sqsClient->CreateQueue(createQueueRequest);
    ASSERT_TRUE(createQueueOutcome.IsSuccess());
    Aws::String deadLetterQueueUrl = createQueueOutcome.GetResult().GetQueueUrl();

    GetQueueAttributesRequest queueAttributesRequest;
    queueAttributesRequest.AddAttributeNames(QueueAttributeName::QueueArn).WithQueueUrl(deadLetterQueueUrl);
    GetQueueAttributesOutcome queueAttributesOutcome = sqsClient->GetQueueAttributes(queueAttributesRequest);
    ASSERT_TRUE(queueAttributesOutcome.IsSuccess());
    Aws::String redrivePolicy = "{\"maxReceiveCount\":\"5\", \"deadLetterTargetArn\":\""
            + queueAttributesOutcome.GetResult().GetAttributes().find(QueueAttributeName::QueueArn)->second + "\"}";

    SetQueueAttributesRequest setQueueAttributesRequest;
    setQueueAttributesRequest.AddAttributes(QueueAttributeName::RedrivePolicy, redrivePolicy).WithQueueUrl(queueUrl);
    SetQueueAttributesOutcome setQueueAttributesOutcome = sqsClient->SetQueueAttributes(setQueueAttributesRequest);
    ASSERT_TRUE(setQueueAttributesOutcome.IsSuccess());

    ListDeadLetterSourceQueuesRequest listDeadLetterQueuesRequest;
    listDeadLetterQueuesRequest.WithQueueUrl(deadLetterQueueUrl);
    ListDeadLetterSourceQueuesOutcome listDeadLetterQueuesOutcome = sqsClient->ListDeadLetterSourceQueues(listDeadLetterQueuesRequest);
    ASSERT_TRUE(listDeadLetterQueuesOutcome.IsSuccess());

    //deadletter queue stuff is eventually consistent, let's try for 100 seconds or so.
    unsigned count = 0;
    bool found = listDeadLetterQueuesOutcome.GetResult().GetQueueUrls().size() == 1uL;

    while (listDeadLetterQueuesOutcome.IsSuccess() && !found && count++ < 100)
    {
        if (listDeadLetterQueuesOutcome.GetResult().GetQueueUrls().size() == 1uL)
        {
            found = true;
        }

        std::this_thread::sleep_for(std::chrono::seconds(1));
        listDeadLetterQueuesOutcome = sqsClient->ListDeadLetterSourceQueues(listDeadLetterQueuesRequest);        
    }

    ASSERT_TRUE(found);
    EXPECT_EQ(queueUrl, listDeadLetterQueuesOutcome.GetResult().GetQueueUrls()[0]);

    DeleteQueueRequest deleteQueueRequest;
    deleteQueueRequest.WithQueueUrl(queueUrl);

    DeleteQueueOutcome deleteQueueOutcome = sqsClient->DeleteQueue(deleteQueueRequest);
    ASSERT_TRUE(deleteQueueOutcome.IsSuccess());

    deleteQueueRequest.WithQueueUrl(deadLetterQueueUrl);
    deleteQueueOutcome = sqsClient->DeleteQueue(deleteQueueRequest);
    ASSERT_TRUE(deleteQueueOutcome.IsSuccess());
}
TEST_F(QueueOperationTest, ChangeMessageVisibilityBatch)
{
  CreateQueueRequest createQueueRequest;
  createQueueRequest.SetQueueName(BuildResourceName(BASE_CHANGE_MESSAGE_VISIBILITY_BATCH_QUEUE_NAME));

  auto createQueueOutcome = sqsClient->CreateQueue(createQueueRequest);
  ASSERT_TRUE(createQueueOutcome.IsSuccess());
  auto queueUrl = createQueueOutcome.GetResult().GetQueueUrl();

  SendMessageBatchRequestEntry sendMessageBatchRequestEntry_1;
  SendMessageBatchRequestEntry sendMessageBatchRequestEntry_2;
  SendMessageBatchRequestEntry sendMessageBatchRequestEntry_3;
  SendMessageBatchRequest sendMessageBatchRequest;
  sendMessageBatchRequest
    .AddEntries(sendMessageBatchRequestEntry_1.WithMessageBody("TestMessageBody_1").WithId("TestMessageId_1"))
    .AddEntries(sendMessageBatchRequestEntry_2.WithMessageBody("TestMessageBody_2").WithId("TestMessageId_2"))
    .AddEntries(sendMessageBatchRequestEntry_3.WithMessageBody("TestMessageBody_3").WithId("TestMessageId_3"))
    .WithQueueUrl(queueUrl);

  auto sendMessageBatchOutcome = sqsClient->SendMessageBatch(sendMessageBatchRequest);
  ASSERT_TRUE(sendMessageBatchOutcome.IsSuccess());
  ASSERT_EQ(3u, sendMessageBatchOutcome.GetResult().GetSuccessful().size());

  ReceiveMessageRequest receiveMessageRequest;
  receiveMessageRequest
    .WithQueueUrl(queueUrl)
    .WithMaxNumberOfMessages(3);

  Vector<Message> messages;
  while (messages.size() < 3u)
  {
    auto receiveMessageOutcome = sqsClient->ReceiveMessage(receiveMessageRequest);
    ASSERT_TRUE(receiveMessageOutcome.IsSuccess());
    for (auto& message : receiveMessageOutcome.GetResult().GetMessages())
    {
      messages.push_back(message);
    }
  }
  ASSERT_EQ(3u, messages.size());

  ChangeMessageVisibilityBatchRequest changeMessageVisibilityBatchRequest;
  auto haveSetOneValidTime = false;
  for (auto& message : messages)
  {
    ChangeMessageVisibilityBatchRequestEntry changeMessageVisibilityBatchRequestEntry;
    changeMessageVisibilityBatchRequestEntry
      .WithId(message.GetMessageId())
      .WithReceiptHandle(message.GetReceiptHandle());
    if (haveSetOneValidTime)
    {
      // Not legal. There's a maximum time of 12 hours.
      changeMessageVisibilityBatchRequestEntry.SetVisibilityTimeout(50000);
    }
    else
    {
      // Legal
      changeMessageVisibilityBatchRequestEntry.SetVisibilityTimeout(1000);
      haveSetOneValidTime = true;
    }
    changeMessageVisibilityBatchRequest.AddEntries(changeMessageVisibilityBatchRequestEntry);
  }
  changeMessageVisibilityBatchRequest.WithQueueUrl(queueUrl);
  auto changeMessageVisibilityBatchOutcome = sqsClient->ChangeMessageVisibilityBatch(changeMessageVisibilityBatchRequest);
  ASSERT_TRUE(changeMessageVisibilityBatchOutcome.IsSuccess());
  EXPECT_EQ(2u, changeMessageVisibilityBatchOutcome.GetResult().GetFailed().size());
  EXPECT_EQ(1u, changeMessageVisibilityBatchOutcome.GetResult().GetSuccessful().size());

  for (auto& batchResultErrorEntry : changeMessageVisibilityBatchOutcome.GetResult().GetFailed())
  {
    EXPECT_EQ("InvalidParameterValue", batchResultErrorEntry.GetCode());
    EXPECT_TRUE(batchResultErrorEntry.GetSenderFault());
  }

  DeleteQueueRequest deleteQueueRequest;
  deleteQueueRequest.WithQueueUrl(queueUrl);

  auto deleteQueueOutcome = sqsClient->DeleteQueue(deleteQueueRequest);
  ASSERT_TRUE(deleteQueueOutcome.IsSuccess());
}