Skip to content

Commit

Permalink
[#2037] Cherry-pick functional test for dataset creation
Browse files Browse the repository at this point in the history
Otherwise the code for new resource creation on the controllers was not
tested.
  • Loading branch information
amercader committed Mar 3, 2015
1 parent c40c171 commit e27d378
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 0 deletions.
46 changes: 46 additions & 0 deletions ckan/new_tests/controllers/test_package.py
@@ -0,0 +1,46 @@
from nose.tools import assert_equal, assert_true

from routes import url_for

import ckan.model as model

import ckan.new_tests.helpers as helpers
import ckan.new_tests.factories as factories


webtest_submit = helpers.webtest_submit
submit_and_follow = helpers.submit_and_follow


def _get_package_new_page(app):
user = factories.User()
env = {'REMOTE_USER': user['name'].encode('ascii')}
response = app.get(
url=url_for(controller='package', action='new'),
extra_environ=env,
)
return env, response


class TestPackageControllerNew(helpers.FunctionalTestBase):

def test_complete_package_with_one_resource(self):
app = self._get_test_app()
env, response = _get_package_new_page(app)
form = response.forms[1]
form['name'] = u'complete-package-with-one-resource'

response = submit_and_follow(app, form, env, 'save')
form = response.forms[1]
form['url'] = u'http://example.com/resource'

response = submit_and_follow(app, form, env, 'save', 'go-metadata')

form = response.forms[1]
form['version'] = '2.0'
response = submit_and_follow(app, form, env, 'save', 'finish')

pkg = model.Package.by_name(u'complete-package-with-one-resource')
assert_equal(pkg.resources[0].url, u'http://example.com/resource')
assert_equal(pkg.version, '2.0')
assert_equal(pkg.state, 'active')
134 changes: 134 additions & 0 deletions ckan/new_tests/helpers.py
Expand Up @@ -21,6 +21,7 @@
from pylons import config
import nose.tools

import ckan.lib.search as search
import ckan.config.middleware
import ckan.model as model
import ckan.logic as logic
Expand Down Expand Up @@ -120,6 +121,138 @@ def call_auth(auth_name, context, **kwargs):
return logic.check_access(auth_name, context, data_dict=kwargs)


def _get_test_app():
'''Return a webtest.TestApp for CKAN, with legacy templates disabled.
For functional tests that need to request CKAN pages or post to the API.
Unit tests shouldn't need this.
'''
config['ckan.legacy_templates'] = False
app = ckan.config.middleware.make_app(config['global_conf'], **config)
app = webtest.TestApp(app)
return app


class FunctionalTestBase(object):
'''A base class for functional test classes to inherit from.
Allows configuration changes by overriding _apply_config_changes and
resetting the CKAN config after your test class has run. It creates a
webtest.TestApp at self.app for your class to use to make HTTP requests
to the CKAN web UI or API.
If you're overriding methods that this class provides, like setup_class()
and teardown_class(), make sure to use super() to call this class's methods
at the top of yours!
'''
@classmethod
def _get_test_app(cls): # leading _ because nose is terrible
# FIXME: remove this method and switch to using helpers.get_test_app
# in each test once the old functional tests are fixed or removed
if not hasattr(cls, '_test_app'):
cls._test_app = _get_test_app()
return cls._test_app

@classmethod
def setup_class(cls):
# Make a copy of the Pylons config, so we can restore it in teardown.
cls._original_config = dict(config)
cls._apply_config_changes(config)
cls._get_test_app()

@classmethod
def _apply_config_changes(cls, cfg):
pass

def setup(self):
'''Reset the database and clear the search indexes.'''
reset_db()
search.clear()

@classmethod
def teardown_class(cls):
# Restore the Pylons config to its original values, in case any tests
# changed any config settings.
config.clear()
config.update(cls._original_config)


def submit_and_follow(app, form, extra_environ, name=None,
value=None, **args):
'''
Call webtest_submit with name/value passed expecting a redirect
and return the response from following that redirect.
'''
response = webtest_submit(form, name, value=value, status=302,
extra_environ=extra_environ, **args)
return app.get(url=response.headers['Location'],
extra_environ=extra_environ)


# FIXME: remove webtest_* functions below when we upgrade webtest

def webtest_submit(form, name=None, index=None, value=None, **args):
'''
backported version of webtest.Form.submit that actually works
for submitting with different submit buttons.
We're stuck on an old version of webtest because we're stuck
on an old version of webob because we're stuck on an old version
of Pylons. This prolongs our suffering, but on the bright side
it lets us have functional tests that work.
'''
fields = webtest_submit_fields(form, name, index=index, submit_value=value)
if form.method.upper() != "GET":
args.setdefault("content_type", form.enctype)
return form.response.goto(form.action, method=form.method,
params=fields, **args)


def webtest_submit_fields(form, name=None, index=None, submit_value=None):
'''
backported version of webtest.Form.submit_fields that actually works
for submitting with different submit buttons.
'''
from webtest.app import File
submit = []
# Use another name here so we can keep function param the same for BWC.
submit_name = name
if index is not None and submit_value is not None:
raise ValueError("Can't specify both submit_value and index.")

# If no particular button was selected, use the first one
if index is None and submit_value is None:
index = 0

# This counts all fields with the submit name not just submit fields.
current_index = 0
for name, field in form.field_order:
if name is None: # pragma: no cover
continue
if submit_name is not None and name == submit_name:
if index is not None and current_index == index:
submit.append((name, field.value_if_submitted()))
if submit_value is not None and \
field.value_if_submitted() == submit_value:
submit.append((name, field.value_if_submitted()))
current_index += 1
else:
value = field.value
if value is None:
continue
if isinstance(field, File):
submit.append((name, field))
continue
if isinstance(value, list):
for item in value:
submit.append((name, item))
else:
submit.append((name, value))
return submit


def change_config(key, value):
'''Decorator to temporarily changes Pylons' config to a new value
Expand Down Expand Up @@ -154,3 +287,4 @@ def wrapper(*args, **kwargs):
return return_value
return nose.tools.make_decorator(func)(wrapper)
return decorator

0 comments on commit e27d378

Please sign in to comment.