diff test/rest_common.py @ 7587:8f29e4ea05ce

fix: issue2551278 - datetime.datetime.utcnow deprecation. Replace calls with equivalent that produces timezone aware dates rather than naive dates. Also some flake8 fixes for test/rest_common.py.
author John Rouillard <rouilj@ieee.org>
date Tue, 25 Jul 2023 16:30:10 -0400
parents 978285986b2c
children be6cb2e0d471
line wrap: on
line diff
--- a/test/rest_common.py	Mon Jul 24 21:24:07 2023 -0400
+++ b/test/rest_common.py	Tue Jul 25 16:30:10 2023 -0400
@@ -1,13 +1,14 @@
 import pytest
 import unittest
-import os
 import shutil
 import errno
 
 from time import sleep
 from datetime import datetime, timedelta
+from roundup.anypy.cgi_ import cgi
+from roundup.anypy.datetime_ import utcnow
 from roundup.test.tx_Source_detector import init as tx_Source_init
-from roundup.anypy.cgi_ import cgi
+
 
 try:
     from datetime import timezone
@@ -16,14 +17,15 @@
     # python 2
     from datetime import tzinfo
     ZERO = timedelta(0)
+
     class UTC(tzinfo):
         """UTC"""
         def utcoffset(self, dt):
             return ZERO
-        
+
         def tzname(self, dt):
             return "UTC"
-        
+
         def dst(self, dt):
             return ZERO
 
@@ -34,13 +36,12 @@
 from roundup.exceptions import *
 from roundup import password, hyperdb
 from roundup.rest import RestfulInstance, calculate_etag
-from roundup.backends import list_backends
 from roundup.cgi import client
 from roundup.anypy.strings import b2s, s2b, us2u
 import random
 
 from roundup.backends.sessions_dbm import OneTimeKeys
-from roundup.anypy.dbm_ import anydbm, whichdb
+from roundup.anypy.dbm_ import whichdb
 
 from .db_test_base import setupTracker
 
@@ -56,10 +57,10 @@
     skip_jwt = lambda func, *args, **kwargs: func
 except ImportError:
     from .pytest_patcher import mark_class
-    jwt=None 
+    jwt = None
     skip_jwt = mark_class(pytest.mark.skip(
         reason='Skipping JWT tests: jwt library not available'))
-    
+
 NEEDS_INSTANCE = 1
 
 
@@ -109,31 +110,32 @@
 
         # add set of roles for testing jwt's.
         self.db.security.addRole(name="User:email",
-                        description="allow email by jwt")
+                                 description="allow email by jwt")
         # allow the jwt to access everybody's email addresses.
         # this makes it easier to differentiate between User and
         # User:email roles by accessing the /rest/data/user
         # endpoint
-        jwt_perms = self.db.security.addPermission(name='View',
-                       klass='user',
-                       properties=('id', 'realname', 'address', 'username'),
-                       description="Allow jwt access to email",
-                       props_only=False)
+        jwt_perms = self.db.security.addPermission(
+            name='View',
+            klass='user',
+            properties=('id', 'realname', 'address', 'username'),
+            description="Allow jwt access to email",
+            props_only=False)
         self.db.security.addPermissionToRole("User:email", jwt_perms)
         self.db.security.addPermissionToRole("User:email", "Rest Access")
 
         # add set of roles for testing jwt's.
         # this is like the user:email role, but it missing access to the rest endpoint.
         self.db.security.addRole(name="User:emailnorest",
-                        description="allow email by jwt")
-        jwt_perms = self.db.security.addPermission(name='View',
-                       klass='user',
-                       properties=('id', 'realname', 'address', 'username'),
-                       description="Allow jwt access to email but forget to allow rest",
-                       props_only=False)
+                                 description="allow email by jwt")
+        jwt_perms = self.db.security.addPermission(
+            name='View',
+            klass='user',
+            properties=('id', 'realname', 'address', 'username'),
+            description="Allow jwt access to email but forget to allow rest",
+            props_only=False)
         self.db.security.addPermissionToRole("User:emailnorest", jwt_perms)
 
