Skip to content

Commit

Permalink
Add test for successful publish, fix publish url
Browse files Browse the repository at this point in the history
  • Loading branch information
Fak3 committed Oct 25, 2016
1 parent fe080cb commit d480a2a
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 46 deletions.
1 change: 1 addition & 0 deletions dpm/client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .validate import validate
39 changes: 39 additions & 0 deletions dpm/client/validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
from __future__ import unicode_literals

import datapackage
import sys
from os.path import exists


def validate():
"""
Validate datapackage in the current dir. Print validation errors if found and
then exit. Return datapackage if valid.
:return:
DataPackage -- valid DataPackage instance
"""
if not exists('datapackage.json'):
print('Current directory is not a datapackage: datapackage.json not found.')
sys.exit(1)

try:
dp = datapackage.DataPackage('datapackage.json')
except:
print('datapackage.json is malformed')
sys.exit(1)

try:
dp.validate()
except datapackage.exceptions.ValidationError:
for error in dp.iter_errors():
# TODO: printing error looks very noisy on output, maybe try make it look nice.
print(error)
sys.exit(1)

return dp
41 changes: 13 additions & 28 deletions dpm/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from requests.exceptions import ConnectionError
from .runtime import credsfile, configfile
from . import __version__
from . import client


# Disable click warning. We are trying to be python3-compatible
Expand Down Expand Up @@ -72,47 +73,31 @@ def validate():
"""
Validate datapackage in the current dir. Print validation errors if found.
"""
if not exists('datapackage.json'):
print('Current directory is not a datapackage: datapackage.json not found.')
sys.exit(1)

try:
dp = datapackage.DataPackage('datapackage.json')
except:
print('datapackage.json is malformed')
sys.exit(1)

try:
dp.validate()
except datapackage.exceptions.ValidationError:
for error in dp.iter_errors():
# TODO: printing error looks very noisy on output, maybe try make it look nice.
print(error)
sys.exit(1)

client.validate()
print('datapackage.json is valid')
return dp


@cli.command()
@click.option('--username')
@click.option('--password')
@click.option('--server')
@click.option('--publisher', prompt=True)
@click.pass_context
def publish(ctx, username, password, server):
def publish(ctx, username, password, server, publisher):
"""
Publish datapackage to the registry server.
"""
dp = client.validate()

if not (username or password):
print('Please launch `dpm configure` first.')
sys.exit(1)
dp = ctx.invoke(validate)
#credentials = get_credentials() # TODO

try:
response = requests.post(
'%s/api/v1/package' % server,
json=dp.to_dict(),
response = requests.put(
'%s/api/package/%s/%s' % (server, publisher, dp.descriptor['name']),
json=dp.descriptor,
allow_redirects=True)
except (OSError, IOError, ConnectionError) as e:
# NOTE: This handling currently does not distinguish various local
Expand All @@ -134,10 +119,10 @@ def publish(ctx, username, password, server):
print('Original error was: %s' % repr(e))
print('Invalid JSON response from server')
sys.exit(1)
if jsonresponse:
if jsonresponse.get('error_code') == 'DP_INVALID':
print('datapackage.json is invalid')
sys.exit(1)

if response.status_code == 400:
print(jsonresponse['message'])
sys.exit(1)
print(response.status_code)

print('publish ok')
Expand Down
9 changes: 3 additions & 6 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def _post_teardown(self):

class BaseCliTestCase(SimpleTestCase):
mock_requests = True # Flag if the testcase should mock out requests library.
isolate = True # Falg if the test should run in isolated environment.
isolate = True # Flag if the test should run in isolated environment.

def _pre_setup(self):
# Use Mocket to prevent any real network access from tests
Expand All @@ -61,22 +61,19 @@ def _pre_setup(self):
if self.mock_requests:
responses.start()

# Start with empty config by default
#patch('dpm.main.ConfigObj', lambda *a: {}).start()
# Start with default config
self.config = {
'username': 'user',
'pasword': 'password',
}
patch('dpm.main.ConfigObj', lambda *a: self.config).start()
#self.config.update(
#server_url='https://example.com'
#)

self.runner = CliRunner()

def _post_teardown(self):
""" Disable all mocks """
if self.mock_requests:
responses.reset()
responses.stop()
# TODO: Mocket.disable() sometimes makes tests hang.
#Mocket.disable()
Expand Down
9 changes: 4 additions & 5 deletions tests/test_publish_connerror.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ def setUp(self):
{ "name": "some-resource", "path": "./data/some_data.csv", }
]
})
patch('dpm.main.datapackage', DataPackage=lambda *a: valid_dp).start()
patch('dpm.main.exists', lambda *a: True).start()
patch('dpm.main.client', validate=lambda *a: valid_dp).start()

