// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs

import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.runInEdtAndWait
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.stub
import software.amazon.awssdk.awscore.exception.AwsServiceException
import software.amazon.awssdk.services.sqs.SqsClient
import software.amazon.awssdk.services.sqs.model.QueueAttributeName
import software.amazon.awssdk.services.sqs.model.SetQueueAttributesRequest
import software.amazon.awssdk.services.sqs.model.SetQueueAttributesResponse
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
import software.aws.toolkits.jetbrains.core.region.getDefaultRegion

class EditAttributesDialogTest {
    lateinit var client: SqsClient
    lateinit var queue: Queue

    @Rule
    @JvmField
    val projectRule = ProjectRule()

    @JvmField
    @Rule
    val mockClientManagerRule = MockClientManagerRule()

    @Before
    fun setUp() {
        client = mockClientManagerRule.create()
        queue = Queue("https://sqs.us-east-1.amazonaws.com/123456789012/test", getDefaultRegion())
    }

    @Test
    fun `Empty field fails`() {
        runInEdtAndWait {
            listOf(
                buildDialog(testRetentionPeriod = null),
                buildDialog(testMessageSize = null)
            ).forEach { dialog ->
                assertThat(dialog.validate()).isNotNull()
            }
        }
    }

    @Test
    fun `Value out of bound fails`() {
        runInEdtAndWait {
            listOf(
                buildDialog(visibilityTimeout = MAX_VISIBILITY_TIMEOUT + 1),
                buildDialog(visibilityTimeout = MIN_VISIBILITY_TIMEOUT - 1),
                buildDialog(maxDeliveryDelay = MAX_DELIVERY_DELAY + 1),
                buildDialog(maxDeliveryDelay = MIN_DELIVERY_DELAY - 1),
                buildDialog(waitTime = MAX_WAIT_TIME + 1),
                buildDialog(waitTime = MIN_WAIT_TIME - 1),
                buildDialog(testRetentionPeriod = MAX_RETENTION_PERIOD + 1),
                buildDialog(testRetentionPeriod = MIN_RETENTION_PERIOD - 1),
                buildDialog(testMessageSize = MAX_MESSAGE_SIZE_LIMIT + 1),
                buildDialog(testMessageSize = MIN_MESSAGE_SIZE_LIMIT - 1)
            ).forEach { dialog ->
                assertThat(dialog.validate()).isNotNull()
            }
        }
    }

    @Test
    fun `Editing queue parameters succeeds`() {
        val attributesCaptor = argumentCaptor<SetQueueAttributesRequest>()
        client.stub {
            on { setQueueAttributes(attributesCaptor.capture()) } doReturn SetQueueAttributesResponse.builder().build()
        }

        runInEdtAndWait {
            buildDialog().updateAttributes()
        }

        val updatedAttributes = attributesCaptor.firstValue.attributes()
        assertThat(updatedAttributes[QueueAttributeName.VISIBILITY_TIMEOUT]).isEqualTo(MAX_VISIBILITY_TIMEOUT.toString())
        assertThat(updatedAttributes[QueueAttributeName.MAXIMUM_MESSAGE_SIZE]).isEqualTo(MAX_MESSAGE_SIZE_LIMIT.toString())
        assertThat(updatedAttributes[QueueAttributeName.MESSAGE_RETENTION_PERIOD]).isEqualTo(MAX_RETENTION_PERIOD.toString())
        assertThat(updatedAttributes[QueueAttributeName.DELAY_SECONDS]).isEqualTo(MAX_DELIVERY_DELAY.toString())
        assertThat(updatedAttributes[QueueAttributeName.RECEIVE_MESSAGE_WAIT_TIME_SECONDS]).isEqualTo(MAX_WAIT_TIME.toString())
    }

    @Test
    fun `Error editing queue parameters`() {
        val message = "Internal error"

        client.stub {
            on { setQueueAttributes(any<SetQueueAttributesRequest>()) } doThrow AwsServiceException.builder().message(message).build()
        }

        runInEdtAndWait {
            assertThatThrownBy { buildDialog().updateAttributes() }.hasMessage(message)
        }
    }