-
         if jwt:
             # must be 32 chars in length minimum (I think this is at least
             # 256 bits of data)
@@ -142,7 +144,7 @@
             self.db.config['WEB_JWT_SECRET'] = secret
 
             # generate all timestamps in UTC.
-            base_datetime = datetime(1970,1,1, tzinfo=myutc)
+            base_datetime = datetime(1970, 1, 1, tzinfo=myutc)
 
             # A UTC timestamp for now.
             dt = datetime.now(myutc)
@@ -158,17 +160,16 @@
 
             # claims match what cgi/client.py::determine_user
             # is looking for
-            claim= { 'sub': self.db.getuid(),
+            claim = {'sub': self.db.getuid(),
                      'iss': self.db.config.TRACKER_WEB,
                      'aud': self.db.config.TRACKER_WEB,
-                     'roles': [ 'User' ],
+                     'roles': ['User'],
                      'iat': now_ts,
-                     'exp': plus1min_ts,
-            }
+                     'exp': plus1min_ts}
 
             # in version 2.0.0 and newer jwt.encode returns string
             # not bytestring. So we have to skip b2s conversion
-            
+
             if version.parse(jwt.__version__) >= version.parse('2.0.0'):
                 tostr = lambda x: x
             else:
@@ -179,45 +180,53 @@
             # generate invalid claim with expired timestamp
             self.claim['expired'] = copy(claim)
             self.claim['expired']['exp'] = expired_ts
-            self.jwt['expired'] = tostr(jwt.encode(self.claim['expired'], secret,
-                                             algorithm='HS256'))
-         
+            self.jwt['expired'] = tostr(jwt.encode(
+                self.claim['expired'], secret,
+                algorithm='HS256'))
+
             # generate valid claim with user role
             self.claim['user'] = copy(claim)
             self.claim['user']['exp'] = plus1min_ts
-            self.jwt['user'] = tostr(jwt.encode(self.claim['user'], secret,
-                                          algorithm='HS256'))
+            self.jwt['user'] = tostr(jwt.encode(
+                self.claim['user'], secret,
+                algorithm='HS256'))
             # generate invalid claim bad issuer
             self.claim['badiss'] = copy(claim)
             self.claim['badiss']['iss'] = "http://someissuer/bugs"
-            self.jwt['badiss'] = tostr(jwt.encode(self.claim['badiss'], secret,
-                                          algorithm='HS256'))
+            self.jwt['badiss'] = tostr(jwt.encode(
+                self.claim['badiss'], secret,
+                algorithm='HS256'))
             # generate invalid claim bad aud(ience)
             self.claim['badaud'] = copy(claim)
             self.claim['badaud']['aud'] = "http://someaudience/bugs"
-            self.jwt['badaud'] = tostr(jwt.encode(self.claim['badaud'], secret,
-                                          algorithm='HS256'))            
+            self.jwt['badaud'] = tostr(jwt.encode(
+                self.claim['badaud'], secret,
+                algorithm='HS256'))
             # generate invalid claim bad sub(ject)
             self.claim['badsub'] = copy(claim)
             self.claim['badsub']['sub'] = str("99")
-            self.jwt['badsub'] = tostr(jwt.encode(self.claim['badsub'], secret,
-                                          algorithm='HS256'))            
+            self.jwt['badsub'] = tostr(
+                jwt.encode(self.claim['badsub'], secret,
+                           algorithm='HS256'))
             # generate invalid claim bad roles
             self.claim['badroles'] = copy(claim)
-            self.claim['badroles']['roles'] = [ "badrole1", "badrole2" ]
-            self.jwt['badroles'] = tostr(jwt.encode(self.claim['badroles'], secret,
-                                          algorithm='HS256'))            
+            self.claim['badroles']['roles'] = ["badrole1", "badrole2"]
+            self.jwt['badroles'] = tostr(jwt.encode(
+                self.claim['badroles'], secret,
+                algorithm='HS256'))
             # generate valid claim with limited user:email role
             self.claim['user:email'] = copy(claim)
