# Copyright (C) 2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import time

from cassandra.cqlengine import columns
from resultsdbpy.controller.configuration import Configuration
from fakeredis import FakeStrictRedis
from redis import StrictRedis
from resultsdbpy.model.cassandra_context import CassandraContext
from resultsdbpy.model.commit_context import CommitContext
from resultsdbpy.model.configuration_context import ConfigurationContext, ClusteredByConfiguration
from resultsdbpy.model.mock_cassandra_context import MockCassandraContext
from resultsdbpy.model.wait_for_docker_test_case import WaitForDockerTestCase


class ConfigurationContextTest(WaitForDockerTestCase):
    KEYSPACE = 'configuration_context_test_keyspace'
    CONFIGURATIONS = [
        Configuration(platform='Mac', version='10.13.0', sdk='17A405', is_simulator=False, architecture='x86_64', style='Debug', flavor='wk1'),
        Configuration(platform='Mac', version='10.13.0', sdk='17A405', is_simulator=False, architecture='x86_64', style='Debug', flavor='wk2'),
        Configuration(platform='Mac', version='10.13.0', sdk='17A405', is_simulator=False, architecture='x86_64', style='Release', flavor='wk1'),
        Configuration(platform='Mac', version='10.13.0', sdk='17A405', is_simulator=False, architecture='x86_64', style='Release', flavor='wk2'),
        Configuration(platform='Mac', version='10.13.0', sdk='17A405', is_simulator=False, architecture='x86_64', style='Asan', flavor='wk1'),
        Configuration(platform='Mac', version='10.13.0', sdk='17A405', is_simulator=False, architecture='x86_64', style='Asan', flavor='wk2'),
        Configuration(platform='Mac', version='10.14.0', sdk='18A391', is_simulator=False, architecture='x86_64', style='Debug', flavor='wk1'),
        Configuration(platform='Mac', version='10.14.0', sdk='18A391', is_simulator=False, architecture='x86_64', style='Debug', flavor='wk2'),
        Configuration(platform='Mac', version='10.14.0', sdk='18A391', is_simulator=False, architecture='x86_64', style='Release', flavor='wk1'),
        Configuration(platform='Mac', version='10.14.0', sdk='18A391', is_simulator=False, architecture='x86_64', style='Release', flavor='wk2'),
        Configuration(platform='Mac', version='10.14.0', sdk='18A391', is_simulator=False, architecture='x86_64', style='Asan', flavor='wk1'),
        Configuration(platform='Mac', version='10.14.0', sdk='18A391', is_simulator=False, architecture='x86_64', style='Asan', flavor='wk2'),
        Configuration(platform='iOS', version='11.0.0', sdk='15A432', is_simulator=True, architecture='x86_64', style='Debug'),
        Configuration(platform='iOS', version='11.0.0', sdk='15A432', is_simulator=True, architecture='x86_64', style='Release'),
        Configuration(platform='iOS', version='11.0.0', sdk='15A432', is_simulator=True, architecture='x86_64', style='Asan'),
        Configuration(platform='iOS', version='11.0.0', sdk='15A432', is_simulator=False, architecture='arm64', model='iPhone 8', style='Debug'),
        Configuration(platform='iOS', version='11.0.0', sdk='15A432', is_simulator=False, architecture='arm64', model='iPhone 8', style='Release'),
        Configuration(platform='iOS', version='11.0.0', sdk='15A432', is_simulator=False, architecture='arm64', model='iPhone 8', style='Asan'),
        Configuration(platform='iOS', version='12.0.0', sdk='16A404', is_simulator=True, architecture='x86_64', style='Debug'),
        Configuration(platform='iOS', version='12.0.0', sdk='16A404', is_simulator=True, architecture='x86_64', style='Release'),
        Configuration(platform='iOS', version='12.0.0', sdk='16A404', is_simulator=True, architecture='x86_64', style='Asan'),
        Configuration(platform='iOS', version='12.0.0', sdk='16A404', is_simulator=False, architecture='arm64', model='iPhone Xs', style='Debug'),
        Configuration(platform='iOS', version='12.0.0', sdk='16A404', is_simulator=False, architecture='arm64', model='iPhone 8', style='Release'),
        Configuration(platform='iOS', version='12.0.0', sdk='16A404', is_simulator=False, architecture='arm64', model='iPhone Xs', style='Asan'),
    ]

    def init_database(self, redis=StrictRedis, cassandra=CassandraContext):
        cassandra.drop_keyspace(keyspace=self.KEYSPACE)
        self.database = ConfigurationContext(
            redis=redis(),
            cassandra=cassandra(keyspace=self.KEYSPACE, create_keyspace=True),
        )

    def register_configurations(self):
        current = time.time()
        old = current - 60 * 60 * 24 * 21

        for configuration in self.CONFIGURATIONS:
            if (configuration.platform == 'Mac' and configuration.version <= Configuration.version_to_integer('10.13')) \
               or (configuration.platform == 'iOS' and configuration.version <= Configuration.version_to_integer('11')):
                self.database.register_configuration(configuration, branch=None, timestamp=old)
            else:
                self.database.register_configuration(configuration, branch=None, timestamp=current)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_invalid_configuration(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)

        with self.assertRaises(TypeError):
            self.database.register_configuration('invalid object')
        with self.assertRaises(TypeError):
            self.database.register_configuration(Configuration(platform='iOS'))

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_no_style_configuration(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)

        self.database.register_configuration(Configuration(
            platform='Mac', version='10.13.0', sdk='17A405', is_simulator=False, architecture='x86_64',
        ))

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_configuration_by_platform(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        configuration_to_search_for = Configuration(platform='Mac', style='Debug')
        matching_configurations = self.database.search_for_configuration(configuration_to_search_for)
        self.assertEqual(4, len(matching_configurations))
        for config in matching_configurations:
            self.assertEqual(configuration_to_search_for, config)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_configuration_by_platform_with_flavor(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        configuration_to_search_for = Configuration(platform='Mac', style='Debug', flavor='wk1')
        matching_configurations = self.database.search_for_configuration(configuration_to_search_for)
        self.assertEqual(2, len(matching_configurations))
        for config in matching_configurations:
            self.assertEqual(configuration_to_search_for, config)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_configuration_by_platform_and_version(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        configuration_to_search_for = Configuration(platform='Mac', version='10.13', style='Release')
        matching_configurations = self.database.search_for_configuration(configuration_to_search_for)
        self.assertEqual(2, len(matching_configurations))
        for config in matching_configurations:
            self.assertEqual(configuration_to_search_for, config)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_configuration_by_model(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()
        configuration_to_search_for = Configuration(model='iPhone 8')
        matching_configurations = self.database.search_for_configuration(configuration_to_search_for)
        self.assertEqual(4, len(matching_configurations))
        for config in matching_configurations:
            self.assertEqual(configuration_to_search_for, config)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_configuration_by_architecture(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        configuration_to_search_for = Configuration(architecture='x86_64', style='Release')
        matching_configurations = self.database.search_for_configuration(configuration_to_search_for)
        self.assertEqual(6, len(matching_configurations))
        for config in matching_configurations:
            self.assertEqual(configuration_to_search_for, config)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_recent_configurations(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        recent_configurations = self.database.search_for_recent_configuration()
        self.assertEqual(12, len(recent_configurations))

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_expired_configurations(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        recent_configurations = self.database.search_for_configuration()
        self.assertEqual(24, len(recent_configurations))

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_recent_configurations_constrained(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        configuration_to_search_for = Configuration(architecture='arm64', style='Release')
        matching_configurations = self.database.search_for_recent_configuration(configuration_to_search_for)
        self.assertEqual(1, len(matching_configurations))
        self.assertEqual(matching_configurations[0], configuration_to_search_for)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_recent_configurations_constrained_by_version(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        configuration_to_search_for = Configuration(version='12', is_simulator=True)
        matching_configurations = self.database.search_for_recent_configuration(configuration_to_search_for)
        self.assertEqual(3, len(matching_configurations))
        for config in matching_configurations:
            self.assertEqual(configuration_to_search_for, config)

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_repopulate_recent(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        self.database.redis.flushdb()

        database = ConfigurationContext(redis=self.database.redis, cassandra=self.database.cassandra)
        self.assertEqual(12, len(database.search_for_recent_configuration()))

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_partition_by_configuration(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        class ExampleModel(ClusteredByConfiguration):
            __table_name__ = 'example_table'
            index = columns.Integer(primary_key=True, required=True)
            sdk = columns.Text(primary_key=True, required=True)
            json = columns.Text()

        with self.database:
            self.database.cassandra.create_table(ExampleModel)
            for configuration in self.CONFIGURATIONS:
                for i in range(5):
                    self.database.insert_row_with_configuration(ExampleModel.__table_name__, configuration, index=i, sdk=configuration.sdk, json=configuration.to_json())

            for configuration in self.CONFIGURATIONS:
                result = self.database.select_from_table_with_configurations(ExampleModel.__table_name__, [configuration], index=2).get(configuration, [])
                self.assertEqual(1, len(result), f'Searching by {configuration} failed, found {len(result)} elements and expected 1')
                self.assertEqual(result[0].json, configuration.to_json())

    @WaitForDockerTestCase.mock_if_no_docker(mock_redis=FakeStrictRedis, mock_cassandra=MockCassandraContext)
    def test_partition_by_partial_configuration(self, redis=StrictRedis, cassandra=CassandraContext):
        self.init_database(redis=redis, cassandra=cassandra)
        self.register_configurations()

        class ExampleModel(ClusteredByConfiguration):
            __table_name__ = 'example_table'
            index = columns.Integer(primary_key=True, required=True)
            json = columns.Text()

        with self.database:
            self.database.cassandra.create_table(ExampleModel)
            for configuration in self.CONFIGURATIONS:
                for i in range(5):
                    self.database.insert_row_with_configuration(ExampleModel.__table_name__, configuration, index=i, json=configuration.to_json())

            configuration_to_search_for = Configuration(model='iPhone Xs')
            results = self.database.select_from_table_with_configurations(ExampleModel.__table_name__, [configuration_to_search_for], index=4)
            self.assertEqual(2, len(results), f'Searching by {configuration_to_search_for} failed, found {len(results)} elements and expected 2')
            for key, value in results.items():
                self.assertEqual(Configuration.from_json(value[0].json), Configuration.from_json(key.to_json()))