    private fun buildDialog(
        visibilityTimeout: Int = MAX_VISIBILITY_TIMEOUT,
        maxDeliveryDelay: Int = MAX_DELIVERY_DELAY,
        waitTime: Int = MAX_WAIT_TIME,
        testRetentionPeriod: Int? = MAX_RETENTION_PERIOD,
        testMessageSize: Int? = MAX_MESSAGE_SIZE_LIMIT
    ) = EditAttributesDialog(projectRule.project, client, queue, mapOf()).apply {
        view.visibilityTimeout.value = visibilityTimeout
        view.messageSize.text = testMessageSize?.toString() ?: ""
        view.retentionPeriod.text = testRetentionPeriod?.toString() ?: ""
        view.deliveryDelay.value = maxDeliveryDelay
        view.waitTime.value = waitTime
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs

import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test
import software.aws.toolkits.core.region.AwsRegion

class QueueTest {
    private val defaultRegion = AwsRegion("us-east-1", "US East (N. Virginia)", "aws")

    @Test
    fun `China region endpoint parsed`() {
        val queueRegion = AwsRegion("cn-northwest-1", "China (Ningxia)", "aws-cn")
        val queue = Queue("https://sqs.cn-northwest-1.amazonaws.com.cn/123456789012/test-1", queueRegion)

        assertThat(queue.arn).isEqualTo("arn:aws-cn:sqs:cn-northwest-1:123456789012:test-1")
        assertThat(queue.accountId).isEqualTo("123456789012")
        assertThat(queue.queueName).isEqualTo("test-1")
    }

    @Test
    fun `GovCloud region endpoint parsed`() {
        val queueRegion = AwsRegion("us-gov-east-1", "AWS GovCloud (US-East)", "aws-us-gov")
        val queue = Queue("https://sqs.us-gov-east-1.amazonaws.com/123456789012/test-2", queueRegion)

        assertThat(queue.arn).isEqualTo("arn:aws-us-gov:sqs:us-gov-east-1:123456789012:test-2")
        assertThat(queue.accountId).isEqualTo("123456789012")
        assertThat(queue.queueName).isEqualTo("test-2")
    }

    @Test
    fun `AWS region endpoint parsed`() {
        val queueRegion = AwsRegion("us-west-2", "US West (Oregon)", "aws")
        val queue = Queue("https://sqs.us-west-2.amazonaws.com/123456789012/test-_3", queueRegion)

        assertThat(queue.arn).isEqualTo("arn:aws:sqs:us-west-2:123456789012:test-_3")
        assertThat(queue.accountId).isEqualTo("123456789012")
        assertThat(queue.queueName).isEqualTo("test-_3")
    }

    @Test
    fun `Throws exception with non-url`() {
        assertThatThrownBy { Queue("Not a URL", defaultRegion) }.isInstanceOf(IllegalArgumentException::class.java)
    }

    @Test
    fun `Throws exception with no name`() {
        assertThatThrownBy { Queue("https://sqs.us-east-1.amazonaws.com/123456789012/", defaultRegion) }.isInstanceOf(IllegalArgumentException::class.java)
    }

    @Test
    fun `Throws exception with invalid account ID`() {
        assertThatThrownBy { Queue("https://sqs.us-east-1.amazonaws.com/123/test-4", defaultRegion) }.isInstanceOf(IllegalArgumentException::class.java)
    }

    @Test
    fun `Throws exception with blank account ID`() {
        assertThatThrownBy {
            Queue(
                "https://sqs.us-east-1.amazonaws.com/            /test_a",
                defaultRegion
            )
        }.isInstanceOf(IllegalArgumentException::class.java)
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs

import com.intellij.testFramework.ProjectRule
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import software.aws.toolkits.jetbrains.core.MockResourceCacheRule
import software.aws.toolkits.jetbrains.core.explorer.nodes.AwsExplorerEmptyNode
import software.aws.toolkits.jetbrains.core.explorer.nodes.AwsExplorerErrorNode
import software.aws.toolkits.jetbrains.core.explorer.nodes.SqsExplorerRootNode
import software.aws.toolkits.jetbrains.services.sqs.resources.SqsResources
import java.util.concurrent.CompletableFuture

class SqsServiceNodeTest {
    @JvmField
    @Rule
    val projectRule = ProjectRule()

    @JvmField
    @Rule
    val resourceCache = MockResourceCacheRule()

    @Test
    fun `Sqs queues are listed`() {
        resourceCache.addEntry(
            projectRule.project,
            SqsResources.LIST_QUEUE_URLS,
            listOf(
                "https://sqs.us-east-1.amazonaws.com/123456789012/test2",
                "https://sqs.us-east-1.amazonaws.com/123456789012/test4",
                "https://sqs.us-east-1.amazonaws.com/123456789012/test3",
                "https://sqs.us-east-1.amazonaws.com/123456789012/test1"
            )
        )

        val children = SqsServiceNode(projectRule.project, SQS_EXPLORER_NODE).children

        assertThat(children).allMatch { it is SqsQueueNode }
        assertThat(children.filterIsInstance<SqsQueueNode>().map { it.displayName() }).containsExactlyInAnyOrder("test4", "test3", "test2", "test1")
        assertThat(children.filterIsInstance<SqsQueueNode>().map { it.resourceArn() }).containsExactlyInAnyOrder(
            "arn:aws:sqs:us-east-1:123456789012:test1",
            "arn:aws:sqs:us-east-1:123456789012:test2",
            "arn:aws:sqs:us-east-1:123456789012:test3",
            "arn:aws:sqs:us-east-1:123456789012:test4"
        )
    }

    @Test
    fun `No queues listed`() {
        resourceCache.addEntry(projectRule.project, SqsResources.LIST_QUEUE_URLS, listOf())
        val children = SqsServiceNode(projectRule.project, SQS_EXPLORER_NODE).children
        assertThat(children).singleElement().isInstanceOf(AwsExplorerEmptyNode::class.java)
    }

    @Test
    fun `Error loading queues`() {
        resourceCache.addEntry(projectRule.project, SqsResources.LIST_QUEUE_URLS, CompletableFuture.failedFuture(RuntimeException("Simulated error")))
        val children = SqsServiceNode(projectRule.project, SQS_EXPLORER_NODE).children
        assertThat(children).singleElement().isInstanceOf(AwsExplorerErrorNode::class.java)
    }

    private companion object {
        val SQS_EXPLORER_NODE = SqsExplorerRootNode()
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs

import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.TestActionEvent
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import software.amazon.awssdk.services.sqs.SqsClient
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
import software.aws.toolkits.jetbrains.services.sqs.actions.SubscribeSnsAction

class SubscribeSnsActionTest {
    lateinit var client: SqsClient

    @Rule
    @JvmField
    val projectRule = ProjectRule()

    @JvmField
    @Rule
    val mockClientManagerRule = MockClientManagerRule()

    @Before
    fun setup() {
        client = mockClientManagerRule.create()
    }

    @Test
    fun `Standard queue shows subscribe action`() {
        val mockNode = SqsQueueNode(projectRule.project, STANDARD_QUEUE_URL)
        val action = TestActionEvent()
        SubscribeSnsAction().update(mockNode, action)
        assertThat(action.presentation.isVisible).isTrue()
    }

    @Test
    fun `FIFO queue doesn't show subscribe action`() {
        val mockNode = SqsQueueNode(projectRule.project, FIFO_QUEUE_URL)
        val action = TestActionEvent()
        SubscribeSnsAction().update(mockNode, action)
        assertThat(action.presentation.isVisible).isFalse()
    }

    private companion object {
        const val STANDARD_QUEUE_URL = "https://sqs.us-east-1.amazonaws.com/123456789012/standard"
        const val FIFO_QUEUE_URL = "https://sqs.us-east-1.amazonaws.com/123456789012/fifo.fifo"
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs

import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.runInEdtAndWait
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.stub
import software.amazon.awssdk.services.iam.IamClient
import software.amazon.awssdk.services.sns.SnsClient
import software.amazon.awssdk.services.sns.model.InternalErrorException
import software.amazon.awssdk.services.sns.model.SubscribeRequest
import software.amazon.awssdk.services.sns.model.SubscribeResponse
import software.amazon.awssdk.services.sqs.SqsClient
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesRequest
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesResponse
import software.amazon.awssdk.services.sqs.model.QueueAttributeName
import software.aws.toolkits.core.region.AwsRegion
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule

class SubscribeSnsDialogTest {
    lateinit var snsClient: SnsClient
    lateinit var sqsClient: SqsClient
    lateinit var iamClient: IamClient
    lateinit var region: AwsRegion
    lateinit var queue: Queue

    @Rule
    @JvmField
    val projectRule = ProjectRule()

    @JvmField
    @Rule
    val mockClientManagerRule = MockClientManagerRule()

    @JvmField
    @Rule
    val regionProvider = MockRegionProviderRule()

    @Before
    fun setup() {
        snsClient = mockClientManagerRule.create()
        sqsClient = mockClientManagerRule.create()
        iamClient = mockClientManagerRule.create()
        sqsClient.stub {
            on { getQueueAttributes(any<GetQueueAttributesRequest>()) } doReturn GetQueueAttributesResponse.builder().attributes(
                mutableMapOf<QueueAttributeName, String?>(
                    QueueAttributeName.POLICY to null
                )
            ).build()
        }

        region = regionProvider.defaultRegion()
        queue = Queue("https://sqs.us-east-1.amazonaws.com/123456789012/test", region)
    }

    @Test
    fun `No topic specified fails`() {
        runInEdtAndWait {
            val dialog = SubscribeSnsDialog(projectRule.project, queue)
            val validationInfo = dialog.validate()
            assertThat(validationInfo).isNotNull()
        }
    }

    @Test
    fun `Error subscribing to topic`() {
        val subscribeCaptor = argumentCaptor<SubscribeRequest>()
        snsClient.stub {
            on { subscribe(subscribeCaptor.capture()) } doThrow InternalErrorException.builder().message(ERROR_MESSAGE).build()
        }

        runInEdtAndWait {
            val dialog = SubscribeSnsDialog(projectRule.project, queue)
            assertThatThrownBy { dialog.subscribe(TOPIC_ARN) }.hasMessage(ERROR_MESSAGE)
        }
        assertThat(subscribeCaptor.firstValue.topicArn()).isEqualTo(TOPIC_ARN)
    }

    @Test
    fun `Subscribing to topic succeeds`() {
        val subscribeCaptor = argumentCaptor<SubscribeRequest>()
        snsClient.stub {
            on { subscribe(subscribeCaptor.capture()) } doReturn SubscribeResponse.builder().build()
        }

        runInEdtAndWait {
            SubscribeSnsDialog(projectRule.project, queue).subscribe(TOPIC_ARN)
        }
        assertThat(subscribeCaptor.firstValue.topicArn()).isEqualTo(TOPIC_ARN)
    }

    private companion object {
        const val TOPIC_ARN = "arn:aws:sns:us-east-1:123456789012:MyTopic"
        const val ERROR_MESSAGE = "Network Error"
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs.toolwindow

import com.intellij.testFramework.DisposableRule
import com.intellij.testFramework.ProjectRule
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito
import org.mockito.kotlin.whenever
import software.amazon.awssdk.services.sqs.SqsClient
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesRequest
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesResponse
import software.amazon.awssdk.services.sqs.model.Message
import software.amazon.awssdk.services.sqs.model.MessageSystemAttributeName
import software.amazon.awssdk.services.sqs.model.QueueAttributeName
import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest
import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse
import software.aws.toolkits.core.region.anAwsRegion
import software.aws.toolkits.core.utils.test.aString
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
import software.aws.toolkits.jetbrains.services.sqs.Queue
import software.aws.toolkits.jetbrains.utils.waitForModelToBeAtLeast
import software.aws.toolkits.jetbrains.utils.waitForTrue
import software.aws.toolkits.resources.message

class PollMessagePaneTest {
    @Rule
    @JvmField
    val projectRule = ProjectRule()

    @Rule
    @JvmField
    val mockClientManagerRule = MockClientManagerRule()

    @Rule
    @JvmField
    val disposableRule = DisposableRule()

    private val queue = Queue("https://sqs.us-east-1.amazonaws.com/123456789012/test1", anAwsRegion())

    @Test
    fun `Message received`() {
        val client = mockClientManagerRule.create<SqsClient>()
        val message = aMessage()
        whenever(client.receiveMessage(Mockito.any<ReceiveMessageRequest>())).thenReturn(
            ReceiveMessageResponse.builder().messages(message).build()
        )
        val pane = PollMessagePane(projectRule.project, client, queue)
        val tableModel = pane.messagesTable.tableModel
        runBlocking {
            pane.requestMessages()
            tableModel.waitForModelToBeAtLeast(1)
        }

        assertThat(tableModel.items.first()).isEqualTo(message)
    }

    @Test
    fun `Messages are de-duplicated by id`() {
        val client = mockClientManagerRule.create<SqsClient>()
        val message = aMessage()
        val anotherMessage = aMessage()
        whenever(client.receiveMessage(Mockito.any<ReceiveMessageRequest>())).thenReturn(
            ReceiveMessageResponse.builder().messages(
                message,
                message,
                anotherMessage
            ).build()
        )
        val pane = PollMessagePane(projectRule.project, client, queue)
        val tableModel = pane.messagesTable.tableModel
        runBlocking {
            pane.requestMessages()
            tableModel.waitForModelToBeAtLeast(1)
        }

        assertThat(tableModel.items).hasSize(2)
        assertThat(tableModel.items.map { it.messageId() }).contains(message.messageId(), anotherMessage.messageId())
    }

    @Test
    fun `No messages received`() {
        val client = mockClientManagerRule.create<SqsClient>()
        whenever(client.receiveMessage(Mockito.any<ReceiveMessageRequest>())).thenReturn(
            ReceiveMessageResponse.builder().build()
        )
        val pane = PollMessagePane(projectRule.project, client, queue)
        runBlocking {
            pane.requestMessages()
            waitForTrue { pane.messagesTable.table.emptyText.text == message("sqs.message.no_messages") }
        }

        assertThat(pane.messagesTable.tableModel.items.size).isZero()
    }

    @Test
    fun `Error receiving messages`() {
        val client = mockClientManagerRule.create<SqsClient>()
        whenever(client.receiveMessage(Mockito.any<ReceiveMessageRequest>())).then {
            throw IllegalStateException("Network Error")
        }
        val pane = PollMessagePane(projectRule.project, client, queue)
        runBlocking {
            pane.requestMessages()
            waitForTrue { pane.messagesTable.table.emptyText.text == message("sqs.failed_to_poll_messages") }
        }

        assertThat(pane.messagesTable.table.listTableModel.items.size).isZero
    }

    @Test
    fun `Available messages are displayed`() {
        val client = mockClientManagerRule.create<SqsClient>()
        whenever(client.getQueueAttributes(Mockito.any<GetQueueAttributesRequest>())).thenReturn(
            GetQueueAttributesResponse.builder().attributes(mutableMapOf(QueueAttributeName.APPROXIMATE_NUMBER_OF_MESSAGES to "10")).build()
        )
        val pane = PollMessagePane(projectRule.project, client, queue)
        runBlocking {
            pane.getAvailableMessages()
        }

        assertThat(pane.messagesAvailableLabel.text).isEqualTo(message("sqs.messages.available.text", 10))
    }

    @Test
    fun `Error displaying messages available`() {
        val client = mockClientManagerRule.create<SqsClient>()
        whenever(client.getQueueAttributes(Mockito.any<GetQueueAttributesRequest>())).then {
            throw IllegalStateException("Network Error")
        }
        val pane = PollMessagePane(projectRule.project, client, queue)
        runBlocking {
            pane.getAvailableMessages()
        }

        assertThat(pane.messagesAvailableLabel.text).isEqualTo(message("sqs.failed_to_load_total"))
    }

    private fun aMessage(): Message = Message.builder()
        .body(aString())
        .messageId(aString())
        .attributes(mapOf(Pair(MessageSystemAttributeName.SENDER_ID, "1234567890:test1"), Pair(MessageSystemAttributeName.SENT_TIMESTAMP, "111111111")))
        .build()
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs.toolwindow

import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.runInEdtAndWait
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import software.amazon.awssdk.services.sqs.model.Message
import software.amazon.awssdk.services.sqs.model.MessageSystemAttributeName
import software.aws.toolkits.core.utils.RuleUtils

class PollMessageUtilsTest {
    @JvmField
    @Rule
    val projectRule = ProjectRule()

    @Test
    fun `Message mapped to columns as expected`() {
        val message = Message.builder()
            .body(RuleUtils.randomName(length = 10))
            .messageId("ABC")
            .attributes(
                mapOf(
                    Pair(MessageSystemAttributeName.SENDER_ID, "1234567890:test1"),
                    Pair(MessageSystemAttributeName.SENT_TIMESTAMP, "111111111")
                )
            )
            .build()
        val table = MessagesTable().apply {
            runInEdtAndWait {
                tableModel.addRow(message)
            }
        }

        assertThat(table.tableModel.items.size).isOne()
        assertThat(table.tableModel.items.first().body()).isEqualTo(message.body())
        assertThat(table.tableModel.items.first().messageId()).isEqualTo(message.messageId())
        assertThat(table.tableModel.items.first().attributes().getValue(MessageSystemAttributeName.SENDER_ID)).isEqualTo("1234567890:test1")
        assertThat(table.tableModel.items.first().attributes().getValue(MessageSystemAttributeName.SENT_TIMESTAMP)).isEqualTo("111111111")
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.sqs.toolwindow

import com.intellij.testFramework.DisposableRule
import com.intellij.testFramework.ProjectRule
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito
import org.mockito.kotlin.whenever
import software.amazon.awssdk.services.sqs.SqsClient
import software.amazon.awssdk.services.sqs.model.SendMessageRequest
import software.amazon.awssdk.services.sqs.model.SendMessageResponse
import software.aws.toolkits.core.region.AwsRegion
import software.aws.toolkits.core.utils.RuleUtils
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule
import software.aws.toolkits.jetbrains.services.sqs.MAX_LENGTH_OF_FIFO_ID
import software.aws.toolkits.jetbrains.services.sqs.Queue
import software.aws.toolkits.jetbrains.utils.waitForTrue
import software.aws.toolkits.resources.message

class SendMessagePaneTest {
    @Rule
    @JvmField
    val projectRule = ProjectRule()

    @Rule
    @JvmField
    val mockClientManagerRule = MockClientManagerRule()

    @Rule
    @JvmField
    val disposableRule = DisposableRule()

    @Rule
    @JvmField
    val mockClientManager = MockClientManagerRule()

    @Rule
    @JvmField
    val regionProvider = MockRegionProviderRule()

    private lateinit var client: SqsClient
    private lateinit var region: AwsRegion
    private lateinit var standardQueue: Queue
    private lateinit var fifoQueue: Queue
    private lateinit var standardPane: SendMessagePane
    private lateinit var fifoPane: SendMessagePane

    @Before
    fun reset() {
        client = mockClientManager.create()
        region = regionProvider.defaultRegion()
        standardQueue = Queue("https://sqs.us-east-1.amazonaws.com/123456789012/standard", region)
        fifoQueue = Queue("https://sqs.us-east-1.amazonaws.com/123456789012/fifo.fifo", region)
        standardPane = SendMessagePane(projectRule.project, client, standardQueue, disposableRule.disposable)
        fifoPane = SendMessagePane(projectRule.project, client, fifoQueue, disposableRule.disposable)
    }

    @Test
    fun `No input fails to send for standard`() {
        standardPane.apply {
            inputText.text = ""
        }

        assertThat(runBlocking { standardPane.validateFields() }).isFalse()
        assertThat(standardPane.fifoFields.component.isVisible).isFalse()
    }

    @Test
    fun `No input fails to send for fifo`() {
        fifoPane.apply {
            inputText.text = ""
            fifoFields.deduplicationId.text = ""
            fifoFields.groupId.text = ""
        }

        runBlocking {
            assertThat(fifoPane.validateFields()).isFalse()
        }
    }

    @Test
    fun `No deduplication ID fails to send for fifo`() {
        fifoPane.apply {
            inputText.text = MESSAGE
            fifoFields.deduplicationId.text = ""
            fifoFields.groupId.text = GROUP_ID
        }

        assertThat(runBlocking { fifoPane.validateFields() }).isFalse()
    }

    @Test
    fun `No group ID fails to send for fifo`() {
        fifoPane.apply {
            inputText.text = MESSAGE
            fifoFields.deduplicationId.text = DEDUPLICATION_ID
            fifoFields.groupId.text = ""
        }

        runBlocking { fifoPane.sendMessage() }

        assertThat(runBlocking { fifoPane.validateFields() }).isFalse()
    }

    @Test
    fun `ID too long fails`() {
        fifoPane.apply {
            inputText.text = MESSAGE
            fifoFields.deduplicationId.text = RuleUtils.randomName(length = MAX_LENGTH_OF_FIFO_ID + 1)
            fifoFields.groupId.text = GROUP_ID
        }

        runBlocking { fifoPane.sendMessage() }

        assertThat(runBlocking { fifoPane.validateFields() }).isFalse()
    }

    @Test
    fun `Error sending message`() {
        whenever(client.sendMessage(Mockito.any<SendMessageRequest>())).then {
            throw IllegalStateException("Network Error")
        }

        standardPane.apply {
            inputText.text = MESSAGE
        }

        runBlocking {
            standardPane.sendMessage()
            waitForTrue { standardPane.messageSentLabel.isVisible }
        }

        assertThat(standardPane.messageSentLabel.text).isEqualTo(message("sqs.failed_to_send_message"))
    }

    @Test
    fun `Message sent for standard`() {
        whenever(client.sendMessage(Mockito.any<SendMessageRequest>())).thenReturn(
            SendMessageResponse.builder().messageId(MESSAGE_ID).build()
        )
        standardPane.apply {
            inputText.text = MESSAGE
        }

        runBlocking {
            standardPane.sendMessage()
            waitForTrue { standardPane.messageSentLabel.isVisible }
        }

        assertThat(standardPane.messageSentLabel.text).isEqualTo(message("sqs.send.message.success", MESSAGE_ID))
    }

    @Test
    fun `Message sent for fifo`() {
        whenever(client.sendMessage(Mockito.any<SendMessageRequest>())).thenReturn(
            SendMessageResponse.builder().messageId(MESSAGE_ID).build()
        )
        fifoPane.apply {
            inputText.text = MESSAGE
            fifoFields.deduplicationId.text = DEDUPLICATION_ID
            fifoFields.groupId.text = GROUP_ID
        }

        runBlocking {
            fifoPane.sendMessage()
            waitForTrue { fifoPane.messageSentLabel.isVisible }
        }

        assertThat(fifoPane.messageSentLabel.text).isEqualTo(message("sqs.send.message.success", MESSAGE_ID))
    }

    private companion object {
        const val MESSAGE_ID = "123"
        const val MESSAGE = "Message body"
        const val DEDUPLICATION_ID = "Deduplication ID"
        const val GROUP_ID = "Group Id"
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.telemetry

import com.intellij.testFramework.ApplicationRule
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials
import software.amazon.awssdk.services.cognitoidentity.CognitoIdentityClient
import software.amazon.awssdk.services.cognitoidentity.model.Credentials
import software.amazon.awssdk.services.cognitoidentity.model.GetCredentialsForIdentityRequest
import software.amazon.awssdk.services.cognitoidentity.model.GetCredentialsForIdentityResponse
import software.amazon.awssdk.services.cognitoidentity.model.GetIdRequest
import software.amazon.awssdk.services.cognitoidentity.model.GetIdResponse
import software.aws.toolkits.core.telemetry.CachedIdentityStorage
import software.aws.toolkits.core.utils.delegateMock
import java.time.Instant
import java.time.temporal.ChronoUnit

class AwsCognitoCredentialsProviderTest {
    @Rule
    @JvmField
    val application = ApplicationRule()

    private val cognitoClient = delegateMock<CognitoIdentityClient>()
    private val storage = mock<CachedIdentityStorage>()
    private val getCredentialsRequestCaptor = argumentCaptor<GetCredentialsForIdentityRequest>()
    private val getIdRequestCaptor = argumentCaptor<GetIdRequest>()

    @Test
    fun testGetCredentials() {
        val getCredentialsResult = GetCredentialsForIdentityResponse.builder()
            .credentials(CREDENTIALS)
            .build()

        cognitoClient.stub {
            on { getId(getIdRequestCaptor.capture()) }.thenReturn(GET_ID_RESULT)
            on { getCredentialsForIdentity(getCredentialsRequestCaptor.capture()) }.thenReturn(getCredentialsResult)
        }

        val provider = AwsCognitoCredentialsProvider(IDENTITY_POOL_ID, cognitoClient)
        val awsCredentials = provider.resolveCredentials() as AwsSessionCredentials

        assertThat(getIdRequestCaptor.firstValue.identityPoolId()).isEqualTo(IDENTITY_POOL_ID)
        assertThat(getCredentialsRequestCaptor.firstValue.identityId()).isEqualTo(IDENTITY_ID)

        assertThat(awsCredentials.accessKeyId()).isEqualTo(ACCESS_KEY)
        assertThat(awsCredentials.secretAccessKey()).isEqualTo(SECRET_KEY)
        assertThat(awsCredentials.sessionToken()).isEqualTo(SESSION_TOKEN)
    }

    @Test
    fun testGetCredentialsNotExpired() {
        val notExpiredCredentials = Credentials.builder()
            .accessKeyId(ACCESS_KEY)
            .secretKey(SECRET_KEY)
            .sessionToken(SESSION_TOKEN)
            .expiration(Instant.now().plus(1, ChronoUnit.HOURS))
            .build()

        val getCredentialsResult = GetCredentialsForIdentityResponse.builder()
            .credentials(notExpiredCredentials)
            .build()

        cognitoClient.stub {
            on { getId(getIdRequestCaptor.capture()) }.thenReturn(GET_ID_RESULT)
            on { getCredentialsForIdentity(getCredentialsRequestCaptor.capture()) }.thenReturn(getCredentialsResult)
        }

        val provider = AwsCognitoCredentialsProvider(IDENTITY_POOL_ID, cognitoClient)

        provider.resolveCredentials()
        provider.resolveCredentials() // Try to get them again to check for a refresh

        verify(cognitoClient).getCredentialsForIdentity(getCredentialsRequestCaptor.capture())
    }

    @Test
    fun testGetCredentialsExpired() {
        val expiredCredentials = Credentials.builder()
            .accessKeyId(ACCESS_KEY)
            .secretKey(SECRET_KEY)
            .sessionToken(SESSION_TOKEN)
            .expiration(Instant.now().minus(1, ChronoUnit.HOURS))
            .build()

        val getCredentialsResult = GetCredentialsForIdentityResponse.builder()
            .credentials(expiredCredentials)
            .build()

        cognitoClient.stub {
            on { getId(getIdRequestCaptor.capture()) }.thenReturn(GET_ID_RESULT)
            on { getCredentialsForIdentity(getCredentialsRequestCaptor.capture()) }.thenReturn(getCredentialsResult)
        }

        val provider = AwsCognitoCredentialsProvider(IDENTITY_POOL_ID, cognitoClient)

        provider.resolveCredentials()
        provider.resolveCredentials()

        verify(cognitoClient, times(1)).getCredentialsForIdentity(getCredentialsRequestCaptor.capture())
    }

    @Test
    fun testGetCredentialsWithEmptyCache() {
        val getCredentialsResult = GetCredentialsForIdentityResponse.builder()
            .credentials(CREDENTIALS)
            .build()

        storage.stub {
            on { loadIdentity(any()) }.thenReturn(null)
        }
        cognitoClient.stub {
            on { getId(getIdRequestCaptor.capture()) }.thenReturn(GET_ID_RESULT)
            on { getCredentialsForIdentity(getCredentialsRequestCaptor.capture()) }.thenReturn(getCredentialsResult)
        }

        val provider = AwsCognitoCredentialsProvider(IDENTITY_POOL_ID, cognitoClient, storage)

        val awsCredentials = provider.resolveCredentials() as AwsSessionCredentials

        verify(storage).loadIdentity(IDENTITY_POOL_ID)
        verify(cognitoClient).getId(getIdRequestCaptor.capture())
        verify(cognitoClient).getCredentialsForIdentity(getCredentialsRequestCaptor.capture())
        verify(storage).storeIdentity(IDENTITY_POOL_ID, IDENTITY_ID)

        assertThat(getIdRequestCaptor.firstValue.identityPoolId()).isEqualTo(IDENTITY_POOL_ID)
        assertThat(getCredentialsRequestCaptor.firstValue.identityId()).isEqualTo(IDENTITY_ID)

        assertThat(awsCredentials.accessKeyId()).isEqualTo(ACCESS_KEY)
        assertThat(awsCredentials.secretAccessKey()).isEqualTo(SECRET_KEY)
        assertThat(awsCredentials.sessionToken()).isEqualTo(SESSION_TOKEN)
    }

    @Test
    fun testGetCredentialsWithValidCache() {
        val getCredentialsResult = GetCredentialsForIdentityResponse.builder()
            .credentials(CREDENTIALS)
            .build()

        storage.stub {
            on { loadIdentity(any()) }.thenReturn(IDENTITY_ID)
        }
        cognitoClient.stub {
            on { getCredentialsForIdentity(getCredentialsRequestCaptor.capture()) }.thenReturn(getCredentialsResult)
        }

        val provider = AwsCognitoCredentialsProvider(IDENTITY_POOL_ID, cognitoClient, storage)
        val awsCredentials = provider.resolveCredentials() as AwsSessionCredentials

        verify(storage).loadIdentity(IDENTITY_POOL_ID)
        verify(cognitoClient).getCredentialsForIdentity(getCredentialsRequestCaptor.capture())

        assertThat(getCredentialsRequestCaptor.firstValue.identityId()).isEqualTo(IDENTITY_ID)

        assertThat(awsCredentials.accessKeyId()).isEqualTo(ACCESS_KEY)
        assertThat(awsCredentials.secretAccessKey()).isEqualTo(SECRET_KEY)
        assertThat(awsCredentials.sessionToken()).isEqualTo(SESSION_TOKEN)
    }

    @Test
    fun closeShutsDownTheClient() {
        AwsCognitoCredentialsProvider(IDENTITY_POOL_ID, cognitoClient, storage).close()

        verify(cognitoClient).close()
    }

    companion object {
        private const val IDENTITY_POOL_ID = "IdentityPoolID"
        private const val IDENTITY_ID = "IdentityID"
        private const val ACCESS_KEY = "AccessKey"
        private const val SECRET_KEY = "SecretKey"
        private const val SESSION_TOKEN = "SessionToken"
        private val GET_ID_RESULT = GetIdResponse.builder().identityId(IDENTITY_ID).build()
        private val CREDENTIALS = Credentials.builder()
            .accessKeyId(ACCESS_KEY)
            .secretKey(SECRET_KEY)
            .sessionToken(SESSION_TOKEN)
            .expiration(Instant.now())
            .build()
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.telemetry

import com.intellij.testFramework.ProjectRule
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import software.amazon.awssdk.services.toolkittelemetry.ToolkitTelemetryClient
import software.amazon.awssdk.services.toolkittelemetry.model.AWSProduct
import software.amazon.awssdk.services.toolkittelemetry.model.MetadataEntry
import software.amazon.awssdk.services.toolkittelemetry.model.PostMetricsRequest
import software.aws.toolkits.core.telemetry.DefaultMetricEvent
import software.aws.toolkits.core.utils.delegateMock

class DefaultTelemetryPublisherTest {
    @Rule
    @JvmField
    val projectRule = ProjectRule()

    private val clientMetadata = ClientMetadata(
        productName = AWSProduct.AWS_TOOLKIT_FOR_JET_BRAINS,
        productVersion = "1.0",
        clientId = "foo",
        parentProduct = "JetBrains",
        parentProductVersion = "191",
        os = "mac",
        osVersion = "1.0"
    )

    @Test
    fun testPublish_withNamespace() {
        val mockPostMetricsRequestCaptor = argumentCaptor<PostMetricsRequest>()

        val mockTelemetryClient = delegateMock<ToolkitTelemetryClient>()
        val publisher = DefaultTelemetryPublisher(
            clientMetadata = clientMetadata,
            clientProvider = { mockTelemetryClient }
        )

        runBlocking {
            publisher.publish(
                listOf(
                    DefaultMetricEvent.builder()
                        .awsAccount("111111111111")
                        .awsRegion("us-west-2")
                        .datum("foobar") { this.count() }
                        .build(),
                    DefaultMetricEvent.builder()
                        .awsAccount("111111111111")
                        .awsRegion("us-west-2")
                        .datum("spam") { this.count() }
                        .build()
                )
            )
        }

        verify(mockTelemetryClient, times(1)).postMetrics(mockPostMetricsRequestCaptor.capture())
        val postMetricsRequest = mockPostMetricsRequestCaptor.firstValue

        assertThat(postMetricsRequest.awsProduct()).isEqualTo(AWSProduct.AWS_TOOLKIT_FOR_JET_BRAINS)
        assertThat(postMetricsRequest.awsProductVersion()).isEqualTo("1.0")
        assertThat(postMetricsRequest.clientID()).isEqualTo("foo")
        assertThat(postMetricsRequest.parentProduct()).isEqualTo("JetBrains")
        assertThat(postMetricsRequest.parentProductVersion()).isEqualTo("191")
        assertThat(postMetricsRequest.os()).isEqualTo("mac")
        assertThat(postMetricsRequest.osVersion()).isEqualTo("1.0")
        assertThat(postMetricsRequest.metricData()).hasSize(2)

        postMetricsRequest.metricData()[0].let {
            assertThat(it.metricName()).isEqualTo("foobar")
            assertThat(it.metadata()).contains(
                MetadataEntry.builder()
                    .key("awsAccount")
                    .value("111111111111")
                    .build(),
                MetadataEntry.builder()
                    .key("awsRegion")
                    .value("us-west-2")
                    .build()
            )
        }

        postMetricsRequest.metricData()[1].let {
            assertThat(it.metricName()).isEqualTo("spam")
            assertThat(it.metadata()).contains(
                MetadataEntry.builder()
                    .key("awsAccount")
                    .value("111111111111")
                    .build(),
                MetadataEntry.builder()
                    .key("awsRegion")
                    .value("us-west-2")
                    .build()
            )
        }
    }

    @Test
    fun testPublish_withoutNamespace() {
        val mockPostMetricsRequestCaptor = argumentCaptor<PostMetricsRequest>()

        val mockTelemetryClient = delegateMock<ToolkitTelemetryClient>()
        val publisher = DefaultTelemetryPublisher(
            clientMetadata = clientMetadata,
            clientProvider = { mockTelemetryClient }
        )

        runBlocking {
            publisher.publish(
                listOf(
                    DefaultMetricEvent.builder()
                        .awsAccount("111111111111")
                        .awsRegion("us-west-2")
                        .datum("foobar") { this.count() }
                        .build(),
                    DefaultMetricEvent.builder()
                        .awsAccount("111111111111")
                        .awsRegion("us-west-2")
                        .datum("spam") { this.count() }
                        .build()
                )
            )
        }

        verify(mockTelemetryClient, times(1)).postMetrics(mockPostMetricsRequestCaptor.capture())
        val postMetricsRequest = mockPostMetricsRequestCaptor.firstValue

        assertThat(postMetricsRequest.awsProduct()).isEqualTo(AWSProduct.AWS_TOOLKIT_FOR_JET_BRAINS)
        assertThat(postMetricsRequest.awsProductVersion()).isEqualTo("1.0")
        assertThat(postMetricsRequest.clientID()).isEqualTo("foo")
        assertThat(postMetricsRequest.parentProduct()).isEqualTo("JetBrains")
        assertThat(postMetricsRequest.parentProductVersion()).isEqualTo("191")
        assertThat(postMetricsRequest.os()).isEqualTo("mac")
        assertThat(postMetricsRequest.osVersion()).isEqualTo("1.0")
        assertThat(postMetricsRequest.metricData()).hasSize(2)

        postMetricsRequest.metricData()[0].let {
            assertThat(it.metricName()).isEqualTo("foobar")
            assertThat(it.metadata()).contains(
                MetadataEntry.builder()
                    .key("awsAccount")
                    .value("111111111111")
                    .build(),
                MetadataEntry.builder()
                    .key("awsRegion")
                    .value("us-west-2")
                    .build()
            )
        }

        postMetricsRequest.metricData()[1].let {
            assertThat(it.metricName()).isEqualTo("spam")
            assertThat(it.metadata()).contains(
                MetadataEntry.builder()
                    .key("awsAccount")
                    .value("111111111111")
                    .build(),
                MetadataEntry.builder()
                    .key("awsRegion")
                    .value("us-west-2")
                    .build()
            )
        }
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.telemetry

import software.amazon.awssdk.services.toolkittelemetry.model.Sentiment
import software.aws.toolkits.core.telemetry.DefaultTelemetryBatcher
import software.aws.toolkits.core.telemetry.MetricEvent
import software.aws.toolkits.core.telemetry.TelemetryBatcher
import software.aws.toolkits.core.telemetry.TelemetryPublisher

class NoOpTelemetryService : TelemetryService {
    constructor() : super(publisher, batcher)

    private companion object {
        private val publisher: TelemetryPublisher by lazy { NoOpPublisher() }
        private val batcher: TelemetryBatcher by lazy { DefaultTelemetryBatcher(publisher) }
    }
}

class NoOpPublisher : TelemetryPublisher {
    override suspend fun publish(metricEvents: Collection<MetricEvent>) {}

    override suspend fun sendFeedback(sentiment: Sentiment, comment: String, metadata: Map<String, String>) {}

    override fun close() {}
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.telemetry

import com.intellij.ide.highlighter.ProjectFileType
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.testFramework.DisposableRule
import com.intellij.testFramework.ExtensionTestUtil
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.TemporaryDirectory
import com.intellij.testFramework.createTestOpenProjectOptions
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import software.amazon.awssdk.services.toolkittelemetry.model.Sentiment
import software.aws.toolkits.core.credentials.CredentialIdentifier
import software.aws.toolkits.core.region.AwsRegion
import software.aws.toolkits.core.telemetry.DefaultMetricEvent.Companion.METADATA_INVALID
import software.aws.toolkits.core.telemetry.DefaultMetricEvent.Companion.METADATA_NOT_SET
import software.aws.toolkits.core.telemetry.MetricEvent
import software.aws.toolkits.core.telemetry.TelemetryBatcher
import software.aws.toolkits.core.telemetry.TelemetryPublisher
import software.aws.toolkits.core.utils.test.aString
import software.aws.toolkits.jetbrains.core.MockResourceCacheRule
import software.aws.toolkits.jetbrains.core.credentials.AwsConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.ConnectionState
import software.aws.toolkits.jetbrains.core.credentials.MockAwsConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.MockAwsConnectionManager.ProjectAccountSettingsManagerRule
import software.aws.toolkits.jetbrains.core.credentials.MockCredentialManagerRule
import software.aws.toolkits.jetbrains.core.credentials.waitUntilConnectionStateIsStable
import software.aws.toolkits.jetbrains.core.experiments.DummyExperiment
import software.aws.toolkits.jetbrains.core.experiments.ToolkitExperimentManager
import software.aws.toolkits.jetbrains.core.experiments.setState
import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule
import software.aws.toolkits.jetbrains.services.sts.StsResources
import software.aws.toolkits.jetbrains.settings.AwsSettings
import software.aws.toolkits.jetbrains.ui.feedback.ENABLED_EXPERIMENTS
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

class TelemetryServiceTest {
    private class TestTelemetryService(publisher: TelemetryPublisher = NoOpPublisher(), batcher: TelemetryBatcher) : TelemetryService(publisher, batcher)

    @Rule
    @JvmField
    val projectRule = ProjectRule()

    @JvmField
    @Rule
    val resourceCache = MockResourceCacheRule()

    @JvmField
    @Rule
    val regionProvider = MockRegionProviderRule()

    @JvmField
    @Rule
    val credentialManager = MockCredentialManagerRule()

    @JvmField
    @Rule
    val connectionSettingsManager = ProjectAccountSettingsManagerRule(projectRule)

    @JvmField
    @Rule
    val disposableRule = DisposableRule()

    @After
    fun tearDown() {
        AwsSettings.getInstance().isTelemetryEnabled = false
    }

    @Test
    fun testInitialTelemetrySetting() {
        AwsSettings.getInstance().isTelemetryEnabled = true

        val changeCountDown = CountDownLatch(1)
        val changeCaptor = argumentCaptor<Boolean>()

        val batcher = mock<TelemetryBatcher> {
            on { onTelemetryEnabledChanged(changeCaptor.capture()) }
                .doAnswer {
                    changeCountDown.countDown()
                }
        }

        TestTelemetryService(batcher = batcher)

        changeCountDown.await(5, TimeUnit.SECONDS)
        verify(batcher).onTelemetryEnabledChanged(true)
        assertThat(changeCaptor.allValues).hasSize(1)
        assertThat(changeCaptor.firstValue).isEqualTo(true)
    }

    @Test
    fun testTelemetrySettingChanged() {
        AwsSettings.getInstance().isTelemetryEnabled = true

        val changeCountDown = CountDownLatch(3)
        val changeCaptor = argumentCaptor<Boolean>()

        val batcher = mock<TelemetryBatcher>()

        batcher.stub {
            on(batcher.onTelemetryEnabledChanged(changeCaptor.capture()))
                .doAnswer {
                    changeCountDown.countDown()
                }
        }

        val telemetryService = TestTelemetryService(batcher = batcher)

        telemetryService.setTelemetryEnabled(false)
        telemetryService.setTelemetryEnabled(true)

        changeCountDown.await(5, TimeUnit.SECONDS)
        verify(batcher, times(2)).onTelemetryEnabledChanged(true)
        verify(batcher).onTelemetryEnabledChanged(false)
        assertThat(changeCaptor.allValues).hasSize(3)
        assertThat(changeCaptor.firstValue).isEqualTo(true)
        assertThat(changeCaptor.secondValue).isEqualTo(false)
        assertThat(changeCaptor.thirdValue).isEqualTo(true)
    }

    @Test
    fun metricEventMetadataIsNotSet() {
        connectionSettingsManager.settingsManager.nullifyCredentialProviderAndWait()

        val eventCaptor = argumentCaptor<MetricEvent>()

        val batcher = mock<TelemetryBatcher>()
        val telemetryService = TestTelemetryService(batcher = batcher)

        telemetryService.record(projectRule.project) {
            datum("Foo")
        }
        telemetryService.dispose()

        verify(batcher).enqueue(eventCaptor.capture())

        assertMetricEventsContains(eventCaptor.allValues, "Foo", METADATA_NOT_SET, "us-east-1")
    }

    @Test
    fun metricEventMetadataIsSet() {
        val credentials = credentialManager.addCredentials("profile:admin")
        val mockRegion = regionProvider.createAwsRegion()

        addAccountId(credentials, mockRegion)

        connectionSettingsManager.settingsManager.changeCredentialProvider(credentials)
        connectionSettingsManager.settingsManager.changeRegion(mockRegion)
        connectionSettingsManager.settingsManager.waitUntilConnectionStateIsStable()

        // assert that connection setting succeeded. This test has been failing sometimes in the assert stage that there is nothing
        assertThat(connectionSettingsManager.settingsManager.connectionState).isInstanceOf(ConnectionState.ValidConnection::class.java)

        val eventCaptor = argumentCaptor<MetricEvent>()
        val batcher = mock<TelemetryBatcher>()
        val telemetryService = TestTelemetryService(batcher = batcher)

        telemetryService.record(projectRule.project) {
            datum("Foo")
        }
        telemetryService.dispose()

        verify(batcher).enqueue(eventCaptor.capture())
        assertMetricEventsContains(eventCaptor.allValues, "Foo", "1111222233333", mockRegion.id)
    }

    @Test
    fun metricEventMetadataIsOverridden() {
        val accountSettings = MockAwsConnectionManager.getInstance(projectRule.project)
        val credentials = credentialManager.addCredentials("profile:admin")

        addAccountId(credentials, accountSettings.activeRegion)
        accountSettings.changeCredentialProvider(credentials)

        val mockRegion = AwsRegion("foo-region", "foo-region", "aws")
        regionProvider.addRegion(mockRegion)
        accountSettings.changeRegion(mockRegion)

        val eventCaptor = argumentCaptor<MetricEvent>()

        val batcher = mock<TelemetryBatcher>()
        val telemetryService = TestTelemetryService(batcher = batcher)

        telemetryService.record(
            MetricEventMetadata(
                awsAccount = "222222222222",
                awsRegion = "bar-region"
            )
        ) {
            datum("Foo")
        }
        telemetryService.dispose()

        verify(batcher).enqueue(eventCaptor.capture())
        assertMetricEventsContains(eventCaptor.allValues, "Foo", "222222222222", "bar-region")
    }

    @Test
    fun telemetryCanBeSendOnAfterProjectClosed() {
        // Create a temp project that we own the life cycle for
        val projectFile = TemporaryDirectory.generateTemporaryPath("project_telemetryCanBeSendOnAfterProjectClosed${ProjectFileType.DOT_DEFAULT_EXTENSION}")
        val options = createTestOpenProjectOptions(runPostStartUpActivities = false)
        val project = ProjectManagerEx.getInstanceEx().openProject(projectFile, options)!!
        try {
            val credentials = credentialManager.addCredentials("profile:admin")
            val mockRegion = regionProvider.createAwsRegion()

            addAccountId(credentials, mockRegion)

            val connectionSettingsManager = AwsConnectionManager.getInstance(project)

            connectionSettingsManager.changeCredentialProvider(credentials)
            connectionSettingsManager.changeRegion(mockRegion)
            connectionSettingsManager.waitUntilConnectionStateIsStable()

            val batcher = mock<TelemetryBatcher>()
            val telemetryService = TestTelemetryService(batcher = batcher)

            telemetryService.record(project) {
                datum("Foo")
            }

            PlatformTestUtil.forceCloseProjectWithoutSaving(project)

            telemetryService.record(project) {
                datum("Bar")
            }

            telemetryService.dispose()

            argumentCaptor<MetricEvent>().apply {
                verify(batcher, times(2)).enqueue(capture())

                assertMetricEventsContains(allValues, "Foo", "1111222233333", mockRegion.id)
                assertMetricEventsContains(allValues, "Bar", METADATA_INVALID, METADATA_INVALID)
            }
        } finally {
            // Make sure we closed it if test failed
            if (project.isOpen) {
                PlatformTestUtil.forceCloseProjectWithoutSaving(project)
            }
        }
    }

    @Test
    @ExperimentalCoroutinesApi
    fun experimentStatusIsIncludedInFeedback() = runBlockingTest {
        val fooExperiment = DummyExperiment()
        val barExperiment = DummyExperiment()
        val bloopExperiment = DummyExperiment()
        ExtensionTestUtil.maskExtensions(ToolkitExperimentManager.EP_NAME, listOf(fooExperiment, barExperiment, bloopExperiment), disposableRule.disposable)

        fooExperiment.setState(true)
        barExperiment.setState(true)

        val publisher = mock<TelemetryPublisher>()
        val telemetryService = TestTelemetryService(publisher = publisher, batcher = mock())

        val comment = aString()

        telemetryService.sendFeedback(Sentiment.NEGATIVE, comment)
        telemetryService.dispose()

        verify(publisher).sendFeedback(Sentiment.NEGATIVE, comment, mapOf(ENABLED_EXPERIMENTS to "${fooExperiment.id},${barExperiment.id}"))
    }

    @Test
    fun disposeClosesThePublisher() {
        val mockPublisher = mock<TelemetryPublisher>()
        val mockBatcher = mock<TelemetryBatcher>()

        val telemetryService = TestTelemetryService(mockPublisher, mockBatcher)
        telemetryService.dispose()

        verify(mockBatcher).shutdown()
        verify(mockPublisher).close()
    }

    private fun addAccountId(credentialsIdentifier: CredentialIdentifier, region: AwsRegion) {
        resourceCache.addEntry(StsResources.ACCOUNT, region.id, credentialsIdentifier.id, "1111222233333")
    }

    private fun assertMetricEventsContains(events: Collection<MetricEvent>, eventName: String, awsAccount: String, awsRegion: String) {
        assertThat(events).filteredOn { event ->
            event.data.any { it.name == eventName }
        }.anySatisfy {
            assertThat(it.awsAccount).isEqualTo(awsAccount)
            assertThat(it.awsRegion).isEqualTo(awsRegion)
        }
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.settings

import com.intellij.openapi.options.ConfigurationException
import com.intellij.openapi.util.SystemInfo
import com.intellij.testFramework.ProjectRule
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Rule
import org.junit.Test
import software.aws.toolkits.jetbrains.services.lambda.sam.SamCommonTestUtils
import java.nio.file.Path

// TODO add PSE tests that makeAPse once we know where we want to put it and have a real PSE ExecutableManager
class AwsSettingsConfigurableTest : ExecutableDetectorTestBase() {
    @JvmField
    @Rule
    val projectRule = ProjectRule()

    @Test
    fun validate_ok_noOp() {
        val settings = AwsSettingsConfigurable()
        settings.apply()
    }

    @Test
    fun validate_ok_changedTelemetry() {
        val settings = AwsSettingsConfigurable()
        // explicit call to suppress compiling error
        settings.samExecutablePath.setText(null)
        settings.enableTelemetry.isSelected = true
        settings.apply()
        settings.enableTelemetry.isSelected = false
        settings.apply()
    }

    @Test
    fun validate_ok_setSamEmpty() {
        val settings = AwsSettingsConfigurable()
        settings.samExecutablePath.setText("")
        settings.apply()
    }

    @Test(expected = ConfigurationException::class)
    fun validate_fail_setBadSam() {
        val settings = AwsSettingsConfigurable()
        settings.samExecutablePath.text = "not_a_valid_path"
        settings.apply()
    }

    @Test
    fun validate_ok_setValidSam() {
        val samPath = makeASam(SamCommonTestUtils.getMinVersionAsJson())

        val settings = AwsSettingsConfigurable()
        settings.samExecutablePath.text = samPath.toString()
        settings.apply()
    }

    @Test
    fun validate_ok_autodetectBadSam() {
        // allow users to save if their autodetected sam executable is bad
        makeASam(SamCommonTestUtils.getMaxVersionAsJson())

        val settings = AwsSettingsConfigurable()
        settings.apply()
    }

    @Test
    fun validate_fail_autodetectBadSam_andManuallySetToBadSam() {
        val sam = makeASam(SamCommonTestUtils.getMaxVersionAsJson())
        val settings = AwsSettingsConfigurable()
        settings.apply()

        settings.samExecutablePath.text = sam.toAbsolutePath().toString()
        assertThatThrownBy {
            settings.apply()
        }.isInstanceOf(ConfigurationException::class.java)
    }

    @Test
    fun validate_ok_autodetectValidSam() {
        makeASam(SamCommonTestUtils.getMinVersionAsJson())

        val settings = AwsSettingsConfigurable()
        settings.apply()
    }

    private fun makeASam(version: String): Path {
        val path = if (SystemInfo.isWindows) {
            "C:\\Program Files (x86)\\Amazon\\AWSSAMCLI\\bin\\sam.bat"
        } else {
            "/usr/local/bin/sam"
        }

        val actualPath = touch(path).absolutePath

        return SamCommonTestUtils.makeATestSam(path = actualPath, message = version)
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.settings

import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import software.aws.toolkits.jetbrains.utils.rules.HeavyJavaCodeInsightTestFixtureRule
import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
import software.aws.toolkits.jetbrains.utils.rules.addModule
import java.nio.file.Paths

class DeploySettingsTest {

    @Rule
    @JvmField
    val projectRule = HeavyJavaCodeInsightTestFixtureRule()

    @Test
    fun relativeSamPath_root() {
        val path = Paths.get("foo.yaml").toString()
        val module = projectRule.fixture.addModule("foo")
        val file = projectRule.fixture.addFileToModule(module, path, """foo""")

        assertThat(relativeSamPath(module, file.virtualFile)).isEqualTo(path)
    }

    @Test
    fun relativeSamPath_null() {
        val fooModule = projectRule.fixture.addModule("foo")
        val barModule = projectRule.fixture.addModule("bar")
        val file = projectRule.fixture.addFileToModule(fooModule, "foo.yaml", """foo""")

        assertThat(relativeSamPath(barModule, file.virtualFile)).isNull()
    }
}


// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.settings

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import software.aws.toolkits.jetbrains.utils.deserializeState
import software.aws.toolkits.jetbrains.utils.serializeState

class DynamicResourcesSettingsTest {
    @Test
    fun `can round trip settings`() {
        val sut = DefaultDynamicResourcesSettings()

        sut.selected = setOf("a", "b", "c")

        val serialized = serializeState("settings", sut)
        val newSut = DefaultDynamicResourcesSettings()
        deserializeState(serialized, newSut)
        assertThat(newSut.selected).isEqualTo(sut.selected)
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.settings

import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import software.aws.toolkits.core.rules.EnvironmentVariableHelper
import java.io.File

abstract class ExecutableDetectorTestBase {
    @Rule
    @JvmField
    val envHelper = EnvironmentVariableHelper()

    @Rule
    @JvmField
    val tempFolderRule = TemporaryFolder()

    lateinit var detector: ExecutableDetector
    lateinit var tempFolder: String

    @Before
    open fun setUp() {
        envHelper.remove("PATH")

        tempFolder = "${tempFolderRule.newFolder()}${File.separator}"

        detector = ExecutableDetector()
    }

    private fun sanitizePath(original: String): String = original.trimStart(File.separatorChar).replace("^(\\w):".toRegex()) { "${it.groupValues[1]}_" }

    private fun unsanitizePath(sanitized: String?): String? {
        val suffix = sanitized?.removePrefix(tempFolder)?.replace("^(\\w)_".toRegex()) { "${it.groupValues[1]}:" }
        return suffix?.let { if (SystemInfo.isUnix) "${File.separator}$suffix" else suffix }
    }

    protected fun assertExecutable(paths: Array<String>, executables: Array<String>, expected: String?) {
        assertThat(unsanitizePath(detector.find(paths, executables))).isEqualTo(expected)
    }

    protected fun touch(path: String): File {
        val sanitized = sanitizePath(path)
        val actualFile = File(tempFolder, sanitized)
        assertThat(FileUtil.createIfDoesntExist(actualFile)).isTrue()
        return actualFile
    }
}

class ExecutableDetectorTest : ExecutableDetectorTestBase() {
    @Before
    override fun setUp() {
        super.setUp()
    }

    @Test
    fun testDefinedPath() {
        val executable = "sam"
        val tempDirectory = FileUtil.createTempDirectory("tempSam", null)
        val expected = File(tempDirectory, executable).absolutePath
        val actualPath = touch(expected).parent

        assertExecutable(arrayOf(actualPath), arrayOf(executable), expected)
    }

    @Test
    fun testDefinedPathMultipleExecutables() {
        val executable = "sam"
        val tempDirectory = FileUtil.createTempDirectory("tempSam", null)
        val expected = File(tempDirectory, executable).absolutePath
        val actualPath = touch(expected).parent

        assertExecutable(arrayOf(actualPath), arrayOf("exe1", "exe2", "exe3", executable), expected)
    }

    @Test
    fun testDefinedMultiplePaths() {
        val executable = "sam"
        val tempDirectory = FileUtil.createTempDirectory("tempSam", null)
        val expected = File(tempDirectory, executable).absolutePath
        val actualPath = touch(expected).parent

        assertExecutable(arrayOf("path1", "path2", "path3", actualPath), arrayOf(executable), expected)
    }

    @Test
    fun testPath() {
        val executable = "sam"
        val tempDirectory = FileUtil.createTempDirectory("tempSam", null)
        val expected = File(tempDirectory, executable).absolutePath
        val actualPath = touch(expected).parent
        envHelper["PATH"] = actualPath

        assertExecutable(arrayOf(), arrayOf(executable), expected)
    }

    @Test
    fun testPathMultipleExecutables() {
        val executable = "sam"
        val tempDirectory = FileUtil.createTempDirectory("tempSam", null)
        val expected = File(tempDirectory, executable).absolutePath
        val actualPath = touch(expected).parent
        envHelper["PATH"] = actualPath

        assertExecutable(arrayOf(), arrayOf("exe1", "exe2", "exe3", executable), expected)
    }

    @Test
    fun returnNullIfNotFound() {
        val executable = "sam"
        val tempDirectory = FileUtil.createTempDirectory("tempSam", null)
        val expected = File(tempDirectory, executable).absolutePath
        touch(expected)

        assertThat(detector.find(arrayOf("thisIsNotTheRightDir"), arrayOf(executable))).isNull()
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.settings

import com.intellij.testFramework.ApplicationRule
import java.util.UUID

class MockAwsSettings : AwsSettings {
    override var isTelemetryEnabled: Boolean = true
    override var promptedForTelemetry: Boolean = false
    override var useDefaultCredentialRegion: UseAwsCredentialRegion = UseAwsCredentialRegion.Prompt
    override var profilesNotification: ProfilesNotification = ProfilesNotification.Always
    override val clientId: UUID = UUID.randomUUID()

    internal fun reset() {
        isTelemetryEnabled = true
        promptedForTelemetry = false
        useDefaultCredentialRegion = UseAwsCredentialRegion.Prompt
        profilesNotification = ProfilesNotification.Always
    }
}

class AwsSettingsRule : ApplicationRule() {
    val settings by lazy {
        AwsSettings.getInstance()
    }

    override fun after() {
        (settings as MockAwsSettings).reset()
    }
}


// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.ui

import com.intellij.testFramework.ApplicationRule
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.spy
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import java.util.concurrent.CountDownLatch
import javax.swing.DefaultComboBoxModel

class AsyncComboBoxTest {
    @Rule
    @JvmField
    val applicationRule = ApplicationRule()

    @Test
    fun `can populate combobox`() {
        val spy = spy<DefaultComboBoxModel<String>>()
        val sut = AsyncComboBox(comboBoxModel = spy)
        sut.proposeModelUpdate { it.addElement("1") }
        sut.waitForSelection().get()

        verify(spy).addElement("1")
    }

    @Test
    fun `returns null selection while loading`() {
        val spy = spy<DefaultComboBoxModel<String>>()
        val sut = AsyncComboBox(comboBoxModel = spy)
        val latch = CountDownLatch(1)
        sut.proposeModelUpdate {
            latch.await()
            it.addElement("1")
        }

        assertThat(sut.selectedItem).isNull()

        latch.countDown()
    }

    @Test
    fun `multiple update proposals results in single execution`() {
        val spy = spy<DefaultComboBoxModel<String>>()
        val sut = AsyncComboBox(comboBoxModel = spy)
        sut.proposeModelUpdate { it.addElement("1") }
        sut.proposeModelUpdate { it.addElement("2") }
        sut.proposeModelUpdate { it.addElement("3") }

        sut.waitForSelection().get()

        verify(spy).addElement("3")
    }

    @Test
    fun `long running update proposals preempted by newer ones`() {
        val spy = spy<DefaultComboBoxModel<String>>()
        val sut = AsyncComboBox(comboBoxModel = spy)
        val latch = CountDownLatch(1)
        val latch2 = CountDownLatch(1)
        sut.proposeModelUpdate {
            it.addElement("1")
            latch2.countDown()
            latch.await()
            it.addElement("2")
        }
        // wait for first update to start running
        latch2.await()
        sut.proposeModelUpdate {
            it.addElement("3")
        }

        sut.waitForSelection().get()
        latch.countDown()

        verify(spy).addElement("1")
        verify(spy).addElement("3")
        verify(spy, times(0)).addElement("2")
    }
}


// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.ui

import com.intellij.testFramework.ApplicationRule
import com.intellij.testFramework.DisposableRule
import com.intellij.ui.layout.applyToComponent
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import software.aws.toolkits.core.credentials.CredentialIdentifier
import software.aws.toolkits.core.credentials.aCredentialsIdentifier
import software.aws.toolkits.jetbrains.ui.CredentialIdentifierSelector.Companion.credentialSelector
import software.aws.toolkits.jetbrains.ui.CredentialIdentifierSelector.Companion.validCredentialSelector

class CredentialIdentifierSelectorTest {
    private lateinit var credentialIdentifiers: List<CredentialIdentifier>

    @Rule
    @JvmField
    val application = ApplicationRule()

    @Rule
    @JvmField
    val disposableRule = DisposableRule()

    @Before
    fun setUp() {
        credentialIdentifiers = listOf(aCredentialsIdentifier(), aCredentialsIdentifier(), aCredentialsIdentifier())
    }

    @Test
    fun `empty ID selection is not valid`() {
        val selector = CredentialIdentifierSelector(credentialIdentifiers)
        selector.setSelectedCredentialIdentifierId(null)
        assertThat(selector.isSelectionValid()).isFalse
        assertThat(selector.getSelectedValidCredentialIdentifier()).isNull()
        assertThat(selector.getSelectedCredentialsIdentifierId()).isNull()
    }

    @Test
    fun `empty identifier selection is not valid`() {
        val selector = CredentialIdentifierSelector(credentialIdentifiers)
        selector.setSelectedCredentialIdentifier(null)
        assertThat(selector.isSelectionValid()).isFalse
        assertThat(selector.getSelectedValidCredentialIdentifier()).isNull()
        assertThat(selector.getSelectedCredentialsIdentifierId()).isNull()
    }

    @Test
    fun `valid selection is valid`() {
        val selection = credentialIdentifiers.random()

        val selector = CredentialIdentifierSelector(credentialIdentifiers)
        selector.setSelectedCredentialIdentifier(selection)
        assertThat(selector.isSelectionValid()).isTrue
        assertThat(selector.getSelectedValidCredentialIdentifier()).isEqualTo(selection)
        assertThat(selector.getSelectedCredentialsIdentifierId()).isEqualTo(selection.id)
    }

    @Test
    fun `unknown ID is invalid`() {
        val selection = aCredentialsIdentifier()

        val selector = CredentialIdentifierSelector(credentialIdentifiers)
        selector.setSelectedCredentialIdentifierId(selection.id)
        assertThat(selector.isSelectionValid()).isFalse
        assertThat(selector.getSelectedValidCredentialIdentifier()).isNull()
        assertThat(selector.getSelectedCredentialsIdentifierId()).isEqualTo(selection.id)
    }

    @Test
    fun `unknown identifier is invalid`() {
        val selection = aCredentialsIdentifier()

        val selector = CredentialIdentifierSelector(credentialIdentifiers)
        selector.setSelectedCredentialIdentifier(selection)
        assertThat(selector.isSelectionValid()).isFalse
        assertThat(selector.getSelectedValidCredentialIdentifier()).isNull()
        assertThat(selector.getSelectedCredentialsIdentifierId()).isEqualTo(selection.id)
    }

    inner class ValidSelectorUiDslTest {
        lateinit var credentialIdentifierUiDsl: CredentialIdentifier
        lateinit var selector: CredentialIdentifierSelector
        fun panel() = validatingPanel(disposableRule.disposable) {
            row {
                validCredentialSelector(::credentialIdentifierUiDsl, credentialIdentifiers).applyToComponent {
                    selector = this
                }
            }
        }
    }

    inner class SelectorUiDslTest {
        var credentialIdentifierUiDsl: CredentialIdentifier? = null
        lateinit var selector: CredentialIdentifierSelector
        fun panel() = validatingPanel(disposableRule.disposable) {
            row {
                credentialSelector(::credentialIdentifierUiDsl, credentialIdentifiers).applyToComponent {
                    selector = this
                }
            }
        }
    }

    @Test
    fun `empty late init in ui dsl leads to no selection`() {
        val test = ValidSelectorUiDslTest()
        test.panel()

        assertThat(test.selector.isSelectionValid()).isFalse
        assertThat(test.selector.getSelectedValidCredentialIdentifier()).isNull()
    }

    @Test
    fun `initial selection is selected in ui dsl`() {
        val test = ValidSelectorUiDslTest()
        val selection = credentialIdentifiers.random()
        test.credentialIdentifierUiDsl = selection
        test.panel()

        assertThat(test.selector.isSelectionValid()).isTrue
        assertThat(test.selector.getSelectedValidCredentialIdentifier()).isEqualTo(selection)
    }

    @Test
    fun `valid selection is applied to field`() {
        val test = ValidSelectorUiDslTest()
        val panel = test.panel()

        val selection = credentialIdentifiers.random()
        test.selector.setSelectedCredentialIdentifier(selection)
        panel.apply()

        assertThat(panel.runValidation()).isTrue
        assertThat(test.credentialIdentifierUiDsl).isEqualTo(selection)
    }

    @Test
    fun `invalid selection is not applied to field when valid is required`() {
        val test = ValidSelectorUiDslTest()
        val panel = test.panel()
        panel.apply()

        assertThat(panel.runValidation()).isFalse
        assertThatThrownBy { test.credentialIdentifierUiDsl }.isInstanceOf(UninitializedPropertyAccessException::class.java)
    }

    @Test
    fun `invalid selection is applied to field when non-valid is allowed`() {
        val test = SelectorUiDslTest()
        val panel = test.panel()
        panel.apply()

        assertThat(panel.runValidation()).isTrue
        assertThat(test.credentialIdentifierUiDsl).isNull()
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.ui

import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.runInEdtAndWait
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.mock
import software.aws.toolkits.core.ConnectionSettings
import software.aws.toolkits.core.credentials.aCredentialsIdentifier
import software.aws.toolkits.core.credentials.aToolkitCredentialsProvider
import software.aws.toolkits.core.region.AwsRegion
import software.aws.toolkits.core.utils.test.retryableAssert
import software.aws.toolkits.jetbrains.core.MockResourceCacheRule
import software.aws.toolkits.jetbrains.core.Resource
import software.aws.toolkits.resources.message
import java.util.concurrent.CompletableFuture

class ResourceSelectorTest {
    @Rule
    @JvmField
    val projectRule = ProjectRule()

    @JvmField
    @Rule
    val resourceCache = MockResourceCacheRule()

    private val mockResource = mock<Resource.Cached<List<String>>> {
        on { id }.thenReturn("mockResource")
    }

    @Test
    fun canSpecifyADefaultItem() {
        resourceCache.addEntry(projectRule.project, mockResource, listOf("foo", "bar", "baz"))
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        comboBox.selectedItem = "bar"

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo("bar")
            }
        }
    }

    @Test
    fun canSpecifyADefaultItemMatcher() {
        resourceCache.addEntry(projectRule.project, mockResource, listOf("foo", "bar", "baz"))
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        comboBox.reload()

        // There is a potential timing issue with reload since it's asyncrhonous but does not return a future
        // so, if we hit it, sleep to fix the issue
        if (comboBox.isLoading) {
            Thread.sleep(200)
        }
        comboBox.selectedItem { it.endsWith("z") }

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo("baz")
            }
        }
    }

    @Test
    fun loadFailureShowsAnErrorAndDisablesTheBox() {
        val future = CompletableFuture<List<String>>()
        resourceCache.addEntry(projectRule.project, mockResource, future)
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        future.completeExceptionally(RuntimeException("boom"))

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.isEnabled).isFalse
                assertThat(comboBox.model.selectedItem).isEqualTo(message("loading_resource.failed"))
            }
        }
    }

    @Test
    fun usePreviouslySelectedItemAfterReloadUnlessSelectItemSet() {
        resourceCache.addEntry(projectRule.project, mockResource, listOf("foo", "bar", "baz"))
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        runInEdtAndWait {
            comboBox.selectedItem = "bar"
        }

        comboBox.reload()

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo("bar")
            }
        }
    }

    @Test
    fun comboBoxIsDisabledWhileEntriesAreLoading() {
        val future = CompletableFuture<List<String>>()
        resourceCache.addEntry(projectRule.project, mockResource, future)
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        assertThat(comboBox.selected()).isNull()

        runInEdtAndWait {
            assertThat(comboBox.isEnabled).isFalse
            assertThat(comboBox.selectedItem).isEqualTo(message("loading_resource.loading"))
        }

        future.complete(listOf("foo", "bar", "baz"))

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.isEnabled).isTrue
                assertThat(comboBox.selectedItem).isNull()
            }
        }
    }

    @Test
    fun comboBoxCancelsOldLoadingFutures() {
        val future = CompletableFuture<List<String>>()
        resourceCache.addEntry(projectRule.project, mockResource, future)
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.isLoading).isTrue()
            }
        }

        assertThat(future).isNotDone

        val replacementFuture = CompletableFuture<List<String>>()
        resourceCache.addEntry(projectRule.project, mockResource, replacementFuture)

        comboBox.reload()

        replacementFuture.complete(listOf("foo", "bar", "baz"))

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.isEnabled).isTrue
                assertThat(comboBox.selectedItem).isNull()
            }

            assertThat(future).isCancelled
        }
    }

    @Test
    fun comboBoxLoadingDoesntCancelIdempotentFutures() {
        val future = CompletableFuture<List<String>>()
        resourceCache.addEntry(projectRule.project, mockResource, future)
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.isLoading).isTrue()
            }
        }

        assertThat(future).isNotDone

        comboBox.reload()

        future.complete(listOf("foo", "bar", "baz"))

        retryableAssert {
            runInEdtAndWait {
                assertThat(future).isNotCancelled
                assertThat(comboBox.isEnabled).isTrue
            }
        }
    }

    @Test
    fun actionListenerIsInvokedOnLoadingCorrectly() {
        val future = CompletableFuture<List<String>>() // Use the future to force slow load
        resourceCache.addEntry(projectRule.project, mockResource, future)
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).disableAutomaticLoading().build()

        val loadingStatus = mutableListOf<Boolean>()
        comboBox.addActionListener { loadingStatus.add(comboBox.isLoading) }

        comboBox.reload()

        runInEdtAndWait {
            comboBox.selectedItem = "bar"
        }

        future.complete(listOf("foo", "bar", "baz"))

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo("bar")
                assertThat(loadingStatus).containsExactly(true, false)
            }
        }
    }

    @Test
    fun aSingleResultWillAutoSelect() {
        resourceCache.addEntry(projectRule.project, mockResource, listOf("bar"))
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        runInEdtAndWait {
            comboBox.selectedItem = "bar"
        }

        comboBox.reload()

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo("bar")
            }
        }
    }

    @Test
    fun selectingAnInvalidItemWillDefaultToUnselected() {
        resourceCache.addEntry(projectRule.project, mockResource, listOf("foo", "bar", "baz"))
        val comboBox = ResourceSelector.builder().resource(mockResource).awsConnection(projectRule.project).build()

        runInEdtAndWait {
            comboBox.selectedItem = "invalidItem"
        }

        comboBox.reload()

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo(null)
            }
        }
    }

    @Test
    fun canSpecifyWhichRegionAndCredentialsToUse() {
        resourceCache.addEntry(mockResource, "region1", "credential1", listOf("foo"))
        val comboBox = ResourceSelector.builder()
            .resource(mockResource)
            .awsConnection(ConnectionSettings(mockCred("credential1"), AwsRegion("region1", "", "aws")))
            .build()

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo("foo")
            }
        }
    }