-            self.claim['user:email']['roles'] = [ "user:email" ]
-            self.jwt['user:email'] = tostr(jwt.encode(self.claim['user:email'], secret,
-                                          algorithm='HS256'))
+            self.claim['user:email']['roles'] = ["user:email"]
+            self.jwt['user:email'] = tostr(jwt.encode(
+                self.claim['user:email'], secret,
+                algorithm='HS256'))
 
             # generate valid claim with limited user:emailnorest role
             self.claim['user:emailnorest'] = copy(claim)
-            self.claim['user:emailnorest']['roles'] = [ "user:emailnorest" ]
-            self.jwt['user:emailnorest'] = tostr(jwt.encode(self.claim['user:emailnorest'], secret,
-                                          algorithm='HS256'))
+            self.claim['user:emailnorest']['roles'] = ["user:emailnorest"]
+            self.jwt['user:emailnorest'] = tostr(jwt.encode(
+                self.claim['user:emailnorest'], secret,
+                algorithm='HS256'))
 
         self.db.tx_Source = 'web'
 
@@ -271,7 +280,7 @@
             if error.errno not in (errno.ENOENT, errno.ESRCH):
                 raise
 
-    def get_header (self, header, not_found=None):
+    def get_header(self, header, not_found=None):
         try:
             return self.headers[header.lower()]
         except (AttributeError, KeyError, TypeError):
@@ -305,13 +314,13 @@
             title='foo1',
             status=self.db.status.lookup('open'),
             priority=self.db.priority.lookup('normal'),
