Skip to content

Commit 9386729

Browse files
committed
Misc smaller refactoring
1 parent b45f423 commit 9386729

File tree

10 files changed

+126
-62
lines changed

10 files changed

+126
-62
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121

2222
* Added more validation of GMN settings
2323
* Added migrations to generate Postgres indexes for default sorting
24-
* Suprisingly, Django does not generate indexes for default sort ordering specified when using the ORM
24+
* Surprisingly, Django does not generate indexes for default sort ordering specified when using the ORM
2525

2626
* Reconfigured logging to take advantage of Django's support for rotating logs, much like logrotate does. Maximum space to use for logging is now a config setting.
2727
* Other usability improvements (see log)
2828

2929
* GMN deployment
3030

3131
* Improved and streamline GMN install procedures, including
32-
* Refactored install so that it can be accomplished by in two stages, where only the first stage needs to be performed by account with sudo access
32+
* Refactored install so that it can be accomplished in two stages, where only the first stage needs to be performed by account with sudo access
3333

3434
* Improved and cleaned up Apache conf file
3535
* Move from Rewrite to Redirect / Alias

README.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,6 @@ Edit `~/.pypirc`:
296296

297297
#### Updating dependencies
298298

299-
TODO: Move from pip to pipenv. https://docs.pipenv.org/
300-
301299
Update all packages managed by pip:
302300

303301
$ cd d1_python
@@ -328,17 +326,15 @@ Commit and push the changes, and check the build on Travis.
328326

329327
After successful build, clone a fresh copy, which will be used for building the release packages:
330328

331-
$ cd ~
332-
$ rm -rf ~/d1_python_build
333-
$ git clone [email protected]:DataONEorg/d1_python.git d1_python_build
334-
335329
Building the release packages from a fresh clone is a simple way of ensuring that only tracked files are released. It is a workaround for the way setuptools works, which is basically that it vacuums up everything that looks like a Python script in anything that looks like a package, which makes it easy to publish local files by accident.
336330

337331
Build and publish the packages:
338332

339-
cd ~/d1_python_build
340-
setup-all.py --root . bdist_wheel upload
341-
333+
$ cd
334+
$ rm -rf ~/d1_python_build
335+
$ git clone [email protected]:DataONEorg/d1_python.git d1_python_build
336+
$ cd ~/d1_python_build
337+
$ python3 ./dev_tools/src/d1_dev/setup-all.py --root . bdist_wheel upload
342338

343339
### Building the documentation
344340

gmn/src/d1_gmn/deployment/gmn3-ssl.conf

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
define gmn_base /mn
1010

1111
ServerName ${server_name}
12-
WSGIPythonHome ${d1_root}/gmn_venv_py3
12+
WSGIPythonHome ${gmn_venv}
1313

1414
<VirtualHost *:80>
1515
Redirect / https://${server_name}/
@@ -52,10 +52,11 @@
5252
WSGIDaemonProcess gmn3 user=gmn processes=2 threads=25 python-path=${gmn_pkg}
5353
WSGIProcessGroup gmn3
5454

55-
Alias /robots.txt ${gmn_root}/app/static/robots.txt
56-
Alias /static/ ${gmn_root}/app/static/
57-
RedirectMatch "^/?$" ${gmn_base}/home
55+
Alias /robots.txt ${gmn_root}/app/static/robots.txt
56+
Alias /static/ ${gmn_root}/app/static/
57+
RedirectMatch "^/?$" ${gmn_base}/home
5858
RedirectMatch "^${gmn_base}/?$" ${gmn_base}/v2/node
5959

60+
AddType text/xsl .xsl
6061
</VirtualHost>
6162
</IfModule>

gmn/src/d1_gmn/tests/gmn_direct.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def get_log_records(version_tag, pid=None, start=None, count=None):
132132

133133
def _add_query(query_dict, url_path):
134134
if query_dict:
135-
url_str = '{}?{}'.format(url_path, d1_common.url.urlencode(query_dict))
135+
url_str = '{}?{}'.format(url_path, d1_common.url.encodePathElement().urlencode(query_dict))
136136
else:
137137
url_str = url_path
138138
return url_str

gmn/src/d1_gmn/wsgi.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525

2626
import django
2727
import django.core.handlers.wsgi
28+
import django.http
2829
import django.utils
30+
import django.utils.datastructures
2931

3032
os.environ['DJANGO_SETTINGS_MODULE'] = 'd1_gmn.settings'
3133

lib_common/src/d1_common/resource_map.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import d1_common.url
4444
import d1_common.util
4545

46-
# RDFLib wrappers around the namespaces. Others are defined by RDFLib
46+
# RDFLib wrappers around the namespaces. Additional ones are defined by RDFLib
4747
DCTERMS = rdflib.Namespace(d1_common.const.ORE_NAMESPACE_DICT['dcterms'])
4848
CITO = rdflib.Namespace(d1_common.const.ORE_NAMESPACE_DICT['cito'])
4949
ORE = rdflib.Namespace(d1_common.const.ORE_NAMESPACE_DICT['ore'])
@@ -133,7 +133,7 @@ def oreInitialize(self, pid, ore_software_id=d1_common.const.ORE_SOFTWARE_ID):
133133
self.add((ore, DCTERMS.identifier, rdflib.term.Literal(pid)))
134134
self.add((ore, DCTERMS.creator, rdflib.term.Literal(ore_software_id)))
135135
# Add an empty aggregation
136-
ag = rdflib.URIRef(d1_common.url.joinPathElements(oid, 'aggregation'))
136+
ag = rdflib.URIRef(oid + '#aggregation')
137137
self.add((ore, ORE.describes, ag))
138138
self.add((ag, rdflib.RDF.type, ORE.Aggregation))
139139
self.add((ORE.Aggregation, rdflib.RDFS.isDefinedBy, ORE.term('')))

lib_common/src/d1_common/tests/test_url.py

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,27 @@
2525

2626
import d1_test.d1_test_case
2727
import d1_test.sample
28+
import d1_test.test_files
2829

29-
HERE_DIR_PATH = os.path.abspath(os.path.dirname(__file__))
30+
# HERE_DIR_PATH = os.path.abspath(os.path.dirname(__file__))
3031

3132

3233
class TestUrl(d1_test.d1_test_case.D1TestCase):
33-
unicode_str_list = d1_test.sample.load_utf8_to_str(
34-
'testUnicodeStrings.utf8.txt'
35-
)
34+
# unicode_str_list = d1_test.test_files.load_utf8_to_str(
35+
# 'testUnicodeStrings.utf8.txt'
36+
# )
3637

3738
def test_1000(self):
3839
"""encodePathElement()"""
39-
for row in self.unicode_str_list.splitlines():
40-
assert isinstance(row, str)
41-
parts = row.split('\t')
42-
if len(parts) > 1:
43-
v = parts[0]
44-
if v.startswith('common') or v.startswith('path'):
45-
e = parts[1].strip()
46-
assert e == d1_common.url.encodePathElement(v)
40+
for did, enc_did in d1_test.test_files.TRICKY_IDENTIFIER_LIST:
41+
if did.startswith('common') or did.startswith('path'):
42+
assert enc_did == d1_common.url.encodePathElement(did)
4743

4844
def test_1010(self):
4945
"""encodeQueryElement()"""
50-
for row in self.unicode_str_list.splitlines():
51-
parts = row.split('\t')
52-
if len(parts) > 1:
53-
v = parts[0]
54-
if v.startswith('common') or v.startswith('query'):
55-
e = parts[1].strip()
56-
assert e == d1_common.url.encodeQueryElement(v)
57-
58-
def test_1020(self):
59-
"""urlencode()"""
60-
data = [('a', '"#<>[]^`{}|'), ('b', '-&=&='),
61-
('c', 'http://example.com/data/mydata?row=24')]
62-
expected = (
63-
'a=%22%23%3C%3E%5B%5D%5E%60%7B%7D%7C&b=-%26%3D%26%3D&c='
64-
'http://example.com/data/mydata?row%3D24'
65-
)
66-
test = d1_common.url.urlencode(data)
67-
assert test == expected
46+
for did, enc_did in d1_test.test_files.TRICKY_IDENTIFIER_LIST:
47+
if did.startswith('common') or did.startswith('path'):
48+
assert enc_did == d1_common.url.encodeQueryElement(did)
6849

6950
def test_1030(self):
7051
"""stripElementSlashes()"""