    @Test
    fun onlyTheLastReloadIsApplied() {
        fun createMockResource(name: String): Triple<Resource.Cached<List<String>>, CompletableFuture<List<String>>, List<String>> {
            val future = CompletableFuture<List<String>>()
            val resource = mock<Resource.Cached<List<String>>> {
                on { id }.thenReturn(name)
            }

            resourceCache.addEntry(projectRule.project, resource, future)

            return Triple(resource, future, listOf(name))
        }

        // Create a bunch of different cache entries
        val resultList = listOf(
            createMockResource("1"),
            createMockResource("2"),
            createMockResource("3"),
            createMockResource("4"),
            createMockResource("5")
        )

        var counter = 0
        val comboBox = ResourceSelector.builder()
            .resource { resultList[counter].first }
            .awsConnection(projectRule.project)
            .disableAutomaticLoading()
            .build()

        val loadingStatus = mutableListOf<Boolean>()
        comboBox.addActionListener { loadingStatus.add(comboBox.isLoading) }

        // Trigger a reload for each resource to simulate a bunch of reloads against different cache entries
        runInEdtAndWait {
            resultList.forEach { _ ->
                comboBox.reload()
                counter++
            }
        }

        // Complete the cache load
        resultList.forEach {
            it.second.complete(it.third)
        }

        retryableAssert {
            runInEdtAndWait {
                assertThat(comboBox.selected()).isEqualTo("5")
                // 5 loads = 5 loadings + 1 loaded
                assertThat(loadingStatus).containsExactly(true, true, true, true, true, false)
            }
        }
    }