-            nosy = [ "1", "2" ]
+            nosy=["1", "2"]
         )
         issue_open_norm = self.db.issue.create(
             title='foo2',
             status=self.db.status.lookup('open'),
             priority=self.db.priority.lookup('normal'),
-            assignedto = "3"
+            assignedto="3"
         )
         issue_open_crit = self.db.issue.create(
             title='foo5',
@@ -371,31 +380,31 @@
         sort by status.name (not order)
         """
         base_path = self.db.config['TRACKER_WEB'] + 'rest/data/'
-        #self.maxDiff=None
+        # self.maxDiff=None
         self.create_sampledata()
         self.db.issue.set('2', status=self.db.status.lookup('closed'))
         self.db.issue.set('3', status=self.db.status.lookup('chatting'))
-        expected={'data':
-                   {'@total_size': 2,
-                    'collection': [
-                      { 'id': '2',
-                        'link': base_path + 'issue/2',
-                        'assignedto.issue': None,
-                        'status':
-                          { 'id': '10',
-                            'link': base_path + 'status/10'
+        expected = {'data':
+                    {'@total_size': 2,
+                     'collection': [
+                         {'id': '2',
+                          'link': base_path + 'issue/2',
+                          'assignedto.issue': None,
+                          'status':
+                          {'id': '10',
+                           'link': base_path + 'status/10'
                           }
-                      },
-                      { 'id': '1',
-                        'link': base_path + 'issue/1',
-                        'assignedto.issue': None,
-                        'status':
-                          { 'id': '9',
-                            'link': base_path + 'status/9'
+                         },
+                         {'id': '1',
+                          'link': base_path + 'issue/1',
+                          'assignedto.issue': None,
+                          'status':
+                          {'id': '9',
+                           'link': base_path + 'status/9'
                           }
-                      },
-                    ]}
-                 }
+                         },
+                     ]}
+        }
         form = cgi.FieldStorage()
         form.list = [
             cgi.MiniFieldStorage('status.name', 'o'),
@@ -411,7 +420,7 @@
         and a somewhat useful error message.
         """
         base_path = self.db.config['TRACKER_WEB'] + 'rest/data/'
-        #self.maxDiff=None
+        # self.maxDiff=None
         self.create_sampledata()
         self.db.issue.set('2', status=self.db.status.lookup('closed'))
         self.db.issue.set('3', status=self.db.status.lookup('chatting'))
@@ -471,22 +480,22 @@
         """ Retrieve all issues with an exact title
         """
         base_path = self.db.config['TRACKER_WEB'] + 'rest/data/'
-        #self.maxDiff=None
+        # self.maxDiff=None
         self.create_sampledata()
         self.db.issue.set('2', title='This is an exact match')
         self.db.issue.set('3', title='This is an exact match')
         self.db.issue.set('1', title='This is AN exact match')
-        expected={'data':
-                   {'@total_size': 2,
-                    'collection': [
-                      { 'id': '2',
-                        'link': base_path + 'issue/2',
-                      },
-                      { 'id': '3',
-                        'link': base_path + 'issue/3',
-                      },
-                    ]}
-                 }
+        expected = {'data':
+                    {'@total_size': 2,
+                     'collection': [
+                         {'id': '2',
+                          'link': base_path + 'issue/2',
+                         },
+                         {'id': '3',
+                          'link': base_path + 'issue/3',
+                         },
+                     ]}
+        }
         form = cgi.FieldStorage()
         form.list = [
             cgi.MiniFieldStorage('title:', 'This is an exact match'),
@@ -502,7 +511,6 @@
         self.create_sampledata()
         base_path = self.db.config['TRACKER_WEB'] + 'rest/data/issue/'
 
-
         # Check formating for issues status=open; @fields and verbose tests
         form = cgi.FieldStorage()
         form.list = [
@@ -511,13 +519,13 @@
             cgi.MiniFieldStorage('@verbose', '2')
         ]
 
-        expected={'data':
-                   {'@total_size': 3,
-                    'collection': [ {
+        expected = {'data':
+                    {'@total_size': 3,
+                     'collection': [ {
                          'creator': {'id': '3',
                                      'link': 'http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data/user/3',
                                      'username': 'joe'},
-                        'status': {'id': '9',
+                         'status': {'id': '9',
                                     'name': 'open',
                                     'link': 'http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data/status/9'},
                          'id': '1',
@@ -1094,7 +1102,7 @@
             # sqlite or anydbm. So don't need to exercise code.
             pass
         
-        start_time = datetime.utcnow()
+        start_time = utcnow()
         # don't set an accept header; json should be the default
         # use up all our allowed api calls
         for i in range(calls_per_interval):
@@ -1105,7 +1113,7 @@
                             "/rest/data/user/%s/realname"%self.joeid,
                             self.empty_form)
  
-            loop_time = datetime.utcnow()
+            loop_time = utcnow()
             self.assertLess((loop_time-start_time).total_seconds(),
                             int(wait_time_str),
                     "Test system is too slow to complete test as configured")
@@ -1148,10 +1156,10 @@
             wait_time_str)  # check as string
 
         print("Reset:", self.server.client.additional_headers["X-RateLimit-Reset"])
-        print("Now realtime pre-sleep:", datetime.utcnow())
+        print("Now realtime pre-sleep:", utcnow())
         # sleep as requested so we can do another login
         sleep(float(wait_time_str) + 0.1)
-        print("Now realtime post-sleep:", datetime.utcnow())
+        print("Now realtime post-sleep:", utcnow())
 
         # this should succeed
         self.server.client.additional_headers.clear()
@@ -1160,7 +1168,7 @@
                             self.empty_form)
         print(results)
         print("Reset:", self.server.client.additional_headers["X-RateLimit-Reset-date"])
-        print("Now realtime:", datetime.utcnow())
+        print("Now realtime:", utcnow())
         print("Now ts header:", self.server.client.additional_headers["Now"])
         print("Now date header:", self.server.client.additional_headers["Now-date"])
 

Roundup Issue Tracker: http://roundup-tracker.org/