1#!/usr/bin/env python3 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from mock import Mock 18from mock import patch 19import unittest 20from unittest import TestCase 21from acts.metrics.logger import LoggerProxy 22from acts.metrics.logger import MetricLogger 23 24COMPILE_IMPORT_PROTO = 'acts.metrics.logger.compile_import_proto' 25CREATE_FROM_INSTANCE = ( 26 'acts.metrics.logger.subscription_bundle.create_from_instance') 27LOGGING_ERROR = 'logging.error' 28LOGGING_DEBUG = 'logging.debug' 29GET_CONTEXT_FOR_EVENT = 'acts.metrics.logger.get_context_for_event' 30GET_FILE = 'acts.metrics.logger.inspect.getfile' 31MKDTEMP = 'acts.metrics.logger.tempfile.mkdtemp' 32PROTO_METRIC_PUBLISHER = 'acts.metrics.logger.ProtoMetricPublisher' 33TEST_CASE_LOGGER_PROXY = 'acts.metrics.logger.TestCaseLoggerProxy' 34TEST_CLASS_LOGGER_PROXY = 'acts.metrics.logger.TestClassLoggerProxy' 35 36 37class MetricLoggerTest(TestCase): 38 """Unit tests for the MetricLogger class.""" 39 40 @patch(TEST_CASE_LOGGER_PROXY) 41 def test_for_test_case_returns_test_case_proxy(self, proxy_cls): 42 args = (Mock(), ) 43 kwargs = {'mock' : Mock()} 44 logger = MetricLogger.for_test_case(*args, **kwargs) 45 46 proxy_cls.assert_called_once_with(MetricLogger, args, kwargs) 47 48 @patch(TEST_CLASS_LOGGER_PROXY) 49 def test_for_test_class_returns_test_class_proxy(self, proxy_cls): 50 args = (Mock(),) 51 kwargs = {'mock': Mock()} 52 logger = MetricLogger.for_test_class(*args, **kwargs) 53 54 proxy_cls.assert_called_once_with(MetricLogger, args, kwargs) 55 56 @patch(TEST_CASE_LOGGER_PROXY) 57 def test_for_test_case_works_on_subclases(self, proxy_cls): 58 class TestLogger(MetricLogger): 59 pass 60 args = (Mock(),) 61 kwargs = {'mock': Mock()} 62 logger = TestLogger.for_test_case(*args, **kwargs) 63 64 proxy_cls.assert_called_once_with(TestLogger, args, kwargs) 65 66 @patch(TEST_CLASS_LOGGER_PROXY) 67 def test_for_test_class_works_on_subclases(self, proxy_cls): 68 class TestLogger(MetricLogger): 69 pass 70 args = (Mock(),) 71 kwargs = {'mock': Mock()} 72 logger = TestLogger.for_test_class(*args, **kwargs) 73 74 proxy_cls.assert_called_once_with(TestLogger, args, kwargs) 75 76 @patch(COMPILE_IMPORT_PROTO) 77 @patch(GET_FILE) 78 def test_compile_proto_relative_path(self, getfile, compile_import_proto): 79 getfile.return_value = '/path/to/class/file.py' 80 proto_path = 'dir/my_proto.proto' 81 compiler_out = Mock() 82 MetricLogger._compile_proto(proto_path, compiler_out=compiler_out) 83 84 full_proto_path = '/path/to/class/dir/my_proto.proto' 85 compile_import_proto.assert_called_once_with( 86 compiler_out, full_proto_path) 87 88 @patch(COMPILE_IMPORT_PROTO) 89 @patch(GET_FILE) 90 def test_compile_proto_absolute_path(self, getfile, compile_import_proto): 91 proto_path = '/abs/path/to/my_proto.proto' 92 compiler_out = Mock() 93 MetricLogger._compile_proto(proto_path, compiler_out=compiler_out) 94 95 compile_import_proto.assert_called_once_with(compiler_out, proto_path) 96 getfile.assert_not_called() 97 98 @patch(COMPILE_IMPORT_PROTO) 99 @patch(GET_FILE) 100 @patch(MKDTEMP) 101 def test_compile_proto_default_compiler_out(self, 102 mkdtemp, 103 getfile, 104 compile_import_proto): 105 compiler_out = Mock() 106 mkdtemp.return_value = compiler_out 107 proto_path = '/abs/path/to/my_proto.proto' 108 MetricLogger._compile_proto(proto_path) 109 110 compile_import_proto.assert_called_once_with(compiler_out, proto_path) 111 112 113 def test_init_empty(self): 114 logger = MetricLogger() 115 116 self.assertIsNone(logger.context) 117 self.assertIsNone(logger.publisher) 118 119 def test_init_with_context_and_publisher(self): 120 context = Mock() 121 publisher = Mock() 122 123 logger = MetricLogger(context=context, publisher=publisher) 124 125 self.assertEqual(logger.context, context) 126 self.assertEqual(logger.publisher, publisher) 127 128 @patch(PROTO_METRIC_PUBLISHER) 129 @patch(GET_CONTEXT_FOR_EVENT) 130 def test_init_with_event(self, get_context, publisher_cls): 131 context = Mock() 132 publisher = Mock() 133 get_context.return_value = context 134 publisher_cls.return_value = publisher 135 event = Mock() 136 137 logger = MetricLogger(event=event) 138 139 get_context.assert_called_once_with(event) 140 publisher_cls.assert_called_once_with(context) 141 self.assertEqual(logger.context, context) 142 self.assertEqual(logger.publisher, publisher) 143 144 def test_start_has_default_impl(self): 145 logger = MetricLogger() 146 logger.start(Mock()) 147 148 def test_end_has_default_impl(self): 149 logger = MetricLogger() 150 logger.end(Mock()) 151 152 def test_compile_proto(self): 153 logger = MetricLogger() 154 155 156class LoggerProxyTest(TestCase): 157 158 @patch(CREATE_FROM_INSTANCE) 159 def test_init(self, create_from_instance): 160 logger_cls = Mock() 161 logger_args = Mock() 162 logger_kwargs = Mock() 163 bundle = Mock() 164 create_from_instance.return_value = bundle 165 proxy = LoggerProxy(logger_cls, 166 logger_args, 167 logger_kwargs) 168 169 self.assertEqual(proxy._logger_cls, logger_cls) 170 self.assertEqual(proxy._logger_args, logger_args) 171 self.assertEqual(proxy._logger_kwargs, logger_kwargs) 172 self.assertIsNone(proxy._logger) 173 create_from_instance.assert_called_once_with(proxy) 174 bundle.register.assert_called_once_with() 175 176 @patch(CREATE_FROM_INSTANCE) 177 def test_setup_proxy(self, create_from_instance): 178 logger_cls = Mock() 179 logger_args = (Mock(), ) 180 logger_kwargs = {'mock': Mock()} 181 bundle = Mock() 182 event = Mock() 183 create_from_instance.return_value = bundle 184 logger = Mock() 185 logger_cls.return_value = logger 186 187 proxy = LoggerProxy(logger_cls, 188 logger_args, 189 logger_kwargs) 190 proxy._setup_proxy(event) 191 192 logger_cls.assert_called_once_with(event=event, 193 *logger_args, 194 **logger_kwargs) 195 logger.start.assert_called_once_with(event) 196 197 @patch(CREATE_FROM_INSTANCE) 198 def test_teardown_proxy(self, create_from_instance): 199 logger_cls = Mock() 200 logger_args = (Mock(),) 201 logger_kwargs = {'mock': Mock()} 202 bundle = Mock() 203 event = Mock() 204 create_from_instance.return_value = bundle 205 logger = Mock() 206 logger_cls.return_value = logger 207 208 proxy = LoggerProxy(logger_cls, 209 logger_args, 210 logger_kwargs) 211 proxy._setup_proxy(event) 212 proxy._teardown_proxy(event) 213 214 logger.end.assert_called_once_with(event) 215 self.assertIsNone(proxy._logger) 216 217 @patch(LOGGING_DEBUG) 218 @patch(LOGGING_ERROR) 219 @patch(CREATE_FROM_INSTANCE) 220 def test_teardown_proxy_logs_upon_exception(self, create_from_instance, 221 logging_error, logging_debug): 222 logger_cls = Mock() 223 logger_args = (Mock(),) 224 logger_kwargs = {'mock': Mock()} 225 bundle = Mock() 226 event = Mock() 227 create_from_instance.return_value = bundle 228 logger = Mock() 229 logger.end.side_effect = ValueError('test') 230 logger_cls.return_value = logger 231 232 proxy = LoggerProxy(logger_cls, 233 logger_args, 234 logger_kwargs) 235 proxy._setup_proxy(event) 236 proxy._teardown_proxy(event) 237 238 self.assertTrue(logging_error.called) 239 self.assertTrue(logging_debug.called) 240 self.assertIsNone(proxy._logger) 241 242 @patch(CREATE_FROM_INSTANCE) 243 def test_getattr_forwards_to_logger(self, create_from_instance): 244 logger_cls = Mock() 245 logger_args = (Mock(),) 246 logger_kwargs = {'mock': Mock()} 247 bundle = Mock() 248 event = Mock() 249 create_from_instance.return_value = bundle 250 logger = Mock() 251 logger_cls.return_value = logger 252 253 proxy = LoggerProxy(logger_cls, 254 logger_args, 255 logger_kwargs) 256 proxy._setup_proxy(event) 257 258 self.assertEqual(proxy.some_attr, logger.some_attr) 259 260 @patch(CREATE_FROM_INSTANCE) 261 def test_getattr_with_no_logger_raises(self, create_from_instance): 262 bundle = Mock() 263 create_from_instance.return_value = bundle 264 265 proxy = LoggerProxy(Mock(), Mock(), Mock()) 266 267 self.assertRaises(ValueError, lambda: proxy.some_attr) 268 269 @patch(CREATE_FROM_INSTANCE) 270 def test_setattr_forwards_to_logger(self, create_from_instance): 271 logger_cls = Mock() 272 logger_args = (Mock(),) 273 logger_kwargs = {'mock': Mock()} 274 bundle = Mock() 275 event = Mock() 276 create_from_instance.return_value = bundle 277 logger = Mock() 278 logger_cls.return_value = logger 279 value = Mock() 280 281 proxy = LoggerProxy(logger_cls, 282 logger_args, 283 logger_kwargs) 284 proxy._setup_proxy(event) 285 proxy.some_attr = value 286 287 self.assertEqual(logger.some_attr, value) 288 289 @patch(CREATE_FROM_INSTANCE) 290 def test_setattr_with_no_logger_raises(self, create_from_instance): 291 bundle = Mock() 292 create_from_instance.return_value = bundle 293 value = Mock() 294 295 proxy = LoggerProxy(Mock(), Mock(), Mock()) 296 297 def try_set(): 298 proxy.some_attr = value 299 self.assertRaises(ValueError, try_set) 300 301 302if __name__ == '__main__': 303 unittest.main() 304