Coverage for manila/tests/scheduler/filters/test_base.py: 100%

71 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright (c) 2013 OpenStack Foundation. 

2# 

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 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

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 

12# implied. 

13# See the License for the specific language governing permissions and 

14# limitations under the License. 

15 

16from unittest import mock 

17 

18from manila.scheduler.filters import base 

19from manila import test 

20 

21 

22class TestBaseFilter(test.TestCase): 

23 

24 def setUp(self): 

25 super(TestBaseFilter, self).setUp() 

26 self.filter = base.BaseFilter() 

27 

28 def test_filter_one_is_called(self): 

29 

30 filters = [1, 2, 3, 4] 

31 filter_properties = {'x': 'y'} 

32 

33 side_effect = lambda value, props: value in [2, 3] # noqa: E731 

34 self.mock_object(self.filter, 

35 '_filter_one', 

36 mock.Mock(side_effect=side_effect)) 

37 

38 result = list(self.filter.filter_all(filters, filter_properties)) 

39 

40 self.assertEqual([2, 3], result) 

41 

42 

43class FakeExtension(object): 

44 

45 def __init__(self, plugin): 

46 self.plugin = plugin 

47 

48 

49class BaseFakeFilter(base.BaseFilter): 

50 pass 

51 

52 

53class FakeFilter1(BaseFakeFilter): 

54 """Derives from BaseFakeFilter and has a fake entry point defined. 

55 

56 Entry point is returned by fake ExtensionManager. 

57 Should be included in the output of all_classes. 

58 """ 

59 

60 

61class FakeFilter2(BaseFakeFilter): 

62 """Derives from BaseFakeFilter but has no entry point. 

63 

64 Should be not included in all_classes. 

65 """ 

66 

67 

68class FakeFilter3(base.BaseFilter): 

69 """Does not derive from BaseFakeFilter. 

70 

71 Should not be included. 

72 """ 

73 

74 

75class FakeFilter4(BaseFakeFilter): 

76 """Derives from BaseFakeFilter and has an entry point. 

77 

78 Should be included. 

79 """ 

80 

81 

82class FakeFilter5(BaseFakeFilter): 

83 """Derives from BaseFakeFilter but has no entry point. 

84 

85 Should not be included. 

86 """ 

87 run_filter_once_per_request = True 

88 

89 

90class FakeExtensionManager(list): 

91 

92 def __init__(self, namespace): 

93 classes = [FakeFilter1, FakeFilter3, FakeFilter4] 

94 exts = map(FakeExtension, classes) 

95 super(FakeExtensionManager, self).__init__(exts) 

96 self.namespace = namespace 

97 

98 

99class TestBaseFilterHandler(test.TestCase): 

100 

101 def setUp(self): 

102 super(TestBaseFilterHandler, self).setUp() 

103 self.mock_object(base.base_handler.extension, 

104 'ExtensionManager', 

105 FakeExtensionManager) 

106 self.handler = base.BaseFilterHandler(BaseFakeFilter, 'fake_filters') 

107 

108 def test_get_all_classes(self): 

109 # In order for a FakeFilter to be returned by get_all_classes, it has 

110 # to comply with these rules: 

111 # * It must be derived from BaseFakeFilter 

112 # AND 

113 # * It must have a python entrypoint assigned (returned by 

114 # FakeExtensionManager) 

115 expected = [FakeFilter1, FakeFilter4] 

116 result = self.handler.get_all_classes() 

117 self.assertEqual(expected, result) 

118 

119 def _get_filtered_objects(self, filter_classes, index=0): 

120 filter_objs_initial = [1, 2, 3, 4] 

121 filter_properties = {'x': 'y'} 

122 return self.handler.get_filtered_objects(filter_classes, 

123 filter_objs_initial, 

124 filter_properties, 

125 index) 

126 

127 @mock.patch.object(FakeFilter4, 'filter_all') 

128 @mock.patch.object(FakeFilter3, 'filter_all', return_value=None) 

129 def test_get_filtered_objects_return_none(self, fake3_filter_all, 

130 fake4_filter_all): 

131 filter_classes = [FakeFilter1, FakeFilter2, FakeFilter3, FakeFilter4] 

132 result, last_filter = self._get_filtered_objects(filter_classes) 

133 self.assertIsNone(result) 

134 self.assertFalse(fake4_filter_all.called) 

135 self.assertEqual('FakeFilter3', last_filter) 

136 

137 def test_get_filtered_objects(self): 

138 filter_objs_expected = [1, 2, 3, 4] 

139 filter_classes = [FakeFilter1, FakeFilter2, FakeFilter3, FakeFilter4] 

140 result, last_filter = self._get_filtered_objects(filter_classes) 

141 self.assertEqual(filter_objs_expected, result) 

142 self.assertEqual('FakeFilter4', last_filter) 

143 

144 def test_get_filtered_objects_with_filter_run_once(self): 

145 filter_objs_expected = [1, 2, 3, 4] 

146 filter_classes = [FakeFilter5] 

147 

148 with mock.patch.object(FakeFilter5, 'filter_all', 

149 return_value=filter_objs_expected 

150 ) as fake5_filter_all: 

151 result, last_filter = self._get_filtered_objects(filter_classes) 

152 self.assertEqual(filter_objs_expected, result) 

153 self.assertEqual(1, fake5_filter_all.call_count) 

154 

155 result, last_filter = self._get_filtered_objects( 

156 filter_classes, index=1) 

157 self.assertEqual(filter_objs_expected, result) 

158 self.assertEqual(1, fake5_filter_all.call_count) 

159 

160 result, last_filter = self._get_filtered_objects( 

161 filter_classes, index=2) 

162 self.assertEqual(filter_objs_expected, result) 

163 self.assertEqual(1, fake5_filter_all.call_count)