Skip to content

Commit f84b980

Browse files
committed
Merge pull request #23 from IQSS/automated-tests
Automated tests
2 parents ad72655 + f5f31f0 commit f84b980

File tree

12 files changed

+128
-42
lines changed

12 files changed

+128
-42
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
.cache/
66
local.py
77
*~
8-
*.egg-info/
8+
*.egg-info/
9+

.travis.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
language: python
2+
python:
3+
- 2.6
4+
- 2.7
5+
- 3.3
6+
#- 3.4 # "No output has been received in the last 10 minutes, this potentially indicates a stalled build or something wrong with the build itself."
7+
install:
8+
- pip install -U .
9+
- pip install httpretty pytest flake8
10+
script:
11+
- flake8 .
12+
- py.test

dataverse/connection.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ class Connection(object):
1313
def __init__(self, host, token):
1414
self.token = token
1515
self.host = host
16-
self.sd_uri = 'https://{host}/dvn/api/data-deposit/v1.1/swordv2/service-document'.format(host=self.host)
16+
17+
self.base_url = 'https://{0}'.format(self.host)
18+
self.native_base_url = '{0}/api/v1'.format(self.base_url)
19+
self.sword_base_url = '{0}/dvn/api/data-deposit/v1.1/swordv2'.format(self.base_url)
20+
self.sd_uri = '{0}/service-document'.format(self.sword_base_url)
1721
self._service_document = None
1822

1923
self.get_service_document()
@@ -38,7 +42,7 @@ def get_service_document(self, refresh=False):
3842

