1 # Copyright 2020 Canonical Ltd.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
18 from unittest
import mock
, TestCase
19 from unittest
.mock
import Mock
20 from n2vc
.juju_watcher
import JujuModelWatcher
, entity_ready
, status
21 from n2vc
.exceptions
import EntityInvalidException
22 from .utils
import FakeN2VC
, AsyncMock
, Deltas
, FakeWatcher
23 from juju
.application
import Application
24 from juju
.model
import Model
25 from juju
.annotation
import Annotation
26 from juju
.machine
import Machine
27 from juju
.action
import Action
30 class JujuWatcherTest(asynctest
.TestCase
):
32 self
.n2vc
= FakeN2VC()
34 self
.loop
= asyncio
.new_event_loop()
36 def test_get_status(self
):
39 (status
, message
, vca_status
) = JujuModelWatcher
.get_status(test
.delta
)
40 self
.assertEqual(status
, test
.entity_status
.status
)
41 self
.assertEqual(message
, test
.entity_status
.message
)
42 self
.assertEqual(vca_status
, test
.entity_status
.vca_status
)
44 @mock.patch("n2vc.juju_watcher.client.AllWatcherFacade.from_connection")
45 def test_model_watcher(self
, allwatcher
):
47 allwatcher
.return_value
= FakeWatcher()
49 with self
.assertRaises(asyncio
.TimeoutError
):
50 allwatcher
.return_value
.delta_to_return
= [test
.delta
]
51 self
.loop
.run_until_complete(
52 JujuModelWatcher
.model_watcher(
54 test
.filter.entity_id
,
55 test
.filter.entity_type
,
57 db_dict
={"something"},
62 self
.assertEqual(self
.n2vc
.last_written_values
, test
.db
.data
)
63 self
.n2vc
.last_written_values
= None
65 @mock.patch("n2vc.juju_watcher.asyncio.wait")
66 def test_wait_for(self
, wait
):
67 wait
.return_value
= asyncio
.Future()
68 wait
.return_value
.set_result(None)
71 self
.loop
.run_until_complete(JujuModelWatcher
.wait_for(self
.model
, machine
))
73 @mock.patch("n2vc.juju_watcher.asyncio.wait")
74 def test_wait_for_exception(self
, wait
):
75 wait
.return_value
= asyncio
.Future()
76 wait
.return_value
.set_result(None)
77 wait
.side_effect
= Exception("error")
80 with self
.assertRaises(Exception):
81 self
.loop
.run_until_complete(JujuModelWatcher
.wait_for(self
.model
, machine
))
83 def test_wait_for_invalid_entity_exception(self
):
84 with self
.assertRaises(EntityInvalidException
):
85 self
.loop
.run_until_complete(
86 JujuModelWatcher
.wait_for(
88 Annotation(0, self
.model
),
90 progress_timeout
=None,
95 class EntityReadyTest(TestCase
):
96 @mock.patch("juju.application.Application.units")
97 def setUp(self
, mock_units
):
99 self
.model
._connector
= mock
.MagicMock()
101 def test_invalid_entity(self
):
102 with self
.assertRaises(EntityInvalidException
):
103 entity_ready(Annotation(0, self
.model
))
105 @mock.patch("juju.machine.Machine.agent_status")
106 def test_machine_entity(self
, mock_machine_agent_status
):
107 entity
= Machine(0, self
.model
)
108 self
.assertEqual(entity
.entity_type
, "machine")
109 self
.assertTrue(isinstance(entity_ready(entity
), bool))
111 @mock.patch("juju.action.Action.status")
112 def test_action_entity(self
, mock_action_status
):
113 entity
= Action(0, self
.model
)
114 self
.assertEqual(entity
.entity_type
, "action")
115 self
.assertTrue(isinstance(entity_ready(entity
), bool))
117 @mock.patch("juju.application.Application.status")
118 def test_application_entity(self
, mock_application_status
):
119 entity
= Application(0, self
.model
)
120 self
.assertEqual(entity
.entity_type
, "application")
121 self
.assertTrue(isinstance(entity_ready(entity
), bool))
124 class StatusTest(TestCase
):
127 self
.model
._connector
= mock
.MagicMock()
129 @mock.patch("n2vc.juju_watcher.derive_status")
130 def test_invalid_entity(self
, mock_derive_status
):
131 application
= mock
.MagicMock()
132 mock_derive_status
.return_value
= "active"
136 def workload_status(self
):
139 application
.units
= [FakeUnit()]
140 value
= status(application
)
141 mock_derive_status
.assert_called_once()
142 self
.assertTrue(isinstance(value
, str))