Coverage for manila/tests/share/drivers/vastdata/test_driver_util.py: 98%
130 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright 2024 VAST Data Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15import json
16import pickle
17from unittest import mock
19import ddt
21from manila.share.drivers.vastdata import driver_util
22from manila import test
25driver_util.CONF.debug = True
28@ddt.ddt
29class TestBunch(test.TestCase):
30 def setUp(self):
31 super(TestBunch, self).setUp()
32 self.bunch = driver_util.Bunch(a=1, b=2)
34 def test_bunch_getattr(self):
35 self.assertEqual(self.bunch.a, 1)
37 def test_bunch_setattr(self):
38 self.bunch.c = 3
39 self.assertEqual(self.bunch.c, 3)
41 def test_bunch_delattr(self):
42 del self.bunch.a
43 self.assertRaises(AttributeError, lambda: self.bunch.a)
45 def test_bunch_to_dict(self):
46 self.assertEqual(self.bunch.to_dict(), {"a": 1, "b": 2})
48 def test_bunch_from_dict(self):
49 self.assertEqual(
50 driver_util.Bunch.from_dict({"a": 1, "b": 2}), self.bunch
51 )
53 def test_bunch_to_json(self):
54 self.assertEqual(self.bunch.to_json(), json.dumps({"a": 1, "b": 2}))
56 def test_bunch_without(self):
57 self.assertEqual(self.bunch.without("a"), driver_util.Bunch(b=2))
59 def test_bunch_but_with(self):
60 self.assertEqual(
61 self.bunch.but_with(c=3), driver_util.Bunch(a=1, b=2, c=3)
62 )
64 def test_bunch_delattr_missing(self):
65 self.assertRaises(
66 AttributeError,
67 lambda: self.bunch.__delattr__("non_existing_attribute")
68 )
70 def test_bunch_from_json(self):
71 json_bunch = json.dumps({"a": 1, "b": 2})
72 self.assertEqual(driver_util.Bunch.from_json(json_bunch), self.bunch)
74 def test_bunch_render(self):
75 self.assertEqual(self.bunch.render(), "a=1, b=2")
77 def test_bunch_pickle(self):
78 pickled_bunch = pickle.dumps(self.bunch)
79 unpickled_bunch = pickle.loads(pickled_bunch)
80 self.assertEqual(self.bunch, unpickled_bunch)
82 @ddt.data(True, False)
83 def test_bunch_copy(self, deep):
84 copy_bunch = self.bunch.copy(deep=deep)
85 self.assertEqual(copy_bunch, self.bunch)
86 self.assertIsNot(copy_bunch, self.bunch)
88 def test_name_starts_with_underscore_and_digit(self):
89 bunch = driver_util.Bunch()
90 bunch["1"] = "value"
91 self.assertEqual(bunch._1, "value")
93 def test_bunch_recursion(self):
94 x = driver_util.Bunch(
95 a="a", b="b", d=driver_util.Bunch(x="axe", y="why")
96 )
97 x.d.x = x
98 x.d.y = x.b
99 print(x)
101 def test_bunch_repr(self):
102 self.assertEqual(repr(self.bunch), "Bunch(a=1, b=2)")
104 def test_getitem_with_integral_key(self):
105 self.bunch["1"] = "value"
106 self.assertEqual(self.bunch[1], "value")
108 def test_bunch_dir(self):
109 self.assertEqual(
110 set(i for i in dir(self.bunch) if not i.startswith("_")),
111 {
112 "a",
113 "b",
114 "but_with",
115 "clear",
116 "copy",
117 "from_dict",
118 "from_json",
119 "fromkeys",
120 "get",
121 "items",
122 "keys",
123 "pop",
124 "popitem",
125 "render",
126 "setdefault",
127 "to_dict",
128 "to_json",
129 "update",
130 "values",
131 "without",
132 },
133 )
135 def test_bunch_edge_cases(self):
136 # Test edge cases for attribute access, setting, and deletion
137 self.bunch["key-with-special-chars_123"] = "value"
138 self.assertEqual(self.bunch["key-with-special-chars_123"], "value")
139 self.bunch["key-with-special-chars_123"] = None
140 self.assertIsNone(self.bunch["key-with-special-chars_123"])
141 del self.bunch["key-with-special-chars_123"]
142 self.assertRaises(
143 KeyError,
144 lambda: self.bunch["key-with-special-chars_123"]
145 )
147 def test_bunch_deep_copy(self):
148 nested_bunch = driver_util.Bunch(x=driver_util.Bunch(y=1))
149 deep_copy = nested_bunch.copy(deep=True)
150 self.assertIsNot(nested_bunch["x"], deep_copy["x"])
151 self.assertEqual(nested_bunch["x"]["y"], deep_copy["x"]["y"])
153 def test_bunch_serialization(self):
154 # Test serialization with nested structures
155 nested_bunch = driver_util.Bunch(a=1, b=driver_util.Bunch(c=2))
156 self.assertEqual(nested_bunch.to_dict(), {"a": 1, "b": {"c": 2}})
157 self.assertEqual(
158 nested_bunch.to_json(),
159 json.dumps({"a": 1, "b": {"c": 2}})
160 )
163class TestBunchify(test.TestCase):
164 def test_bunchify(self):
165 self.assertEqual(
166 driver_util.bunchify({"a": 1, "b": 2}, c=3),
167 driver_util.Bunch(a=1, b=2, c=3)
168 )
169 x = driver_util.bunchify(dict(a=[dict(b=5), 9, (1, 2)], c=8))
170 self.assertEqual(x.a[0].b, 5)
171 self.assertEqual(x.a[1], 9)
172 self.assertIsInstance(x.a[2], tuple)
173 self.assertEqual(x.c, 8)
174 self.assertEqual(x.pop("c"), 8)
176 def test_bunchify_edge_cases(self):
177 # Test edge cases for bunchify function
178 self.assertEqual(driver_util.bunchify({}), driver_util.Bunch())
180 def test_bunchify_nested_structures(self):
181 # Test bunchify with nested structures
182 nested_dict = {"a": [{"b": 1}, 2]}
183 self.assertEqual(driver_util.bunchify(nested_dict).a[0].b, 1)
186class TestUnbunchify(test.TestCase):
187 def test_unbunchify(self):
188 self.assertEqual(
189 driver_util.unbunchify(driver_util.Bunch(a=1, b=2)),
190 {"a": 1, "b": 2}
191 )
194@ddt.ddt
195class TestGenerateIpRange(test.TestCase):
197 @ddt.data(
198 (
199 [["15.0.0.1", "15.0.0.4"], ["10.0.0.27", "10.0.0.30"]],
200 [
201 "15.0.0.1",
202 "15.0.0.2",
203 "15.0.0.3",
204 "15.0.0.4",
205 "10.0.0.27",
206 "10.0.0.28",
207 "10.0.0.29",
208 "10.0.0.30",
209 ],
210 ),
211 (
212 [["15.0.0.1", "15.0.0.1"], ["10.0.0.20", "10.0.0.20"]],
213 ["15.0.0.1", "10.0.0.20"],
214 ),
215 ([], []),
216 )
217 @ddt.unpack
218 def test_generate_ip_range(self, ip_ranges, expected):
219 ips = driver_util.generate_ip_range(ip_ranges)
220 assert ips == expected
222 def test_generate_ip_range_edge_cases(self):
223 # Test edge cases for generate_ip_range function
224 self.assertEqual(driver_util.generate_ip_range([]), [])
225 self.assertEqual(driver_util.generate_ip_range(
226 [["15.0.0.1", "15.0.0.1"]]), ["15.0.0.1"]
227 )
229 def test_generate_ip_range_large_range(self):
230 # Test with a large range of IPs
231 start_ip = "192.168.0.1"
232 end_ip = "192.168.255.255"
233 ips = driver_util.generate_ip_range([[start_ip, end_ip]])
234 self.assertEqual(len(ips), 65535)
237class MockClass1:
238 def method1(self):
239 return 1
241 def _private_method(self):
242 return 2
245class TestDecorateMethodsWith(test.TestCase):
247 def test_decorate_methods_with(self):
248 decorated_cls = driver_util.decorate_methods_with(
249 mock.Mock())(MockClass1)
250 self.assertTrue(hasattr(decorated_cls, 'method1'))
251 self.assertTrue(hasattr(decorated_cls, '_private_method'))
254class MockClass2:
255 @driver_util.verbose_driver_trace
256 def method1(self):
257 return 1
260class TestVerboseDriverTrace(test.TestCase):
262 def test_verbose_driver_trace_debug_true(self):
263 mock_instance = MockClass2()
264 with mock.patch.object(
265 driver_util.LOG, 'debug') as mock_debug:
266 mock_instance.method1()
267 self.assertEqual(mock_debug.call_count, 2)