3943
def create_dataverse(self, alias, name, email, parent=':root'):
4044
resp = requests.post(
41-
'https://{0}/api/dataverses/{1}'.format(self.host, parent),
45+
'{0}/dataverses/{1}'.format(self.native_base_url, parent),
4246
json={
4347
'alias': alias,
4448
'name': name,
@@ -48,26 +52,36 @@ def create_dataverse(self, alias, name, email, parent=':root'):
4852
)
4953

5054
if resp.status_code == 404:
51-
raise exceptions.DataverseNotFoundError('Dataverse {0} was not found.'.format(parent))
55+
raise exceptions.DataverseNotFoundError(
56+
'Dataverse {0} was not found.'.format(parent)
57+
)
5258
elif resp.status_code != 201:
53-
raise exceptions.OperationFailedError('{0} Dataverse could not be created.'.format(name))
59+
raise exceptions.OperationFailedError(
60+
'{0} Dataverse could not be created.'.format(name)
61+
)
5462

5563
self.get_service_document(refresh=True)
5664
return self.get_dataverse(alias)
5765

5866
def delete_dataverse(self, dataverse):
5967

6068
resp = requests.delete(
61-
'https://{0}/api/dataverses/{1}'.format(self.host, dataverse.alias),
69+
'{0}/dataverses/{1}'.format(self.native_base_url, dataverse.alias),
6270
params={'key': self.token},
6371
)
6472

6573
if resp.status_code == 401:
66-
raise exceptions.UnauthorizedError('Delete Dataverse unauthorized.')
74+
raise exceptions.UnauthorizedError(
75+
'Delete Dataverse {0} unauthorized.'.format(dataverse.alias)
76+
)
6777
elif resp.status_code == 404:
68-
raise exceptions.DataverseNotFoundError('Dataverse {0} was not found.'.format(dataverse.alias))
78+
raise exceptions.DataverseNotFoundError(
79+
'Dataverse {0} was not found.'.format(dataverse.alias)
80+
)
6981
elif resp.status_code != 200:
70-
raise exceptions.OperationFailedError('Dataverse {0} could not be deleted.'.format(dataverse.alias))
82+
raise exceptions.OperationFailedError(
83+
'Dataverse {0} could not be deleted.'.format(dataverse.alias)
84+
)
7185

7286
self.get_service_document(refresh=True)
7387

dataverse/dataset.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,18 @@ def get_metadata(self, version='latest', refresh=False):
185185
if not self.dataverse:
186186
raise NoContainerError('This dataset has not been added to a Dataverse.')
187187

188-
url = 'https://{0}/api/datasets/{1}/versions/:{2}'.format(
189-
self.connection.host,
188+
url = '{0}/datasets/{1}/versions/:{2}'.format(
189+
self.connection.native_base_url,
190190
self.id,
191191
version,
192192
)
193193

194194
resp = requests.get(url, params={'key': self.connection.token})
195195

196196
if resp.status_code == 404:
197-
raise VersionJsonNotFoundError('JSON metadata could not be found for this version.')
197+
raise VersionJsonNotFoundError(
198+
'JSON metadata could not be found for this version.'
199+
)
198200
elif resp.status_code != 200:
199201
raise ConnectionError('JSON metadata could not be retrieved.')
200202

@@ -203,7 +205,11 @@ def get_metadata(self, version='latest', refresh=False):
203205

204206
# Update corresponding version metadata if retrieving 'latest'
205207
if version == 'latest':
206-
latest_version = 'latest-published' if metadata['versionState'] == 'RELEASED' else 'draft'
208+
latest_version = (
209+
'latest-published'
210+
if metadata['versionState'] == 'RELEASED'
211+
else 'draft'
212+
)
207213
self._metadata[latest_version] = metadata
208214

209215
return metadata
@@ -214,8 +220,8 @@ def update_metadata(self, metadata):
214220
215221
:param dict metadata: json retrieved from `get_version_metadata`
216222
"""
217-
url = 'https://{0}/api/datasets/{1}/versions/:draft'.format(
218-
self.connection.host,
223+
url = '{0}/datasets/{1}/versions/:draft'.format(
224+
self.connection.native_base_url,
219225
self.id,
220226
)
221227
resp = requests.put(

dataverse/dataverse.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ def get_contents(self, refresh=False):
5151
if not refresh and self._contents_json:
5252
return self._contents_json
5353

54-
content_uri = 'https://{0}/api/dataverses/{1}/contents'.format(
55-
self.connection.host, self.alias
54+
content_uri = '{0}/dataverses/{1}/contents'.format(
55+
self.connection.native_base_url, self.alias
5656
)
5757
resp = requests.get(
5858
content_uri,
@@ -76,8 +76,8 @@ def get_collection_info(self, refresh=False):
7676
return self._collection_info
7777

7878
def publish(self):
79-
edit_uri = 'https://{0}/dvn/api/data-deposit/v1.1/swordv2/edit/dataverse/{1}'.format(
80-
self.connection.host, self.alias
79+
edit_uri = '{0}/edit/dataverse/{1}'.format(
80+
self.connection.sword_base_url, self.alias
8181
)
8282
resp = requests.post(
8383
edit_uri,

dataverse/exceptions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import absolute_import
22

3+
34
class DataverseError(Exception):
45
"""Base exception class for Dataverse-related error."""
56
pass

dataverse/file.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ def __init__(self, dataset, name, file_id=None):
99
self.name = sanitize(name)
1010
self.id = file_id
1111

12-
self.download_url = 'http://{0}/api/access/datafile/{1}'.format(
13-
dataset.connection.host, self.id
12+
self.download_url = '{0}/access/datafile/{1}'.format(
13+
dataset.connection.native_base_url, self.id
1414
)
15-
self.edit_media_uri = 'https://{0}/dvn/api/data-deposit/v1.1/swordv2/edit-media/file/{1}'.format(
16-
dataset.connection.host, self.id
15+
edit_media_base = '{0}/edit-media/file/{1}'
16+
self.edit_media_uri = edit_media_base.format(
17+
dataset.connection.sword_base_url, self.id
1718
)
1819

1920
@classmethod
2021
def from_json(cls, dataset, json):
2122
name = json['datafile']['name']
2223
file_id = json['datafile']['id']
23-
return cls(dataset, name, file_id)
24+
return cls(dataset, name, file_id)

dataverse/settings/defaults.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import os
44

55
TEST_HOST = 'apitest.dataverse.org'
6-
TEST_TOKEN = 'changeme'
76

87
HERE = os.path.dirname(os.path.abspath(__file__))
98
BASE_PATH = os.path.abspath(os.path.join(HERE, os.pardir))

dataverse/test/test_dataverse.py

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
import uuid
66
import httpretty
7+
import requests
78

89
from dataverse.connection import Connection
910
from dataverse.dataset import Dataset
10-
from dataverse.settings import TEST_HOST, TEST_TOKEN
11+
from dataverse.settings import TEST_HOST
1112
from dataverse.test.config import PICS_OF_CATS_DATASET, ATOM_DATASET, EXAMPLE_FILES
1213
from dataverse import exceptions
1314
from dataverse import utils
@@ -16,6 +17,44 @@
1617
logging.basicConfig(level=logging.ERROR)
1718

1819

20+
class DataverseServerTestBase(object):
21+
"""Create a temporary user on `TEST_SERVER` for testing purposes.
22+
23+
This attaches `username`, `password`, and `token` to the class.
24+
"""
25+
26+
@classmethod
27+
def setup_class(cls):
28+
"""Create a temporary user"""
29+
cls.username = str(uuid.uuid1())
30+
cls.password = 'p4ssw0rd'
31+
key = 'burrito' # hardcoded on test servers
32+
user_url = 'https://{0}/api/builtin-users?key={1}&password={2}'.format(
33+
TEST_HOST, key, cls.password,
34+
)
35+
user_json = {
36+
'email': '{0}@gmail.com'.format(cls.username),
37+
'firstName': 'Namey',
38+
'lastName': 'Namington',
39+
'userName': cls.username,
40+
}
41+
42+
resp = requests.post(user_url, json=user_json)
43+
cls.token = resp.json()['data']['apiToken']
44+
45+
@classmethod
46+
def teardown_class(cls):
47+
"""Delete the temporary user.
48+
49+
Note that this will fail if the user has any non-deleted content.
50+
"""
51+
delete_url = 'https://{0}/api/admin/authenticatedUsers/{1}/'.format(
52+
TEST_HOST, cls.username,
53+
)
54+
resp = requests.delete(delete_url)
55+
assert resp.status_code == 200
56+
57+
1958
class TestUtils(object):
2059

2160
def test_get_element(self):
@@ -64,13 +103,13 @@ def test_format_term_replace(self):
64103
assert formatted_term == '{http://purl.org/dc/terms/}identifier'
65104

66105

67-
class TestConnection(object):
106+
class TestConnection(DataverseServerTestBase):
68107

69108
def test_connect(self):
70-
connection = Connection(TEST_HOST, TEST_TOKEN)
109+
connection = Connection(TEST_HOST, self.token)
71110

72111
assert connection.host == TEST_HOST
73-
assert connection.token == TEST_TOKEN
112+
assert connection.token == self.token
74113
assert connection._service_document
75114

76115
def test_connect_unauthorized(self):
@@ -81,15 +120,17 @@ def test_connect_unauthorized(self):
81120
def test_connect_unknown_failure(self):
82121
httpretty.register_uri(
83122
httpretty.GET,
84-
'https://{host}/dvn/api/data-deposit/v1.1/swordv2/service-document'.format(host=TEST_HOST),
123+
'https://{host}/dvn/api/data-deposit/v1.1/swordv2/service-document'.format(
124+
host=TEST_HOST
125+
),
85126
status=400,
86127
)
87128

88129
with pytest.raises(exceptions.ConnectionError):
89-
Connection(TEST_HOST, TEST_TOKEN)
130+
Connection(TEST_HOST, self.token)
90131

91132
def test_create_dataverse(self):
92-
connection = Connection(TEST_HOST, TEST_TOKEN)
133+
connection = Connection(TEST_HOST, self.token)
93134
alias = str(uuid.uuid1()) # must be unique
94135
connection.create_dataverse(
95136
alias,
@@ -105,7 +146,7 @@ def test_create_dataverse(self):
105146
connection.delete_dataverse(dataverse)
106147

107148
def test_delete_dataverse(self):
108-
connection = Connection(TEST_HOST, TEST_TOKEN)
149+
connection = Connection(TEST_HOST, self.token)
109150
alias = str(uuid.uuid1()) # must be unique
110151
dataverse = connection.create_dataverse(
111152
alias,
@@ -119,7 +160,7 @@ def test_delete_dataverse(self):
119160
assert dataverse is None
120161

121162
def test_get_dataverses(self):
122-
connection = Connection(TEST_HOST, TEST_TOKEN)
163+
connection = Connection(TEST_HOST, self.token)
123164
original_dataverses = connection.get_dataverses()
124165
assert isinstance(original_dataverses, list)
125166

@@ -142,7 +183,7 @@ def test_get_dataverses(self):
142183
assert [dv.alias for dv in current_dataverses] == [dv.alias for dv in original_dataverses]
143184

144185
def test_get_dataverse(self):
145-
connection = Connection(TEST_HOST, TEST_TOKEN)
186+
connection = Connection(TEST_HOST, self.token)
146187
alias = str(uuid.uuid1()) # must be unique
147188
assert connection.get_dataverse(alias) is None
148189

@@ -190,15 +231,18 @@ def test_init_from_xml(self):
190231
tag='rights'
191232
).text
192233
assert title == 'Roasting at Home'
193-
assert publisher == 'Creative Commons CC-BY 3.0 (unported) http://creativecommons.org/licenses/by/3.0/'
234+
assert publisher == 'Creative Commons CC-BY 3.0 (unported) ' \
235+
'http://creativecommons.org/licenses/by/3.0/'
194236

195237

196-
class TestDatasetOperations(object):
238+
class TestDatasetOperations(DataverseServerTestBase):
197239

198240
@classmethod
199241
def setup_class(cls):
242+
super(TestDatasetOperations, cls).setup_class()
243+
200244
print('Connecting to Dataverse host at {0}'.format(TEST_HOST))
201-
cls.connection = Connection(TEST_HOST, TEST_TOKEN)
245+
cls.connection = Connection(TEST_HOST, cls.token)
202246

203247
print('Creating test Dataverse')
204248
cls.alias = str(uuid.uuid1())
@@ -212,6 +256,7 @@ def setup_class(cls):
212256

213257
@classmethod
214258
def teardown_class(cls):
259+
super(TestDatasetOperations, cls).setup_class()
215260

216261
print('Removing test Dataverse')
217262
cls.connection.delete_dataverse(cls.dataverse)

readme.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ information:
3838

3939
```python
4040
TEST_HOST = 'apitest.dataverse.org' # or 'dataverse-demo.iq.harvard.edu'
41-
TEST_TOKEN = '' # Token can be generated at {host}/account/apitoken
4241
```
4342

4443
Do not commit this file.
@@ -51,4 +50,8 @@ To run tests:
5150

5251
Or, to run a specific test:
5352

54-
$ py.test dataverse/test/test_dataverse.py::TestClassName::test_method_name
53+
$ py.test dataverse/test/test_dataverse.py::TestClassName::test_method_name
54+
55+
To check for style:
56+
57+
$ flake8 .

0 commit comments

Comments
 (0)