3030class TestPrometheusExtractor :
3131 """Test the Prometheus extractor."""
3232
33+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor._get_nova_client" )
34+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor.__init__" )
3335 @mock .patch ("caso.extract.prometheus.requests.get" )
34- def test_extract_with_results (self , mock_get ):
36+ def test_extract_with_results (self , mock_get , mock_base_init , mock_get_nova ):
3537 """Test extraction with successful Prometheus query."""
3638 # Configure CONF
3739 CONF .set_override ("site_name" , "TEST-Site" )
3840 CONF .set_override ("service_name" , "TEST-Service" )
3941
42+ # Mock the base class __init__ to do nothing
43+ mock_base_init .return_value = None
44+
45+ # Mock Nova client and servers
46+ mock_server1 = mock .Mock ()
47+ mock_server1 .id = "vm-uuid-1"
48+ mock_server1 .name = "test-vm-1"
49+
50+ mock_server2 = mock .Mock ()
51+ mock_server2 .id = "vm-uuid-2"
52+ mock_server2 .name = "test-vm-2"
53+
54+ mock_nova = mock .Mock ()
55+ mock_nova .servers .list .return_value = [mock_server1 , mock_server2 ]
56+ mock_get_nova .return_value = mock_nova
57+
58+ # Create extractor and manually set required attributes
59+ extractor = PrometheusExtractor ("test-project" , "test-vo" )
60+ extractor .project = "test-project"
61+ extractor .vo = "test-vo"
62+ extractor .project_id = "test-project-id"
63+
4064 # Mock Prometheus response
4165 mock_response = mock .Mock ()
4266 mock_response .json .return_value = {
@@ -53,54 +77,74 @@ def test_extract_with_results(self, mock_get):
5377 mock_response .raise_for_status = mock .Mock ()
5478 mock_get .return_value = mock_response
5579
56- # Create extractor
57- extractor = PrometheusExtractor ("test-project" , "test-vo" )
58-
5980 # Extract records
6081 extract_from = datetime .datetime (2023 , 5 , 25 , 0 , 0 , 0 )
6182 extract_to = datetime .datetime (2023 , 5 , 25 , 23 , 59 , 59 )
6283 records = extractor .extract (extract_from , extract_to )
6384
64- # Verify
65- assert len (records ) == 1
85+ # Verify - should create 2 records (one per VM)
86+ assert len (records ) == 2
6687 assert records [0 ].energy_consumption == 125.5
6788 assert records [0 ].energy_unit == "kWh"
6889 assert records [0 ].fqan == "test-vo"
6990
70- @mock .patch ("caso.extract.prometheus.requests.get" )
71- def test_extract_with_no_results (self , mock_get ):
72- """Test extraction when Prometheus returns no results."""
91+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor._get_nova_client" )
92+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor.__init__" )
93+ def test_extract_with_no_vms (self , mock_base_init , mock_get_nova ):
94+ """Test extraction when there are no VMs."""
7395 # Configure CONF
7496 CONF .set_override ("site_name" , "TEST-Site" )
7597 CONF .set_override ("service_name" , "TEST-Service" )
7698
77- # Mock Prometheus response with no results
78- mock_response = mock .Mock ()
79- mock_response .json .return_value = {
80- "status" : "success" ,
81- "data" : {"result" : []},
82- }
83- mock_response .raise_for_status = mock .Mock ()
84- mock_get .return_value = mock_response
99+ # Mock the base class __init__ to do nothing
100+ mock_base_init .return_value = None
85101
86- # Create extractor
102+ # Mock Nova client with no servers
103+ mock_nova = mock .Mock ()
104+ mock_nova .servers .list .return_value = []
105+ mock_get_nova .return_value = mock_nova
106+
107+ # Create extractor and manually set required attributes
87108 extractor = PrometheusExtractor ("test-project" , "test-vo" )
109+ extractor .project = "test-project"
110+ extractor .vo = "test-vo"
111+ extractor .project_id = "test-project-id"
88112
89113 # Extract records
90114 extract_from = datetime .datetime (2023 , 5 , 25 , 0 , 0 , 0 )
91115 extract_to = datetime .datetime (2023 , 5 , 25 , 23 , 59 , 59 )
92116 records = extractor .extract (extract_from , extract_to )
93117
94- # Verify
118+ # Verify - no VMs, no records
95119 assert len (records ) == 0
96120
121+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor._get_nova_client" )
122+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor.__init__" )
97123 @mock .patch ("caso.extract.prometheus.requests.get" )
98- def test_extract_with_failed_query (self , mock_get ):
124+ def test_extract_with_failed_query (self , mock_get , mock_base_init , mock_get_nova ):
99125 """Test extraction when Prometheus query fails."""
100126 # Configure CONF
101127 CONF .set_override ("site_name" , "TEST-Site" )
102128 CONF .set_override ("service_name" , "TEST-Service" )
103129
130+ # Mock the base class __init__ to do nothing
131+ mock_base_init .return_value = None
132+
133+ # Mock Nova client and servers
134+ mock_server = mock .Mock ()
135+ mock_server .id = "vm-uuid-1"
136+ mock_server .name = "test-vm-1"
137+
138+ mock_nova = mock .Mock ()
139+ mock_nova .servers .list .return_value = [mock_server ]
140+ mock_get_nova .return_value = mock_nova
141+
142+ # Create extractor and manually set required attributes
143+ extractor = PrometheusExtractor ("test-project" , "test-vo" )
144+ extractor .project = "test-project"
145+ extractor .vo = "test-vo"
146+ extractor .project_id = "test-project-id"
147+
104148 # Mock Prometheus error response
105149 mock_response = mock .Mock ()
106150 mock_response .json .return_value = {
@@ -110,36 +154,52 @@ def test_extract_with_failed_query(self, mock_get):
110154 mock_response .raise_for_status = mock .Mock ()
111155 mock_get .return_value = mock_response
112156
113- # Create extractor
114- extractor = PrometheusExtractor ("test-project" , "test-vo" )
115-
116157 # Extract records
117158 extract_from = datetime .datetime (2023 , 5 , 25 , 0 , 0 , 0 )
118159 extract_to = datetime .datetime (2023 , 5 , 25 , 23 , 59 , 59 )
119160 records = extractor .extract (extract_from , extract_to )
120161
121- # Verify
162+ # Verify - query failed, no records
122163 assert len (records ) == 0
123164
165+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor._get_nova_client" )
166+ @mock .patch ("caso.extract.openstack.base.BaseOpenStackExtractor.__init__" )
124167 @mock .patch ("caso.extract.prometheus.requests.get" )
125168 @mock .patch ("caso.extract.prometheus.LOG" )
126- def test_extract_with_request_exception (self , mock_log , mock_get ):
169+ def test_extract_with_request_exception (
170+ self , mock_log , mock_get , mock_base_init , mock_get_nova
171+ ):
127172 """Test extraction when request to Prometheus fails."""
128173 # Configure CONF
129174 CONF .set_override ("site_name" , "TEST-Site" )
130175 CONF .set_override ("service_name" , "TEST-Service" )
131176
132- # Mock request exception
133- mock_get .side_effect = Exception ("Connection error" )
177+ # Mock the base class __init__ to do nothing
178+ mock_base_init .return_value = None
179+
180+ # Mock Nova client and servers
181+ mock_server = mock .Mock ()
182+ mock_server .id = "vm-uuid-1"
183+ mock_server .name = "test-vm-1"
184+
185+ mock_nova = mock .Mock ()
186+ mock_nova .servers .list .return_value = [mock_server ]
187+ mock_get_nova .return_value = mock_nova
134188
135- # Create extractor
189+ # Create extractor and manually set required attributes
136190 extractor = PrometheusExtractor ("test-project" , "test-vo" )
191+ extractor .project = "test-project"
192+ extractor .vo = "test-vo"
193+ extractor .project_id = "test-project-id"
194+
195+ # Mock request exception
196+ mock_get .side_effect = Exception ("Connection error" )
137197
138198 # Extract records
139199 extract_from = datetime .datetime (2023 , 5 , 25 , 0 , 0 , 0 )
140200 extract_to = datetime .datetime (2023 , 5 , 25 , 23 , 59 , 59 )
141201 records = extractor .extract (extract_from , extract_to )
142202
143- # Verify
203+ # Verify - exception caught, no records
144204 assert len (records ) == 0
145205 mock_log .error .assert_called ()
0 commit comments