# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import botocore.session
import json
import errno

from awscli.testutils import mock, unittest
from awscli.customizations.ecs import executecommand


class TestExecuteCommand(unittest.TestCase):

    def setUp(self):
        self.session = mock.Mock(botocore.session.Session)
        self.client = mock.Mock()
        self.region = 'us-west-2'
        self.profile = 'testProfile'
        self.endpoint_url = 'testUrl'
        self.client.meta.region_name = self.region
        self.client.meta.endpoint_url = self.endpoint_url
        self.caller = executecommand.ExecuteCommandCaller(self.session)
        self.session.profile = self.profile
        self.session.create_client.return_value = self.client
        self.execute_command_params = {
            "cluster": "default",
            "task": "someTaskId",
            "command": "ls",
            "interactive": "true"}
        self.execute_command_response = {
            "containerName": "someContainerName",
            "containerArn": "ecs/someContainerArn",
            "taskArn": "ecs/someTaskArn",
            "session": {"sessionId": "session-id",
                        "tokenValue": "token-value",
                        "streamUrl": "stream-url"},
            "clusterArn": "ecs/someClusterArn",
            "interactive": "true"
        }
        self.describe_tasks_response = {
            "failures": [],
            "tasks": [
                {
                    "clusterArn": "ecs/someCLusterArn",
                    "desiredStatus": "RUNNING",
                    "createdAt": "1611619514.46",
                    "taskArn": "someTaskArn",
                    "containers": [
                        {
                            "containerArn": "ecs/someContainerArn",
                            "taskArn": "ecs/someTaskArn",
                            "name": "someContainerName",
                            "managedAgents": [
                             {
                                 "reason": "Execute Command Agent started",
                                 "lastStatus": "RUNNING",
                                 "lastStartedAt": "1611619528.272",
                                 "name": "ExecuteCommandAgent"
                             }
                             ],
                            "runtimeId": "someRuntimeId"
                        },
                        {
                            "containerArn": "ecs/dummyContainerArn",
                            "taskArn": "ecs/someTaskArn",
                            "name": "dummyContainerName",
                            "managedAgents": [
                                {
                                    "reason": "Execute Command Agent started",
                                    "lastStatus": "RUNNING",
                                    "lastStartedAt": "1611619528.272",
                                    "name": "ExecuteCommandAgent"
                                }
                            ],
                            "runtimeId": "dummyRuntimeId"
                        }
                    ],
                    "lastStatus": "RUNNING",
                    "enableExecuteCommand": "true"
                }
            ]
        }
        self.describe_tasks_response_fail = {
            "failures": [
                {
                    "reason": "MISSING",
                    "arn": "someTaskArn"
                }
            ],
            "tasks": []
        }
        self.ssm_request_parameters = {
            "Target": "ecs:someClusterArn_someTaskArn_someRuntimeId"
        }

    @mock.patch('awscli.customizations.ecs.executecommand.check_call')
    def test_when_calls_fails_from_ecs(self, mock_check_call):
        self.client.execute_command.side_effect = Exception('some exception')
        mock_check_call.return_value = 0
        with self.assertRaisesRegex(Exception, 'some exception'):
            self.caller.invoke('ecs', 'ExecuteCommand', {}, mock.Mock())

    @mock.patch('awscli.customizations.ecs.executecommand.check_call')
    def test_when_session_manager_plugin_not_installed(self, mock_check_call):
        mock_check_call.side_effect = [OSError(errno.ENOENT, 'some error'), 0]

        with self.assertRaises(ValueError):
            self.caller.invoke('ecs', 'ExecuteCommand', {}, mock.Mock())

    @mock.patch('awscli.customizations.ecs.executecommand.check_call')
    def test_execute_command_success(self, mock_check_call):
        mock_check_call.return_value = 0

        self.client.execute_command.return_value = \
            self.execute_command_response
        self.client.describe_tasks.return_value = self.describe_tasks_response

        rc = self.caller.invoke('ecs', 'ExecuteCommand',
                                self.execute_command_params, mock.Mock())

        self.assertEqual(rc, 0)
        self.client.execute_command.\
            assert_called_with(**self.execute_command_params)

        mock_check_call_list = mock_check_call.call_args[0][0]
        mock_check_call_list[1] = json.loads(mock_check_call_list[1])
        self.assertEqual(
            mock_check_call_list,
            ['session-manager-plugin',
             self.execute_command_response["session"],
             self.region,
             'StartSession',
             self.profile,
             json.dumps(self.ssm_request_parameters),
             self.endpoint_url
             ]
        )

    @mock.patch('awscli.customizations.ecs.executecommand.check_call')
    def test_when_describe_task_fails(self, mock_check_call):
        mock_check_call.return_value = 0

        self.client.execute_command.return_value = \
            self.execute_command_response
        self.client.describe_tasks.side_effect = \
            Exception("Some Server Exception")

        with self.assertRaisesRegex(Exception, 'Some Server Exception'):
            rc = self.caller.invoke('ecs', 'ExecuteCommand',
                                    self.execute_command_params, mock.Mock())
            self.assertEqual(rc, 0)
            self.client.execute_command. \
                assert_called_with(**self.execute_command_params)

    @mock.patch('awscli.customizations.ecs.executecommand.check_call')
    def test_when_describe_task_returns_no_tasks(self, mock_check_call):
        mock_check_call.return_value = 0

        self.client.execute_command.return_value = \
            self.execute_command_response
        self.client.describe_tasks.return_value = \
            self.describe_tasks_response_fail

        with self.assertRaises(Exception):
            rc = self.caller.invoke('ecs', 'ExecuteCommand',
                                    self.execute_command_params, mock.Mock())
            self.assertEqual(rc, 0)
            self.client.execute_command. \
                assert_called_with(**self.execute_command_params)

    @mock.patch('awscli.customizations.ecs.executecommand.check_call')
    def test_when_check_call_fails(self, mock_check_call):
        mock_check_call.side_effect = [0, Exception('some Exception')]

        self.client.execute_command.return_value = \
            self.execute_command_response
        self.client.describe_tasks.return_value = self.describe_tasks_response

        with self.assertRaises(Exception):
            self.caller.invoke('ecs', 'ExecuteCommand',
                               self.execute_command_params, mock.Mock())

            mock_check_call_list = mock_check_call.call_args[0][0]
            mock_check_call_list[1] = json.loads(mock_check_call_list[1])
            self.assertEqual(
                mock_check_call_list,
                ['session-manager-plugin',
                 self.execute_command_response["session"],
                 self.region,
                 'StartSession',
                 self.profile,
                 json.dumps(self.ssm_request_parameters),
                 self.endpoint_url],
            )
