1+ import unittest
2+ from unittest .mock import patch , MagicMock
3+
4+ from rss2email .feed import Feed
5+ from rss2email .config import Config , CONFIG
6+
7+
8+ class TestFeedURLRedirect (unittest .TestCase ):
9+
10+ def setUp (self ):
11+ """Set up a feed object for testing."""
12+ # Use a mock config to avoid touching the user's real configuration
13+ mock_config = Config ()
14+ mock_config .read_dict ({'DEFAULT' : CONFIG ['DEFAULT' ]})
15+ # Prevent the config from trying to load or save real files
16+ mock_config .load_from_file = MagicMock ()
17+ mock_config .save_to_file = MagicMock ()
18+
19+ self .feed = Feed (name = 'TestFeed' , url = 'http://old-url.com/feed' ,
20+ config = mock_config )
21+ self .
feed .
to = '[email protected] ' 22+ # Mock the save method on the feed object to isolate the test
23+ self .feed .save_to_config = MagicMock ()
24+
25+ @patch ('rss2email.feed._feedparser.parse' )
26+ def test_redirect_updates_url_and_saves_config (self , mock_parse ):
27+ # Simulate a 301 redirect response from feedparser
28+ data = {
29+ 'status' : 301 ,
30+ 'url' : 'http://new-url.com/feed' ,
31+ 'entries' : [],
32+ 'bozo' : 0 ,
33+ 'headers' : {},
34+ 'etag' : None ,
35+ 'modified' : None ,
36+ 'bozo_exception' : None ,
37+ }
38+ mock_parsed = MagicMock ()
39+ mock_parsed .status = data ['status' ]
40+ mock_parsed .entries = data ['entries' ]
41+ mock_parsed .bozo = data ['bozo' ]
42+
43+ def getitem_side_effect (key ):
44+ return data [key ]
45+ mock_parsed .__getitem__ .side_effect = getitem_side_effect
46+
47+ def get_side_effect (key , default = None ):
48+ return data .get (key , default )
49+ mock_parsed .get .side_effect = get_side_effect
50+ mock_parse .return_value = mock_parsed
51+
52+ # Run the feed with save_config=True, disable sending emails
53+ self .feed .run (send = False , save_config = True )
54+
55+ # Check that the URL was updated in the feed object
56+ self .assertEqual (self .feed .url , 'http://new-url.com/feed' )
57+ # Check that the change was persisted to config
58+ self .feed .save_to_config .assert_called_once ()
59+
60+ @patch ('rss2email.feed._feedparser.parse' )
61+ def test_redirect_updates_url_without_saving_config (self , mock_parse ):
62+ """Test a 301 redirect updates the URL in memory but does not save."""
63+ # Simulate a 301 redirect response from feedparser
64+ data = {
65+ 'status' : 301 ,
66+ 'url' : 'http://new-url.com/feed' ,
67+ 'entries' : [],
68+ 'bozo' : 0 ,
69+ 'headers' : {},
70+ 'etag' : None ,
71+ 'modified' : None ,
72+ 'bozo_exception' : None ,
73+ }
74+ mock_parsed = MagicMock ()
75+ mock_parsed .status = data ['status' ]
76+ mock_parsed .entries = data ['entries' ]
77+ mock_parsed .bozo = data ['bozo' ]
78+
79+ def getitem_side_effect (key ):
80+ return data [key ]
81+ mock_parsed .__getitem__ .side_effect = getitem_side_effect
82+
83+ def get_side_effect (key , default = None ):
84+ return data .get (key , default )
85+ mock_parsed .get .side_effect = get_side_effect
86+ mock_parse .return_value = mock_parsed
87+
88+ # Run the feed with save_config=False
89+ self .feed .run (send = False , save_config = False )
90+
91+ # Check that the URL was updated in the feed object for this session
92+ self .assertEqual (self .feed .url , 'http://new-url.com/feed' )
93+ # Check that the change was NOT persisted to config
94+ self .feed .save_to_config .assert_not_called ()
95+
96+ @patch ('rss2email.feed._feedparser.parse' )
97+ def test_no_redirect_does_not_update_url (self , mock_parse ):
98+ """Test that a normal (200 OK) response does not change the URL."""
99+ # Simulate a normal 200 OK response
100+ mock_parsed = MagicMock ()
101+ mock_parsed .status = 200
102+ mock_parsed .url = 'http://old-url.com/feed'
103+ mock_parsed .entries = []
104+ mock_parsed .bozo = 0
105+ mock_parsed .headers = {}
106+ mock_parsed .etag = None
107+ mock_parsed .modified = None
108+ mock_parse .return_value = mock_parsed
109+
110+ # Run the feed, save_config can be true or false
111+ self .feed .run (send = False , save_config = True )
112+
113+ # Check that the URL was NOT updated
114+ self .assertEqual (self .feed .url , 'http://old-url.com/feed' )
115+ # Check that save_to_config was NOT called for a non-redirect
116+ self .feed .save_to_config .assert_not_called ()
117+
118+
119+ if __name__ == '__main__' :
120+ unittest .main ()
0 commit comments