    private companion object {
        fun mockCred(id: String) = aToolkitCredentialsProvider(aCredentialsIdentifier(id))
    }
}


// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.ui

import com.intellij.openapi.ui.ComponentValidator
import com.intellij.openapi.ui.ValidationInfo
import com.intellij.testFramework.ApplicationRule
import com.intellij.testFramework.DisposableRule
import com.intellij.testFramework.EdtRule
import com.intellij.testFramework.RunsInEdt
import com.intellij.ui.components.JBTextField
import com.intellij.ui.layout.applyToComponent
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import javax.swing.JButton
import javax.swing.JTextField

@RunsInEdt
class ValidatingPanelTest {
    @Rule
    @JvmField
    val disposableRule = DisposableRule()

    @Rule
    @JvmField
    val executeOnEdtRule = EdtRule()

    @Rule
    @JvmField
    val appRule = ApplicationRule()

    @Test
    fun `valid panels can execute actions`() {
        val testPanel = TestPanel(initialTextValue = "Valid text")

        assertThat(testPanel.validatingButton.isEnabled).isTrue
        assertThat(testPanel.normalButton.isEnabled).isTrue

        assertThat(testPanel.executeValidatingButton()).isTrue
        assertThat(testPanel.executeNormalButton()).isTrue
    }

