Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion hca/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ def special_cli_command(self, required_argument, optional_argument=""):
from requests_oauthlib import OAuth2Session
from urllib3.util import retry, timeout
from jsonpointer import resolve_pointer
from datetime import datetime

from .. import get_config, logger
from .compat import USING_PYTHON2
Expand Down Expand Up @@ -176,6 +177,7 @@ class SwaggerClient(object):
_authenticated_session = None
_session = None
_swagger_spec = None
_spec_valid_for_days = 7
_type_map = {
"string": str,
"number": float,
Expand Down Expand Up @@ -238,7 +240,9 @@ def swagger_spec(self):
else:
swagger_filename = base64.urlsafe_b64encode(swagger_url.encode()).decode() + ".json"
swagger_filename = os.path.join(self.config.user_config_dir, swagger_filename)
if not os.path.exists(swagger_filename):
is_cached = os.path.exists(swagger_filename)
if (not is_cached) or (is_cached and
self._get_days_since_last_modified(swagger_filename) >= self._spec_valid_for_days):
try:
os.makedirs(self.config.user_config_dir)
except OSError as e:
Expand Down Expand Up @@ -298,6 +302,11 @@ def login(self, access_token=""):
token_type="Bearer")
print("Storing access credentials")

def _get_days_since_last_modified(self, filename):
now = datetime.now()
last_modified = datetime.fromtimestamp(os.path.getmtime(filename))
return (now - last_modified).days

def _get_oauth_token_from_service_account_credentials(self):
scopes = ["https://www.googleapis.com/auth/userinfo.email"]
assert 'GOOGLE_APPLICATION_CREDENTIALS' in os.environ
Expand Down
3 changes: 3 additions & 0 deletions test/test_dss_api_retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from requests import ConnectTimeout
from urllib3 import Timeout
from datetime import datetime

from hca.util import RetryPolicy

Expand Down Expand Up @@ -61,10 +62,12 @@ def test_get_retry(self):
client = hca.dss.DSSClient()
file_uuid = str(uuid.uuid4())
creator_uid = client.config.get("creator_uid", 0)
version = datetime.utcnow().strftime("%Y-%m-%dT%H%M%S.%fZ")

client.put_file._request(
dict(
uuid=file_uuid,
version=version,
bundle_uuid=str(uuid.uuid4()),
creator_uid=creator_uid,
source_url=TestDssApiRetry.source_url,
Expand Down
91 changes: 91 additions & 0 deletions test/test_dss_swagger_spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env python
# coding: utf-8

import unittest
import requests
from hca.util.compat import USING_PYTHON2

import hca.dss

if USING_PYTHON2:
import mock
from mock import mock_open
else:
from unittest import mock
from unittest.mock import mock_open


class TestDssSwaggerSpec(unittest.TestCase):
client = hca.dss.DSSClient()
swagger_url = ""
dummy_response = None
open_fn_name = "__builtin__.open" if USING_PYTHON2 else "builtins.open"

def setUp(self):
self.client.__class__._swagger_spec = None
self.client._spec_valid_for_days = 1
self.swagger_url = "test_swagger_url"
self.client._session = requests.Session()
self.client.config.__dict__.update({
'DSSClient': {
'swagger_url': self.swagger_url
},
'swagger_filename': "test_filename"
})
self.dummy_response = requests.models.Response()
self.dummy_response._content = b'{"swagger": ""}'
self.dummy_response.status_code = 200

def tearDown(self):
self.client.__class__._swagger_spec = None

def test_get_swagger_spec_new(self):
with mock.patch('os.path.exists') as mock_exists, \
mock.patch('hca.dss.SwaggerClient._get_days_since_last_modified') as mock_days_since_last_modified, \
mock.patch('os.makedirs') as mock_makedirs, \
mock.patch('requests.Session.get') as mock_get, \
mock.patch('hca.dss.SwaggerClient.load_swagger_json'), \
mock.patch(self.open_fn_name, mock_open()) as open_mock:
mock_exists.return_value = False
mock_days_since_last_modified.return_value = 0
mock_get.return_value = self.dummy_response

test = self.client.swagger_spec
self.assertTrue(mock_makedirs.called)
self.assertTrue(mock_get.calledWith(self.swagger_url))
self.assertTrue(open_mock().write.calledWith(self.dummy_response._content))

def test_get_swagger_spec_cache_valid(self):
with mock.patch('os.path.exists') as mock_exists, \
mock.patch('hca.dss.SwaggerClient._get_days_since_last_modified') as mock_days_since_last_modified, \
mock.patch('os.makedirs') as mock_makedirs, \
mock.patch('requests.Session.get') as mock_get, \
mock.patch('hca.dss.SwaggerClient.load_swagger_json'), \
mock.patch(self.open_fn_name, mock_open()) as open_mock:
mock_exists.return_value = True
mock_days_since_last_modified.return_value = 0
mock_get.return_value = self.dummy_response

test = self.client.swagger_spec
self.assertFalse(mock_makedirs.called)
self.assertFalse(mock_get.called)
self.assertFalse(open_mock().write.called)

def test_get_swagger_spec_cache_expired(self):
with mock.patch('os.path.exists') as mock_exists, \
mock.patch('hca.dss.SwaggerClient._get_days_since_last_modified') as mock_days_since_last_modified, \
mock.patch('os.makedirs') as mock_makedirs, \
mock.patch('requests.Session.get') as mock_get, \
mock.patch('hca.dss.SwaggerClient.load_swagger_json'), \
mock.patch(self.open_fn_name, mock_open()) as open_mock:
mock_exists.return_value = True
mock_days_since_last_modified.return_value = 2
mock_get.return_value = self.dummy_response

test = self.client.swagger_spec
self.assertTrue(mock_get.calledWith(self.swagger_url))
self.assertTrue(open_mock().write.calledWith(self.dummy_response._content))


if __name__ == '__main__':
unittest.main()