Skip to content
Snippets Groups Projects
Commit 107bc846 authored by Daniel Lyons's avatar Daniel Lyons
Browse files

Merge pull request #6 in SSA/pycapo from release/0.3 to main

* commit '3d2b9d63':
  SSA-6463: version bump fix
  SSA-6463: version bump and release prep
  SSA-6463: now using fake properties files in test_pycapo
  SSA-6463: fixed last deprecation warning and added more unit tests for pycapo
  SSA-6463: fix deprecated method call
  SSA-6463: version bump per Daniel
  SSA-6463: replaced deprecated readfp() with read_file()
parents 6d761bd6 3d2b9d63
No related branches found
No related tags found
No related merge requests found
""" Version information for this package, don't put anything else here. """ """ Version information for this package, don't put anything else here. """
___version___ = '0.2.1' ___version___ = '0.3.1'
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
import os import os
import os.path import os.path
import re import re
import sys
try: try:
import configparser import configparser
...@@ -16,7 +15,7 @@ except ImportError: ...@@ -16,7 +15,7 @@ except ImportError:
from pycapo import DEFAULT_CAPO_PATH from pycapo import DEFAULT_CAPO_PATH
_ENV_PATTERN = re.compile('\$\{env:([a-zA-Z\_]+)\}') _ENV_PATTERN = re.compile(r'\$\{env:([a-zA-Z\_]+)\}')
class CapoConfig: class CapoConfig:
...@@ -262,9 +261,10 @@ class _SimpleConfigParser(configparser.RawConfigParser): ...@@ -262,9 +261,10 @@ class _SimpleConfigParser(configparser.RawConfigParser):
NOSECTION = 'NOSECTION' NOSECTION = 'NOSECTION'
def read(self, filename): def read(self, filename):
text = open(filename, 'r').read() with open(filename, 'r') as f:
f = stringio.StringIO("[%s]\n" % self.NOSECTION + text) text = f.read()
self.readfp(f, filename) f = stringio.StringIO("[%s]\n" % self.NOSECTION + text)
self.read_file(f, filename)
def getoption(self, option): def getoption(self, option):
'get the value of an option' 'get the value of an option'
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from setuptools import setup, find_packages ''' CAPO setup '''
import os import os
from setuptools import setup, find_packages
NAME = 'pycapo' NAME = 'pycapo'
HERE = os.path.abspath(os.path.dirname(__file__)) HERE = os.path.abspath(os.path.dirname(__file__))
...@@ -18,6 +20,8 @@ setup(name=NAME, ...@@ -18,6 +20,8 @@ setup(name=NAME,
long_description=README + '\n\n' + CHANGES, long_description=README + '\n\n' + CHANGES,
author='Stephan Witz', author='Stephan Witz',
author_email='switz@nrao.edu', author_email='switz@nrao.edu',
maintainer='Janet L. Goldstein',
maintainer_email='jgoldste@nrao.edu',
url='https://open-bitbucket.nrao.edu/projects/SSA/repos/pycapo', url='https://open-bitbucket.nrao.edu/projects/SSA/repos/pycapo',
keywords='', keywords='',
license='GPL', license='GPL',
...@@ -43,7 +47,7 @@ setup(name=NAME, ...@@ -43,7 +47,7 @@ setup(name=NAME,
test_suite='pycapo.tests', test_suite='pycapo.tests',
install_requires=[], install_requires=[],
tests_require=['pytest'], tests_require=['pytest'],
setup_requires=['pytest-runner','pytest'], setup_requires=['pytest-runner', 'pytest'],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
'pycapo = pycapo.commands:pycapo' 'pycapo = pycapo.commands:pycapo'
......
# PyCapo configuration file to set values for development context.
# Ensure that the environment variable $CAPO_PROFILE is set correctly
# to enable use of this file.
tunes.looney.metadataDatabaseJdbcUsername = elmer
tunes.looney.metadataDatabaseJdbcPassword = wascally_wabbit
tunes.looney.metadataDatabaseJdbcUrl = jdbc:postgresql://dev.looney-toons.net/meta
tunes.looney.someOtherDatabaseJdbcUsername = bugs_ro
tunes.looney.someOtherDatabaseJdbcPassword = 'wazzup-doc'
tunes.looney.someOtherDatabaseJdbcUrl = jdbc:oracle:thin:@//dev.looney-toons.net:1521/legacy
tunes.looney.metadataDatabaseJdbcUsername =
# PyCapo configuration file to set values for production context.
# Ensure that the environment variable $CAPO_PROFILE is set correctly
# to enable use of this file.
tunes.looney.metadataDatabaseJdbcUsername = elmer
tunes.looney.metadataDatabaseJdbcPassword = wascally_wabbit
tunes.looney.metadataDatabaseJdbcUrl = jdbc:postgresql://prod.looney-toons.net/meta
tunes.looney.someOtherDatabaseJdbcUsername = bugs
tunes.looney.someOtherDatabaseJdbcPassword = 'no, really'
tunes.looney.someOtherDatabaseJdbcUrl = jdbc:oracle:thin:@//prod.looney-toons.net:1521/legacy
...@@ -27,7 +27,7 @@ OPTIONS = ( ...@@ -27,7 +27,7 @@ OPTIONS = (
class CapoTest: class CapoTest:
""" A class that builds a test environment for pycapo with two """ A class that builds a test environment for pycapo with two
properties files, a/test.properties and b/test.properties, with properties files, a/test.properties and b/test.properties, with
options defined in the OPTOINS dict above. """ options defined in the OPTIONS dict above. """
def __init__(self, tmpdir): def __init__(self, tmpdir):
self.tmpdir = tmpdir self.tmpdir = tmpdir
......
# -*- coding: utf-8 -*-
""" CapoConfig tests """
import os
import shutil
import subprocess
import sys
import unittest
from enum import Enum
from pathlib import Path
import pytest
from pycapo import CapoConfig
_TEST_PROFILES = ['dev_profile', 'prod_profile', 'empty_profile']
class Keys(Enum):
''' Keys in our fake Capo profiles '''
METADATA_USER = 'TUNES.LOONEY.METADATADATABASE.JDBCUSERNAME'
METADATA_PW = 'TUNES.LOONEY.METADATADATABASEJDBCPASSWORD'
METADATA_URL = 'TUNES.LOONEY.METADATADATABASEJDBCURL'
OTHER_USER = 'TUNES.LOONEY.SOMEOTHERDATABASEJDBCUSERNAME'
OTHER_PW = 'TUNES.LOONEY.SOMEOTHERDATABASEJDBCPASSWORD'
OTHER_URL = 'TUNES.LOONEY.SOMEOTHERDATABASEJDBCURL'
class PycapoTestCase(unittest.TestCase):
''' Tests for pycapo and CapoConfig() '''
@classmethod
def setUpClass(cls) -> None:
cls.get_props_files(cls)
cls.capo_dir_was_created = False
@classmethod
def tearDownClass(cls) -> None:
cls.delete_properties(cls)
def test_capo_copes_with_bad_path(self):
''' if capo path is bad, capo should default to something usual
rather than crashing
'''
user = os.environ['USER']
for profile in _TEST_PROFILES:
capo_config = CapoConfig(profile=profile, path='foo')
self.assertTrue(user in capo_config.getpath())
try:
for key, val in capo_config.getoptions().items():
if 'prod' not in profile:
self.assertFalse('prod' in val)
if key == Keys.OTHER_URL.value:
self.assertTrue('dev' in val)
else:
if key == Keys.METADATA_USER.value:
self.assertTrue('_ro' not in val)
if key == Keys.OTHER_URL.value:
self.assertTrue('prod' in val)
except Exception as exc:
pytest.fail(f'failure for {capo_config.profile}, '
f'{capo_config.getpath()}: {exc}')
def test_gets_expected_values_for_profile(self):
''' properties files for different profiles may (or may not)
have disparate values
'''
for profile in _TEST_PROFILES:
try:
capo_config = CapoConfig(profile=profile)
try:
options = capo_config.getoptions()
for key, val in options.items():
if key == Keys.OTHER_URL:
self.assertTrue('thin' in val)
if 'prod' not in profile:
self.assertFalse('prod' in val)
if key == Keys.OTHER_URL.value:
self.assertTrue('dev' in val)
else:
if key == Keys.METADATA_USER.value:
self.assertTrue('_ro' not in val)
if key == Keys.OTHER_URL.value:
self.assertTrue('prod' in val)
except Exception as exc:
pytest.fail(f'failure for {profile} '
f'when {key}=={val}: {exc}')
except Exception as exc:
pytest.fail(f'failure for {profile}: {exc}')
def test_capo_config_handles_bad_args_expectedly(self):
''' CapoConfig() should complain when given bad args or none '''
with pytest.raises(ValueError):
CapoConfig(profile=None)
CapoConfig()
CapoConfig(path='foo')
bogus_config = CapoConfig(profile='bogus')
# CapoConfig() should NOT have any default values
self.assertEqual(0, len(bogus_config.getoptions()))
self.assertEqual(0, len(bogus_config.getlocations()))
def test_missing_setting_fails_expectedly(self):
''' missing Capo setting should return appropriate code '''
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run(profile='empty_profile')
self.assertEqual(3, exc.value)
def test_command_line_returns_expected_code(self):
''' under various scenarios, pycapo should return appropriate code
for each
'''
# no arguments: should fail w/approp return code
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run()
self.assertEqual(2, exc.value)
# one argument, not a k/v pair: should fail w/approp return code
with pytest.raises(TypeError) as exc:
CommandLineLauncher().run('dev_profile')
self.assertEqual(2, exc.value)
# invalid k/v pair
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run(foo='bar')
self.assertEqual(1, exc.value)
# key but no value
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run(profile=None)
self.assertEqual(1, exc.value)
# invalid profile
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run(profile='foo')
self.assertEqual(1, exc.value)
# no profile; invalid path
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run(path='foo')
self.assertEqual(1, exc.value)
# no profile; valid path
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run(path=Path.cwd())
self.assertEqual(1, exc.value)
# valid profile, invalid path
with pytest.raises(SystemExit) as exc:
CommandLineLauncher().run(profile='dev_profile', path='foo')
self.assertEqual(1, exc.value)
### UTILITIES ###
def get_props_files(self):
''' grab our fake properties files and copy them to user's .capo dir '''
user_home = Path(os.environ['HOME'])
capo_path = user_home / '.capo'
props_source_dir = Path.cwd() / 'tests/test_data'
if not capo_path.is_dir():
capo_path.mkdir()
self.capo_dir_was_created = True
for profile in _TEST_PROFILES:
filename = profile + '.properties'
source = props_source_dir / filename
destn = capo_path / filename
shutil.copy(str(source), str(destn))
def delete_properties(self):
''' delete fake properties files from user's .capo dir '''
user_home = Path(os.environ['HOME'])
default_path = user_home / '.capo'
for profile in _TEST_PROFILES:
filename = profile + '.properties'
to_delete = default_path / filename
if to_delete.is_file():
to_delete.unlink()
if self.capo_dir_was_created:
default_path.unlink()
class CommandLineLauncher:
''' launches a system process and executes a pycapo command '''
def run(self, **kwargs):
''' kick off pycapo with these args and grab return code '''
args = ['pycapo']
if kwargs:
for arg in kwargs:
args.append(arg)
try:
proc = subprocess.run(args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=False,
timeout=100,
bufsize=1,
universal_newlines=True)
if proc.returncode != 0:
sys.exit(proc.returncode)
return proc.returncode
except Exception as exc:
pytest.fail(f'Error launching pycapo with args {args}: {exc}')
if __name__ == '__main__':
unittest.main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment