# Copyright 2022 Red Hat, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License 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.

from unittest import mock

import eventlet

from neutron.common.ovn import constants as ovn_const
from neutron.plugins.ml2.drivers.ovn.agent import neutron_agent
from neutron.tests import base
from neutron.tests.unit import fake_resources as fakes


class AgentCacheTestCase(base.BaseTestCase):

    def setUp(self):
        super().setUp()
        self.agent_cache = neutron_agent.AgentCache(driver=mock.ANY)
        self.addCleanup(self._clean_agent_cache)
        self.names_ref = []
        for i in range(10):  # Add 10 agents.
            chassis_private = fakes.FakeOvsdbRow.create_one_ovsdb_row(
                attrs={'name': 'chassis' + str(i)})
            self.agent_cache.update(ovn_const.OVN_CONTROLLER_AGENT,
                                    chassis_private)
            self.names_ref.append('chassis' + str(i))

    def _clean_agent_cache(self):
        self.agent_cache.agents = {}

    def _list_agents(self):
        self.names_read = []
        for idx, agent in enumerate(self.agent_cache):
            self.names_read.append(agent.agent_id)
            if idx == 5:  # Swap to "_add_and_delete_agents" thread.
                eventlet.sleep(0)

    def _add_and_delete_agents(self):
        del self.agent_cache['chassis8']
        chassis_private = fakes.FakeOvsdbRow.create_one_ovsdb_row(
            attrs={'name': 'chassis10'})
        self.agent_cache.update(ovn_const.OVN_CONTROLLER_AGENT,
                                chassis_private)

    def test_update_while_iterating_agents(self):
        pool = eventlet.GreenPool(2)
        pool.spawn(self._list_agents)
        pool.spawn(self._add_and_delete_agents)
        pool.waitall()
        self.assertEqual(self.names_ref, self.names_read)

    def test_agents_by_chassis_private(self):
        chassis_private = fakes.FakeOvsdbRow.create_one_ovsdb_row(
            attrs={'name': 'chassis5'})
        agents = self.agent_cache.agents_by_chassis_private(chassis_private)
        agents = list(agents)
        self.assertEqual(1, len(agents))
        self.assertEqual('chassis5', agents[0].agent_id)