    @Test
    fun `invalid panels can only execute normal actions`() {
        val testPanel = TestPanel()

        assertThat(testPanel.validatingButton.isEnabled).isTrue
        assertThat(testPanel.normalButton.isEnabled).isTrue

        assertThat(testPanel.executeValidatingButton()).isFalse
        assertThat(testPanel.executeNormalButton()).isTrue

        assertThat(testPanel.validatingButton.isEnabled).isFalse
        assertThat(testPanel.normalButton.isEnabled).isTrue
    }

    @Test
    fun `errors get applied on executing a validating action`() {
        val testPanel = TestPanel()

        assertThat(testPanel.textFieldValidator?.validationInfo).isNull()

        assertThat(testPanel.executeValidatingButton()).isFalse
        assertThat(testPanel.validatingButton.isEnabled).isFalse

        assertThat(testPanel.textFieldValidator?.validationInfo?.message).isNotEmpty
    }

    @Test
    fun `errors get applied and cleared on typing`() {
        val testPanel = TestPanel()

        assertThat(testPanel.textFieldValidator?.validationInfo).isNull()
        assertThat(testPanel.validatingButton.isEnabled).isTrue

        testPanel.textFieldComponent.text = "Foo"

        assertThat(testPanel.textFieldValidator?.validationInfo?.message).isNotEmpty
        assertThat(testPanel.validatingButton.isEnabled).isFalse

        testPanel.textFieldComponent.text = "Valid Text"

        assertThat(testPanel.textFieldValidator?.validationInfo).isNull()
        assertThat(testPanel.validatingButton.isEnabled).isTrue
    }

    @Test
    fun `valid panels can apply their state`() {
        val initialText = "Initial Text"
        val updatedText = "Updated Text"
        val testPanel = TestPanel(initialTextValue = initialText)

        assertThat(testPanel.textFieldComponent.text).isEqualTo(initialText)

        testPanel.textFieldComponent.text = updatedText

        assertThat(testPanel.executeValidatingButton()).isTrue

        assertThat(testPanel.testText).isEqualTo(updatedText)
    }

    inner class TestPanel(initialTextValue: String = "") {
        var testText = initialTextValue

        private val validatingButtonName = "NeedsValidation"
        private val normalButtonName = "DoesNotNeedValidation"
        private var validatingButtonRan = false
        private var normalButtonRan = false
        lateinit var textFieldComponent: JTextField
            private set
        lateinit var validatingButton: JButton
            private set
        lateinit var normalButton: JButton
            private set

        @Suppress("UnusedPrivateMember")
        private val panel = validatingPanel(disposableRule.disposable) {
            row {
                validatingButton(validatingButtonName) {
                    validatingButtonRan = true
                }.applyToComponent {
                    validatingButton = this
                }

                button(normalButtonName) {
                    normalButtonRan = true
                }.applyToComponent {
                    normalButton = this
                }

                textField(::testText)
                    .withValidationOnInput { it.validateText() }
                    .withValidationOnApply { it.validateText() }
                    .applyToComponent {
                        textFieldComponent = this
                    }
            }
        }

        private fun JBTextField.validateText() = if (this.text.length < 5) ValidationInfo("Test Error, '${this.text}'.length() < 5", this) else null

        fun executeValidatingButton(): Boolean {
            validatingButtonRan = false
            validatingButton.doClick()
            return validatingButtonRan
        }

        fun executeNormalButton(): Boolean {
            normalButtonRan = false
            normalButton.doClick()
            return normalButtonRan
        }

        val textFieldValidator: ComponentValidator?
            get() = ComponentValidator.getInstance(textFieldComponent).orElse(null)
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.ui.feedback

import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.ui.DialogPanel
import com.intellij.testFramework.ProjectRule
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import software.amazon.awssdk.services.toolkittelemetry.model.Sentiment

class FeedbackTest {
    @Rule
    @JvmField
    val projectRule = ProjectRule()

    private lateinit var sut: FeedbackDialog
    private lateinit var sutPanel: DialogPanel

    @Test
    fun `Initial dialog with sentiment positive and no comment is valid`() {
        runInEdt {
            sut = FeedbackDialog(projectRule.project)
            sutPanel = sut.getFeedbackDialog()
            val validationErrors = sutPanel.validationsOnApply.flatMap { it.value }.filter { it.validate() != null }
            assertThat(validationErrors).isEmpty()
        }
    }

    @Test
    fun `Dialog with negative sentiment and comment is valid`() {
        runInEdt {
            sut = FeedbackDialog(projectRule.project, Sentiment.NEGATIVE, "test")
            sutPanel = sut.getFeedbackDialog()
            val validationErrors = sutPanel.validationsOnApply.flatMap { it.value }.filter { it.validate() != null }
            assertThat(validationErrors).isEmpty()
        }
    }
}


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.utils

import org.assertj.core.api.AbstractAssert
import org.assertj.core.api.AbstractThrowableAssert
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.CompletableFutureAssert
import java.time.Duration
import java.util.concurrent.CompletionStage
import java.util.concurrent.TimeUnit
import java.util.function.Consumer

private val TIMEOUT = Duration.ofSeconds(1)

fun <T> CompletableFutureAssert<T>.wait(): CompletableFutureAssert<T> {
    try {
        matches { it.get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS) != null }
    } catch (e: Exception) {
        // suppress
    }
    return this
}

fun <T> CompletableFutureAssert<T>.hasValue(value: T) {
    wait().isCompletedWithValue(value)
}

val <T> CompletionStage<T>.value get() = toCompletableFuture().get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS)