test_utilities/src/d1_test/d1_test_case.py

Lines changed: 95 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,25 @@
1919
# See the License for the specific language governing permissions and
2020
# limitations under the License.
2121
"""Utilities for unit- and integration tests"""
22-
22+
import codecs
2323
import collections
2424
import contextlib
2525
import datetime
2626
import gc
2727
import inspect
2828
import io
29+
import json
2930
import logging
3031
import os
3132
import random
33+
import re
3234
import resource
3335
import sys
3436
import tempfile
3537
import traceback
3638
import xml
3739

40+
import d1_common
3841
import decorator
3942
import mock
4043
import psutil
@@ -54,6 +57,7 @@
5457
import d1_test.instance_generator.date_time
5558
import d1_test.instance_generator.system_metadata
5659
import d1_test.sample
60+
import d1_test.test_files
5761

5862
CN_URL = d1_common.const.URL_DATAONE_ROOT
5963

@@ -79,6 +83,7 @@
7983
}
8084

8185

86+
8287
@contextlib.contextmanager
8388
def capture_std():
8489
"""Capture stdout and stderr.
@@ -208,11 +213,11 @@ def temp_sparse_file(gib=0, mib=0, kib=0, b=0):
208213

209214

210215
@contextlib.contextmanager
211-
def temp_file_name():
216+
def temp_file_name(suffix=None):
212217
"""Provide a file path that can be used as the location of a temporary file,
213218
and delete any file written to the path on exit
214219
"""
215-
with tempfile.NamedTemporaryFile() as f:
220+
with tempfile.NamedTemporaryFile(suffix=suffix) as f:
216221
temp_file_path = f.name
217222
yield temp_file_path
218223
try:
@@ -236,8 +241,9 @@ def memory_limit(max_mem_bytes):
236241
current_used_bytes = process.memory_info().vms
237242
limit_bytes = current_used_bytes + max_mem_bytes
238243
logging.debug(
239-
'Setting memory limit. current={:,} bytes, limit={:,} bytes'.
240-
format(current_used_bytes, limit_bytes)
244+
'Setting memory limit. current={:,} bytes, limit={:,} bytes'.format(
245+
current_used_bytes, limit_bytes
246+
)
241247
)
242248
resource.setrlimit(
243249
resource.RLIMIT_AS,
@@ -262,6 +268,11 @@ class D1TestCase(object):
262268
def sample(self):
263269
return d1_test.sample
264270

271+
@property
272+
def test_files(self):
273+
return d1_test.test_files
274+
275+
265276
@staticmethod
266277
def deserialize_and_check(doc, raises_pyxb_exc=False):
267278
try:
@@ -312,19 +323,91 @@ def touch(module_path, times=None):
312323
with open(module_path, 'a'):
313324
os.utime(module_path, times)
314325

326+
327+
#
328+
# Exception handling
329+
#
330+
331+
# @staticmethod
332+
# def get_d1_test_case_location(exc_traceback=None):
333+
# """Return the abs path and line number of the unit test that directly or
334+
# indirectly triggered the exception
335+
# - Use the exception currently being handled if exc_traceback is None,
336+
# else use exc_traceback.
337+
# - The unit test must be a method in a class that derives from D1TestCase.
338+
# """
339+
# tb_frame = D1TestCase.get_last_d1_test_case_frame(exc_traceback)
340+
# return tb_frame.f_code.co_filename, tb_frame.f_lineno #+ 1
341+
342+
# exc_traceback = D1TestCase.get_and_check_traceback(exc_traceback)
343+
# location_tup = None
344+
# while exc_traceback:
345+
# if D1TestCase.frame_is_d1_test_case_method(exc_traceback):
346+
# co = exc_traceback.tb_frame.f_code
347+
# location_tup = co.co_filename, co.co_firstlineno + 1
348+
# exc_traceback = exc_traceback.tb_next
349+
# if location_tup:
350+
# return location_tup
351+
# raise Exception(
352+
# "Exception was not triggered in a D1TestCase unit test method"
353+
# )
354+
355+
356+
@staticmethod
357+
def get_d1_test_case_location(exc_traceback=None):
358+
"""Return the last stack frame that holds a D1TestCase unit test method
359+
- Use the exception currently being handled if exc_traceback is None,
360+
else use exc_traceback.
361+
- The unit test must be a method in a class that derives from D1TestCase.
362+
"""
363+
exc_traceback = D1TestCase.get_and_check_traceback(exc_traceback)
364+
location_tup = None
365+
while exc_traceback:
366+
if D1TestCase.frame_is_d1_test_case_method(exc_traceback):
367+
location_tup = (
368+
exc_traceback.tb_frame.f_code.co_filename,
369+
exc_traceback.tb_lineno,
370+
)
371+
372+
exc_traceback = exc_traceback.tb_next
373+
if not location_tup:
374+
raise Exception(
375+
"Exception was not triggered in a D1TestCase unit test method"
376+
)
377+
return location_tup
378+
379+
380+
@staticmethod
381+
def frame_is_d1_test_case_method(exc_traceback):
382+
try:
383+
return isinstance(exc_traceback.tb_frame.f_locals['self'],
384+
D1TestCase)
385+
except KeyError:
386+
return False
387+
388+
389+
@staticmethod
390+
def get_and_check_traceback(tb):
391+
tb = tb or sys.exc_info()[2]
392+
assert hasattr(tb, "tb_next"), \
393+
"Not a valid traceback. Must be a native Python traceback, not a " \
394+
"pytest.Traceback."
395+
return tb
396+
397+
#
398+
# Misc
399+
#
400+
315401
@staticmethod
316402
@contextlib.contextmanager
317403
def mock_ssl_download(cert_obj):
318404
"""Simulate successful cert download by catching call to
319405
ssl.SSLSocket.getpeercert() and returning {cert_obj} in DER format.
320406
"""
321407
cert_der = d1_common.cert.x509.get_cert_der(cert_obj)
322-
with mock.patch(
323-
'd1_common.cert.x509.ssl.SSLSocket.connect'
324-
) as mock_connect:
325-
with mock.patch(
326-
'd1_common.cert.x509.ssl.SSLSocket.getpeercert'
327-
) as mock_getpeercert:
408+
with mock.patch('d1_common.cert.x509.ssl.SSLSocket.connect') as mock_connect:
409+
with mock.patch('d1_common.cert.x509.ssl.SSLSocket.getpeercert'
410+
) as mock_getpeercert:
328411
mock_getpeercert.return_value = cert_der
329412
yield mock_connect, mock_getpeercert
330413

