55import unittest .mock as mock
66import io
77import json
8+ import importlib
89import requests
910import redis
1011from minio .error import S3Error , InvalidResponseError
@@ -82,6 +83,7 @@ class MockOpenSenseResponse:
8283 def __init__ (self , temp_value ):
8384 self .text = "mock response text"
8485 self .temp_value = temp_value
86+ self .status_code = 200 # Add this attribute
8587 payload = json .dumps ([{
8688 'sensors' : [
8789 {
@@ -174,7 +176,7 @@ def test_cache_hit(self):
174176 mock_redis_client .get .return_value = "cached_result"
175177
176178 with mock .patch ('app.opensense.REDIS_AVAILABLE' , True ), \
177- mock .patch ('app.opensense.redis_client ' , mock_redis_client ), \
179+ mock .patch ('app.opensense.REDIS_CLIENT ' , mock_redis_client ), \
178180 mock .patch ('app.opensense.requests.get' ) as mock_requests :
179181
180182 result , _ = opensense .get_temperature ()
@@ -188,7 +190,7 @@ def test_cache_miss_and_store(self):
188190 mock_redis_client .get .return_value = None
189191
190192 with mock .patch ('app.opensense.REDIS_AVAILABLE' , True ), \
191- mock .patch ('app.opensense.redis_client ' , mock_redis_client ), \
193+ mock .patch ('app.opensense.REDIS_CLIENT ' , mock_redis_client ), \
192194 mock .patch ('app.opensense.requests.get' ,
193195 return_value = MockOpenSenseResponse (25 )):
194196
@@ -205,7 +207,7 @@ def test_cache_hit_bytes_decoded(self):
205207 mock_redis_client = mock .MagicMock ()
206208 mock_redis_client .get .return_value = b"cached_result"
207209 with mock .patch ('app.opensense.REDIS_AVAILABLE' , True ), \
208- mock .patch ('app.opensense.redis_client ' , mock_redis_client ), \
210+ mock .patch ('app.opensense.REDIS_CLIENT ' , mock_redis_client ), \
209211 mock .patch ('app.opensense.requests.get' ) as req_get :
210212 result , stats = opensense .get_temperature ()
211213 self .assertEqual (result , "cached_result" )
@@ -404,7 +406,7 @@ def test_check_caching_key_not_exists(self):
404406 mock_redis_client .ttl .return_value = - 2 # Key doesn't exist
405407
406408 with mock .patch ('app.readiness.REDIS_AVAILABLE' , True ), \
407- mock .patch ('app.readiness.redis_client ' , mock_redis_client ):
409+ mock .patch ('app.readiness.REDIS_CLIENT ' , mock_redis_client ):
408410 result = readiness .check_caching ()
409411 self .assertTrue (result )
410412
@@ -414,7 +416,7 @@ def test_check_caching_key_no_expiry(self):
414416 mock_redis_client .ttl .return_value = - 1 # Key exists but no expiry
415417
416418 with mock .patch ('app.readiness.REDIS_AVAILABLE' , True ), \
417- mock .patch ('app.readiness.redis_client ' , mock_redis_client ):
419+ mock .patch ('app.readiness.REDIS_CLIENT ' , mock_redis_client ):
418420 result = readiness .check_caching ()
419421 self .assertTrue (result )
420422
@@ -424,7 +426,7 @@ def test_check_caching_fresh_cache(self):
424426 mock_redis_client .ttl .return_value = 150 # 2.5 minutes remaining
425427
426428 with mock .patch ('app.readiness.REDIS_AVAILABLE' , True ), \
427- mock .patch ('app.readiness.redis_client ' , mock_redis_client ):
429+ mock .patch ('app.readiness.REDIS_CLIENT ' , mock_redis_client ):
428430 result = readiness .check_caching ()
429431 self .assertFalse (result ) # Cache is fresh
430432
@@ -434,7 +436,7 @@ def test_check_caching_redis_error(self):
434436 mock_redis_client .ttl .side_effect = redis .RedisError ("boom" )
435437
436438 with mock .patch ('app.readiness.REDIS_AVAILABLE' , True ), \
437- mock .patch ('app.readiness.redis_client ' , mock_redis_client ), \
439+ mock .patch ('app.readiness.REDIS_CLIENT ' , mock_redis_client ), \
438440 mock .patch ('builtins.print' ):
439441 result = readiness .check_caching ()
440442 self .assertTrue (result )
@@ -529,5 +531,45 @@ def test_readiness_check_partial_failure(self):
529531 self .assertEqual (result , 200 )
530532
531533
534+ class TestOpenSenseExceptionBranches (unittest .TestCase ):
535+ """Covers exception branches in opensense module."""
536+
537+ def test_set_cached_temperature_redis_error_is_swallowed (self ):
538+ """_set_cached_temperature should swallow RedisError (pass)."""
539+ with mock .patch ('app.opensense.REDIS_AVAILABLE' , True ), \
540+ mock .patch ('app.opensense.REDIS_CLIENT' ) as mock_client :
541+ mock_client .setex .side_effect = redis .RedisError ("boom" )
542+ # Should not raise
543+ opensense ._set_cached_temperature ("value" )
544+ mock_client .setex .assert_called_once ()
545+
546+ def test_get_cached_temperature_redis_error_returns_none (self ):
547+ """_get_cached_temperature should return None on RedisError."""
548+ with mock .patch ('app.opensense.REDIS_AVAILABLE' , True ), \
549+ mock .patch ('app.opensense.REDIS_CLIENT' ) as mock_client :
550+ mock_client .get .side_effect = redis .RedisError ("boom" )
551+ result = opensense ._get_cached_temperature ()
552+ self .assertIsNone (result )
553+ mock_client .get .assert_called_once_with ("temperature_data" )
554+
555+ def test_module_level_redis_init_errors_are_caught_all_types (self ):
556+ """create_redis_client exceptions at import-time are handled (all types)."""
557+ for exc in (
558+ redis .ConnectionError ("c" ),
559+ redis .TimeoutError ("t" ),
560+ OSError ("o" ),
561+ ImportError ("i" )):
562+ with self .subTest (exc = type (exc ).__name__ ), \
563+ mock .patch ('app.config.create_redis_client' , side_effect = exc ), \
564+ mock .patch ('builtins.print' ):
565+ reloaded = importlib .reload (opensense )
566+ self .assertIsNone (reloaded .REDIS_CLIENT )
567+ self .assertFalse (reloaded .REDIS_AVAILABLE )
568+ # Restore module for other tests
569+ with mock .patch ('app.config.create_redis_client' , return_value = (None , False )), \
570+ mock .patch ('builtins.print' ):
571+ importlib .reload (opensense )
572+
573+
532574if __name__ == '__main__' :
533575 unittest .main ()
0 commit comments