val <T> CompletableFutureAssert<T>.hasException get() = this.wait().isCompletedExceptionally

fun <SELF : AbstractThrowableAssert<SELF, ACTUAL>, ACTUAL : Throwable> AbstractThrowableAssert<SELF, ACTUAL>.hasCauseWithMessage(
    message: String
): AbstractThrowableAssert<SELF, ACTUAL> {
    satisfies { parentThrowable ->
        assertThat(parentThrowable.cause).isNotNull.hasMessage(message)
    }
    return this
}

inline fun <reified T> AbstractAssert<*, *>.isInstanceOf() = isInstanceOf(T::class.java)
inline fun <reified T> AbstractAssert<*, *>.isInstanceOfSatisfying(checker: Consumer<T>) = isInstanceOfSatisfying(T::class.java, checker)


// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.utils

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import software.aws.toolkits.core.utils.AttributeBag
import software.aws.toolkits.core.utils.AttributeBagKey

@Suppress("UNCHECKED_CAST")
class AttributeBagTest {
    @Test
    fun createAndRetrieveValuesWorks() {
        val bag = AttributeBag()
        val key = AttributeBagKey.create<String>("1234567890")
        bag.putData(key, "abc")
        assertThat(bag.get(key)).isEqualTo("abc")
    }

    @Test
    fun getNonexistentValueIsNull() {
        val bag = AttributeBag()
        val key = AttributeBagKey.create<String>("hjkl")
        assertThat(bag.get(key)).isNull()
    }