@@ -426,7 +509,6 @@ def prep_node_list(self, node_list, tag_str, num_nodes=5):
426509
for _ in range(num_nodes)
427510
]
428511

429-
430512
#===============================================================================
431513

432514
# import logging, logging.config, colorstreamhandler
@@ -496,3 +578,4 @@ def get_test_module_name():
496578
module_name = os.path.splitext(os.path.split(module_path)[1])[0]
497579
if module_name.startswith('test_') and func_name.startswith('test_'):
498580
return module_name
581+

test_utilities/src/d1_test/utilities/generate_test_subject_certs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ def create_session_extension(subject, persons, groups):
247247

248248

249249
def create_certificate(
250+
# TODO: Fix and test
250251
req, xxx_todo_changeme, serial, xxx_todo_changeme1, digest="md5"
251252
):
252253
"""Generate a certificate given a certificate request.

utilities/src/d1_util/jwt_token_tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ def find_valid_combinations(cert_file_name_list, jwt_file_name_list):
9999
successfully validated with the cert.
100100
"""
101101
for cert_file_name in cert_file_name_list:
102-
cert_pem = '' # self.sample.load_utf8_to_str(cert_file_name)
102+
cert_pem = '' # self.test_files.load_utf8_to_str(cert_file_name)
103103
cert_obj = d1_common.cert.x509.deserialize_pem(cert_pem)
104104
# d1_common.cert.x509.log_cert_info(logging.info, 'CERT', cert_obj)
105105
for jwt_file_name in jwt_file_name_list:
106-
jwt_bu64 = '' # self.sample.load_utf8_to_str(jwt_file_name)
106+
jwt_bu64 = '' # self.test_files.load_utf8_to_str(jwt_file_name)
107107
# d1_common.cert.jwt.log_jwt_bu64_info(logging.info, 'JWT', jwt_bu64)
108108
is_ok = False
109109
try:

0 commit comments

Comments
 (0)