@@ -25,10 +25,7 @@ def test_channel_list(self):
2525 response .status_code = 200
2626 mock_request .return_value = response
2727
28- url = (
29- "https://go.urbanairship.com/api/channels/"
30- "0492662a-1b52-4343-a1f9-c6b0c72931c0"
31- )
28+ url = "https://go.urbanairship.com/api/channels/0492662a-1b52-4343-a1f9-c6b0c72931c0"
3229
3330 airship = ua .Airship (TEST_KEY , TEST_SECRET )
3431 channel_list = ua .ChannelList (airship , url )
@@ -73,9 +70,7 @@ def test_channel_lookup(self):
7370 channel_id = "0492662a-1b52-4343-a1f9-c6b0c72931c0"
7471 channel_lookup = ua .ChannelInfo (airship ).lookup (channel_id )
7572
76- date_created = datetime .datetime .strptime (
77- "2014-04-17T23:35:15" , "%Y-%m-%dT%H:%M:%S"
78- )
73+ date_created = datetime .datetime .strptime ("2014-04-17T23:35:15" , "%Y-%m-%dT%H:%M:%S" )
7974
8075 self .assertEqual (channel_lookup .channel_id , channel_id )
8176 self .assertEqual (channel_lookup .device_type , "ios" )
@@ -85,9 +80,7 @@ def test_channel_lookup(self):
8580 self .assertEqual (channel_lookup .alias , "null" )
8681 self .assertEqual (channel_lookup .tags , ["test_tag" ])
8782 self .assertEqual (channel_lookup .created , date_created )
88- self .assertEqual (
89- channel_lookup .push_address , "3C0590EBCC11618723B3D4C8AA60BCFB6"
90- )
83+ self .assertEqual (channel_lookup .push_address , "3C0590EBCC11618723B3D4C8AA60BCFB6" )
9184 self .assertEqual (channel_lookup .last_registration , "UNKNOWN" )
9285 self .assertEqual (
9386 channel_lookup .ios ,
@@ -97,3 +90,285 @@ def test_channel_lookup(self):
9790 "tz" : "null" ,
9891 },
9992 )
93+
94+ def test_channel_info_datetime_parsing_with_none_values (self ):
95+ """Test that ChannelInfo handles None values for datetime fields correctly."""
96+ with mock .patch .object (ua .Airship , "_request" ) as mock_request :
97+ response = requests .Response ()
98+ response ._content = json .dumps (
99+ {
100+ "channel" : {
101+ "channel_id" : "test-channel-id" ,
102+ "device_type" : "ios" ,
103+ "created" : "2023-01-01T12:00:00" ,
104+ "last_registration" : None , # This should not cause a ValueError
105+ "commercial_opted_in" : None ,
106+ "commercial_opted_out" : None ,
107+ "transactional_opted_in" : None ,
108+ "transactional_opted_out" : None ,
109+ }
110+ }
111+ ).encode ("utf-8" )
112+ response .status_code = 200
113+ mock_request .return_value = response
114+
115+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
116+ channel_info = ua .ChannelInfo (airship ).lookup ("test-channel-id" )
117+
118+ # Valid datetime should be parsed
119+ expected_created = datetime .datetime .strptime (
120+ "2023-01-01T12:00:00" , "%Y-%m-%dT%H:%M:%S"
121+ )
122+ self .assertEqual (channel_info .created , expected_created )
123+
124+ # None values should remain None (not converted to "UNKNOWN")
125+ self .assertIsNone (channel_info .last_registration )
126+ self .assertIsNone (channel_info .commercial_opted_in )
127+ self .assertIsNone (channel_info .commercial_opted_out )
128+ self .assertIsNone (channel_info .transactional_opted_in )
129+ self .assertIsNone (channel_info .transactional_opted_out )
130+
131+ def test_channel_info_datetime_parsing_with_empty_strings (self ):
132+ """Test that ChannelInfo handles empty strings for datetime fields correctly."""
133+ with mock .patch .object (ua .Airship , "_request" ) as mock_request :
134+ response = requests .Response ()
135+ response ._content = json .dumps (
136+ {
137+ "channel" : {
138+ "channel_id" : "test-channel-id" ,
139+ "device_type" : "ios" ,
140+ "created" : "2023-01-01T12:00:00" ,
141+ "last_registration" : "" , # Empty string should not cause ValueError
142+ "commercial_opted_in" : "" ,
143+ }
144+ }
145+ ).encode ("utf-8" )
146+ response .status_code = 200
147+ mock_request .return_value = response
148+
149+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
150+ channel_info = ua .ChannelInfo (airship ).lookup ("test-channel-id" )
151+
152+ # Valid datetime should be parsed
153+ expected_created = datetime .datetime .strptime (
154+ "2023-01-01T12:00:00" , "%Y-%m-%dT%H:%M:%S"
155+ )
156+ self .assertEqual (channel_info .created , expected_created )
157+
158+ # Empty strings should remain empty strings
159+ self .assertEqual (channel_info .last_registration , "" )
160+ self .assertEqual (channel_info .commercial_opted_in , "" )
161+
162+ def test_channel_info_datetime_parsing_with_invalid_strings (self ):
163+ """Test that ChannelInfo handles invalid datetime strings correctly."""
164+ with mock .patch .object (ua .Airship , "_request" ) as mock_request :
165+ response = requests .Response ()
166+ response ._content = json .dumps (
167+ {
168+ "channel" : {
169+ "channel_id" : "test-channel-id" ,
170+ "device_type" : "ios" ,
171+ "created" : "2023-01-01T12:00:00" ,
172+ "last_registration" : "invalid-datetime" , # Should become "UNKNOWN"
173+ "commercial_opted_in" : "not-a-date" ,
174+ }
175+ }
176+ ).encode ("utf-8" )
177+ response .status_code = 200
178+ mock_request .return_value = response
179+
180+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
181+ channel_info = ua .ChannelInfo (airship ).lookup ("test-channel-id" )
182+
183+ # Valid datetime should be parsed
184+ expected_created = datetime .datetime .strptime (
185+ "2023-01-01T12:00:00" , "%Y-%m-%dT%H:%M:%S"
186+ )
187+ self .assertEqual (channel_info .created , expected_created )
188+
189+ # Invalid datetime strings should become "UNKNOWN"
190+ self .assertEqual (channel_info .last_registration , "UNKNOWN" )
191+ self .assertEqual (channel_info .commercial_opted_in , "UNKNOWN" )
192+
193+ def test_device_info_datetime_parsing_with_none_values (self ):
194+ """Test that DeviceInfo handles None values for datetime fields correctly."""
195+ # Test DeviceInfo.from_payload directly
196+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
197+
198+ # Test with None value for created field
199+ payload = {
200+ "device_token" : "test-device-token" ,
201+ "created" : None , # This should not cause a ValueError
202+ "active" : True ,
203+ "tags" : ["test_tag" ],
204+ }
205+
206+ device_info = ua .DeviceInfo .from_payload (payload , "device_token" , airship )
207+
208+ # None value should remain None
209+ self .assertIsNone (device_info .created )
210+ self .assertEqual (device_info .id , "test-device-token" )
211+ self .assertEqual (device_info .device_type , "device_token" )
212+ self .assertTrue (device_info .active )
213+ self .assertEqual (device_info .tags , ["test_tag" ])
214+
215+ def test_device_info_datetime_parsing_with_valid_datetime (self ):
216+ """Test that DeviceInfo correctly parses valid datetime strings."""
217+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
218+
219+ payload = {
220+ "device_token" : "test-device-token" ,
221+ "created" : "2023-01-01 12:00:00" , # Space-separated format for DeviceInfo
222+ "active" : True ,
223+ "tags" : ["test_tag" ],
224+ }
225+
226+ device_info = ua .DeviceInfo .from_payload (payload , "device_token" , airship )
227+
228+ # Valid datetime should be parsed
229+ expected_created = datetime .datetime .strptime ("2023-01-01 12:00:00" , "%Y-%m-%d %H:%M:%S" )
230+ self .assertEqual (device_info .created , expected_created )
231+
232+ def test_device_info_datetime_parsing_with_invalid_strings (self ):
233+ """Test that DeviceInfo handles invalid datetime strings correctly."""
234+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
235+
236+ payload = {
237+ "device_token" : "test-device-token" ,
238+ "created" : "invalid-datetime" , # Should become "UNKNOWN"
239+ "active" : True ,
240+ "tags" : ["test_tag" ],
241+ }
242+
243+ device_info = ua .DeviceInfo .from_payload (payload , "device_token" , airship )
244+
245+ # Invalid datetime string should become "UNKNOWN"
246+ self .assertEqual (device_info .created , "UNKNOWN" )
247+
248+ def test_channel_info_opt_in_date_opt_out_date_with_none_values (self ):
249+ """Test that ChannelInfo handles None values for opt_in_date and opt_out_date correctly."""
250+ with mock .patch .object (ua .Airship , "_request" ) as mock_request :
251+ response = requests .Response ()
252+ response ._content = json .dumps (
253+ {
254+ "channel" : {
255+ "channel_id" : "test-channel-id" ,
256+ "device_type" : "ios" ,
257+ "created" : "2023-01-01T12:00:00" ,
258+ "opt_in_date" : None , # This should not cause a ValueError
259+ "opt_out_date" : None , # This should not cause a ValueError
260+ }
261+ }
262+ ).encode ("utf-8" )
263+ response .status_code = 200
264+ mock_request .return_value = response
265+
266+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
267+ channel_info = ua .ChannelInfo (airship ).lookup ("test-channel-id" )
268+
269+ # Valid datetime should be parsed
270+ expected_created = datetime .datetime .strptime (
271+ "2023-01-01T12:00:00" , "%Y-%m-%dT%H:%M:%S"
272+ )
273+ self .assertEqual (channel_info .created , expected_created )
274+
275+ # None values should remain None (not converted to "UNKNOWN")
276+ self .assertIsNone (channel_info .opt_in_date )
277+ self .assertIsNone (channel_info .opt_out_date )
278+
279+ def test_channel_info_opt_in_date_opt_out_date_with_valid_datetime (self ):
280+ """Test that ChannelInfo correctly parses valid opt_in_date and opt_out_date datetime strings."""
281+ with mock .patch .object (ua .Airship , "_request" ) as mock_request :
282+ response = requests .Response ()
283+ response ._content = json .dumps (
284+ {
285+ "channel" : {
286+ "channel_id" : "test-channel-id" ,
287+ "device_type" : "ios" ,
288+ "created" : "2023-01-01T12:00:00" ,
289+ "opt_in_date" : "2023-01-15T10:30:00" ,
290+ "opt_out_date" : "2023-02-20T14:45:00" ,
291+ }
292+ }
293+ ).encode ("utf-8" )
294+ response .status_code = 200
295+ mock_request .return_value = response
296+
297+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
298+ channel_info = ua .ChannelInfo (airship ).lookup ("test-channel-id" )
299+
300+ # Valid datetime should be parsed
301+ expected_created = datetime .datetime .strptime (
302+ "2023-01-01T12:00:00" , "%Y-%m-%dT%H:%M:%S"
303+ )
304+ expected_opt_in_date = datetime .datetime .strptime (
305+ "2023-01-15T10:30:00" , "%Y-%m-%dT%H:%M:%S"
306+ )
307+ expected_opt_out_date = datetime .datetime .strptime (
308+ "2023-02-20T14:45:00" , "%Y-%m-%dT%H:%M:%S"
309+ )
310+ self .assertEqual (channel_info .created , expected_created )
311+ self .assertEqual (channel_info .opt_in_date , expected_opt_in_date )
312+ self .assertEqual (channel_info .opt_out_date , expected_opt_out_date )
313+
314+ def test_channel_info_opt_in_date_opt_out_date_with_empty_strings (self ):
315+ """Test that ChannelInfo handles empty strings for opt_in_date and opt_out_date correctly."""
316+ with mock .patch .object (ua .Airship , "_request" ) as mock_request :
317+ response = requests .Response ()
318+ response ._content = json .dumps (
319+ {
320+ "channel" : {
321+ "channel_id" : "test-channel-id" ,
322+ "device_type" : "ios" ,
323+ "created" : "2023-01-01T12:00:00" ,
324+ "opt_in_date" : "" , # Empty string should not cause ValueError
325+ "opt_out_date" : "" , # Empty string should not cause ValueError
326+ }
327+ }
328+ ).encode ("utf-8" )
329+ response .status_code = 200
330+ mock_request .return_value = response
331+
332+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
333+ channel_info = ua .ChannelInfo (airship ).lookup ("test-channel-id" )
334+
335+ # Valid datetime should be parsed
336+ expected_created = datetime .datetime .strptime (
337+ "2023-01-01T12:00:00" , "%Y-%m-%dT%H:%M:%S"
338+ )
339+ self .assertEqual (channel_info .created , expected_created )
340+
341+ # Empty strings should remain empty strings
342+ self .assertEqual (channel_info .opt_in_date , "" )
343+ self .assertEqual (channel_info .opt_out_date , "" )
344+
345+ def test_channel_info_opt_in_date_opt_out_date_with_invalid_strings (self ):
346+ """Test that ChannelInfo handles invalid opt_in_date and opt_out_date datetime strings correctly."""
347+ with mock .patch .object (ua .Airship , "_request" ) as mock_request :
348+ response = requests .Response ()
349+ response ._content = json .dumps (
350+ {
351+ "channel" : {
352+ "channel_id" : "test-channel-id" ,
353+ "device_type" : "ios" ,
354+ "created" : "2023-01-01T12:00:00" ,
355+ "opt_in_date" : "invalid-datetime" , # Should become "UNKNOWN"
356+ "opt_out_date" : "not-a-date" , # Should become "UNKNOWN"
357+ }
358+ }
359+ ).encode ("utf-8" )
360+ response .status_code = 200
361+ mock_request .return_value = response
362+
363+ airship = ua .Airship (TEST_KEY , TEST_SECRET )
364+ channel_info = ua .ChannelInfo (airship ).lookup ("test-channel-id" )
365+
366+ # Valid datetime should be parsed
367+ expected_created = datetime .datetime .strptime (
368+ "2023-01-01T12:00:00" , "%Y-%m-%dT%H:%M:%S"
369+ )
370+ self .assertEqual (channel_info .created , expected_created )
371+
372+ # Invalid datetime strings should become "UNKNOWN"
373+ self .assertEqual (channel_info .opt_in_date , "UNKNOWN" )
374+ self .assertEqual (channel_info .opt_out_date , "UNKNOWN" )
0 commit comments