    @Test
    fun replacingValuesWorks() {
        val bag = AttributeBag()
        val key = AttributeBagKey.create<String>("23456754")
        bag.putData(key, "abc")
        bag.putData(key, "cdf")
        assertThat(bag.get(key)).isEqualTo("cdf")
    }

    @Test
    fun creatingTheSameValueIsIdempotent() {
        assertThat(AttributeBagKey.create<String>("fail")).isSameAs(AttributeBagKey.create<String>("fail"))
    }

    @Test(expected = NoSuchElementException::class)
    fun getOrThrowThrowsOnFailure() {
        val bag = AttributeBag()
        val key = AttributeBagKey.create<String>("asdf")
        bag.getOrThrow(key)
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.utils

import com.intellij.testFramework.ProjectRule
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineScope
import org.junit.After
import org.junit.Rule
import software.aws.toolkits.jetbrains.core.MockClientManagerRule

/*
 * BaseCoroutineTest contains utilities that are useful for testing corutines which would otherwise
 * have to be copy pasted. It is abstract so it is not implemented.
 */
@ExperimentalCoroutinesApi
abstract class BaseCoroutineTest(@Suppress("UnusedPrivateMember") timeoutSeconds: Int = 15) {
    @JvmField
    @Rule
    val projectRule = ProjectRule()

    @JvmField
    @Rule
    val mockClientManagerRule = MockClientManagerRule()

    // TODO: figure out why this doesn't work on 223 Windows
//    @JvmField
//    @Rule
//    val timeout = CoroutinesTimeout.seconds(timeoutSeconds)

    val testCoroutineScope: TestCoroutineScope = TestCoroutineScope()

    @After
    fun after() {
        testCoroutineScope.cleanupTestCoroutines()
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.utils

import com.intellij.util.ui.ListTableModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import software.aws.toolkits.jetbrains.ui.ResourceSelector
import software.aws.toolkits.resources.message

fun ResourceSelector<*>.waitToLoad() {
    runBlocking {
        // State gets set before the selected item gets set so we need to check for that too
        waitForTrue { selectedItem != message("loading_resource.loading") }
        waitForFalse { isLoading }
    }
}

suspend fun ListTableModel<*>.waitForModelToBeAtLeast(size: Int) {
    waitForFalse { items.size < size }
}

suspend fun waitForFalse(block: () -> Boolean) {
    while (block()) {
        delay(10)
    }
}

suspend fun waitForTrue(block: () -> Boolean) {
    while (!block()) {
        delay(10)
    }
}


// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.utils

import software.aws.toolkits.jetbrains.core.executables.ExecutableManager
import software.aws.toolkits.jetbrains.core.executables.ExecutableType
import software.aws.toolkits.jetbrains.services.lambda.sam.SamExecutable
import java.nio.file.Paths

fun setSamExecutableFromEnvironment() {
    val samPath = Paths.get(System.getenv().getOrDefault("SAM_CLI_EXEC", SamExecutable().resolve().toString()))
    ExecutableManager.getInstance()
        .setExecutablePath(ExecutableType.getInstance<SamExecutable>(), samPath)
        .toCompletableFuture().join()
}