# AND valid credentials
patch('dpm.main.get_credentials', lambda *a: 'fake creds').start()
Expand All @@ -36,7 +35,7 @@ def test_connerror_oserror(self):
# GIVEN socket that throws OSError
with patch("socket.socket.connect", side_effect=OSError) as mocksock:
# WHEN dpm publish is invoked
result = self.invoke(cli, ['publish'])
result = self.invoke(cli, ['publish', '--publisher', 'testpub'])

# THEN socket.connect should be called once with server address
mocksock.assert_called_once_with(('example.com', 443))
Expand All @@ -49,7 +48,7 @@ def test_connerror_ioerror(self):
# GIVEN socket that throws IOError
with patch("socket.socket.connect", side_effect=IOError) as mocksock:
# WHEN dpm publish is invoked
result = self.invoke(cli, ['publish'])
result = self.invoke(cli, ['publish', '--publisher', 'testpub'])

# THEN socket.connect should be called once with server address
mocksock.assert_called_once_with(('example.com', 443))
Expand All @@ -63,7 +62,7 @@ def test_connerror_typeerror(self):
with patch("socket.socket.connect", side_effect=TypeError) as mocksock:
# WHEN dpm publish is invoked
try:
result = self.invoke(cli, ['publish'])
result = self.invoke(cli, ['publish', '--publisher', 'testpub'])
except Exception as e:
result = e

Expand Down
13 changes: 6 additions & 7 deletions tests/test_publish_invalid.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,27 @@ class PublishInvalidTest(BaseCliTestCase):
def setUp(self):
# GIVEN datapackage that can be treated as valid by the dpm
valid_dp = datapackage.DataPackage({
"name": "some-name",
"name": "some-datapackage",
"resources": [
{ "name": "some-resource", "path": "./data/some_data.csv", }
]
})
patch('dpm.main.datapackage', DataPackage=lambda *a: valid_dp).start()
patch('dpm.main.exists', lambda *a: True).start()
patch('dpm.main.client', validate=lambda *a: valid_dp).start()

# AND valid credentials
patch('dpm.main.get_credentials', lambda *a: 'fake creds').start()

def test_publish_invalid(self):
# GIVEN the server that rejects datapackage as invalid
responses.add(
responses.POST, 'https://example.com/api/v1/package',
json={'error': 'invalid datapackage json', 'error_code': 'DP_INVALID'},
responses.PUT, 'https://example.com/api/package/testpub/some-datapackage',
json={'message': 'invalid datapackage json'},
status=400)

# WHEN `dpm publish` is invoked
result = self.invoke(cli, ['publish'])
result = self.invoke(cli, ['publish', '--publisher', 'testpub'])

# THEN exit code should be 1
self.assertEqual(result.exit_code, 1)
# AND 'datapackage.json is invalid' should be printed to stdout
self.assertTrue('datapackage.json is invalid' in result.output)
self.assertTrue('invalid datapackage json' in result.output)
47 changes: 47 additions & 0 deletions tests/test_publish_success.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
from __future__ import unicode_literals

import datapackage
import responses
from mock import patch

from dpm.main import cli
from .base import BaseCliTestCase


class PublishSuccessTest(BaseCliTestCase):
"""
When user publishes valid datapackage, and server accepts it, dpm should
report sucess.
"""

def setUp(self):
# GIVEN datapackage that can be treated as valid by the dpm
valid_dp = datapackage.DataPackage({
"name": "some-datapackage",
"resources": [
{ "name": "some-resource", "path": "./data/some_data.csv", }
]
})
patch('dpm.main.client', validate=lambda *a: valid_dp).start()

# AND valid credentials
patch('dpm.main.get_credentials', lambda *a: 'fake creds').start()

def test_publish_success(self):
# GIVEN the server that accepts datapackage
responses.add(
responses.PUT, 'https://example.com/api/package/testpub/some-datapackage',
json={'message': 'OK'},
status=200)

# WHEN `dpm publish` is invoked
result = self.invoke(cli, ['publish', '--publisher', 'testpub'])

# THEN exit code should be 0
self.assertEqual(result.exit_code, 0)
# AND 'publish OK' should be printed to stdout
self.assertTrue('publish ok' in result.output)

0 comments on commit d480a2a

Please sign in to comment.