Django 1.8 support / Project revamp #13
46 changed files with 442 additions and 1224 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,3 +10,4 @@ dist/
|
||||||
.project
|
.project
|
||||||
.pydevproject
|
.pydevproject
|
||||||
build/
|
build/
|
||||||
|
*.sqlite3
|
||||||
|
|
16
Makefile
16
Makefile
|
@ -3,11 +3,17 @@ setup: deps db
|
||||||
deps:
|
deps:
|
||||||
@pip install -r requirements.txt
|
@pip install -r requirements.txt
|
||||||
|
|
||||||
pyvows: db
|
sandbox_run:
|
||||||
@env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. pyvows -c -l django_pyvows --profile-threshold 95 vows/
|
@env PYTHONPATH=sandbox:.:$$PYTHONPATH python sandbox/manage.py runserver
|
||||||
|
|
||||||
ci_test:
|
sandbox_shell:
|
||||||
@env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. python vows/sandbox/manage.py syncdb && pyvows --no_color --cover --cover_package=django_pyvows --cover_threshold=100 -r django_pyvows.coverage.xml -x vows/
|
@env PYTHONPATH=sandbox:.:$$PYTHONPATH python sandbox/manage.py shell
|
||||||
|
|
||||||
|
pyvows:
|
||||||
|
@env PYTHONPATH=sandbox:.:$$PYTHONPATH pyvows -c -l django_pyvows --profile-threshold 95 vows/
|
||||||
|
|
||||||
|
ci_test: db
|
||||||
|
@env PYTHONPATH=sandbox:.:$$PYTHONPATH pyvows -c -l django_pyvows --profile-threshold 95 -r django_pyvows.coverage.xml vows/
|
||||||
|
|
||||||
db:
|
db:
|
||||||
@env PYTHONPATH=$$PYTHONPATH:. python vows/sandbox/manage.py syncdb
|
@env PYTHONPATH=$$PYTHONPATH:. python sandbox/manage.py syncdb --noinput
|
||||||
|
|
64
README.md
64
README.md
|
@ -1,58 +1,52 @@
|
||||||
Django-Pyvows
|
# Django-PyVows
|
||||||
=============
|
|
||||||
|
|
||||||
|
This project is an extension of pyVows to test [Django](https://www.djangoproject.com/) projects. It enables usage of core Django testing tools in a way that is in sync with pyVows workflow mindset.
|
||||||
|
|
||||||
Pyvows
|
PyVows is a BDD (Behaviour Driven Development) inspired by Vows for node.js
|
||||||
-------
|
|
||||||
|
|
||||||
pyvows is a BDD (Behaviour Driven Development) inspired by Vows for node.js
|
More documentation about pyVows can be found at [the project homepage](http://pyvows.org) or for more updated usage check the project [tests itself](https://github.com/heynemann/pyvows/tree/master/tests).
|
||||||
|
|
||||||
More documentation about pyvows can be found at the project homepage
|
Django-PyVows is in sync with the latest Django developments and supports Django 1.8.
|
||||||
|
|
||||||
http://pyvows.org
|
## Usage
|
||||||
|
|
||||||
Django-Pyvows
|
There is no need to modify your project to use Django-PyVows. You only have to define where is your project settings module and start calling your project urls in your tests.
|
||||||
--------------
|
|
||||||
|
|
||||||
This project contains extensions to test Django projects under pyVows.
|
|
||||||
|
|
||||||
Using Django-Pyvows
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
There is no need to modify your project to use Django-PyVows. You only have to create the vows
|
|
||||||
as you usually would, start the server and call your project urls:
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from pyvows import Vows, expect
|
from pyvows import Vows, expect
|
||||||
|
|
||||||
from django_pyvows.context import DjangoHTTPContext
|
from django_pyvows.context import DjangoContext
|
||||||
|
|
||||||
@Vows.batch
|
@Vows.batch
|
||||||
class ContextTest(DjangoHTTPContext):
|
class SimpleTestVows(DjangoContext):
|
||||||
|
|
||||||
def setup(self):
|
def settings_module(self):
|
||||||
self.start_server()
|
return 'yourproject.settings'
|
||||||
|
|
||||||
def topic(self):
|
def topic(self):
|
||||||
return self.get('/mygreaturl/')
|
return self.get('/mygreaturl/')
|
||||||
|
|
||||||
def should_be_a_success(self, topic):
|
def should_be_a_success(self, topic):
|
||||||
expect(topic.getcode()).to_equal(200)
|
expect(topic.status_code).to_equal(200)
|
||||||
|
|
||||||
def should_return_the_correct_response_type(self, topic):
|
def should_return_the_correct_response(self, topic):
|
||||||
expect(topic.headers.type).to_equal("text/html")
|
expect(topic).contains("Welcome!")
|
||||||
```
|
```
|
||||||
|
|
||||||
To work you only need to override the `get_settings` method from DjangoHTTPContext to
|
The default `settings_module` is `settings` so you should define it accordly based on your `PYTHONPATH`.
|
||||||
return the path of your settings module. The default `get_settings` returns `"settings"`.
|
|
||||||
|
|
||||||
More info: https://github.com/rafaelcaricio/django-pyvows/wiki
|
### HTTP Client
|
||||||
|
|
||||||
External links
|
We support `django.test.Client`, the methods `DjangoContext.get` and `DjangoContext.post` are actually simple wrappers around it so [the usage](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#the-test-client) is the same. The test client is also available in the `DjangoContext` instance as `self.client`.
|
||||||
--------------
|
|
||||||
- Asynchronous Testing with Django and PyVows
|
### Assertions
|
||||||
- http://www.realpython.com/blog/python/asynchronous-testing-with-django-and-pyvows/
|
|
||||||
- Unit Testing with pyVows and Django
|
The available assertions in Django-PyVows are the same as in `django.test.SimpleTestCase` they were adapted to the context of BDD and PyVows.
|
||||||
- http://www.realpython.com/blog/python/unit-testing-with-pyvows-and-django/
|
|
||||||
- Integration testing with pyVows and Django
|
- `contains`: reflects the `django.test.SimpleTestCase.assertContains`. Check usage at: [https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertContains](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertContains)
|
||||||
- http://www.realpython.com/blog/python/integration-testing-with-pyvows-and-django/
|
- `redirects_to`: reflects the `django.test.SimpleTestCase.assertRedirects`. Check usage at: [https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects)
|
||||||
|
- `with_form_error`: reflects the `django.test.SimpleTestCase.assertFormError`. Check usage at: [https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertFormError](https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.SimpleTestCase.assertFormError)
|
||||||
|
|
||||||
|
### Settings Override
|
||||||
|
|
||||||
|
TODO
|
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# django-pyvows extensions
|
# django-pyvows extensions
|
||||||
|
@ -8,4 +7,5 @@
|
||||||
# http://www.opensource.org/licenses/mit-license
|
# http://www.opensource.org/licenses/mit-license
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
from context import DjangoContext, DjangoHTTPContext
|
from context import DjangoContext # NOQA
|
||||||
|
from assertions import * # NOQA
|
||||||
|
|
33
django_pyvows/assertions.py
Normal file
33
django_pyvows/assertions.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# django-pyvows extensions
|
||||||
|
# https://github.com/rafaelcaricio/django-pyvows
|
||||||
|
|
||||||
|
# Licensed under the MIT license:
|
||||||
|
# http://www.opensource.org/licenses/mit-license
|
||||||
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
|
from django.test import SimpleTestCase
|
||||||
|
from pyvows import Vows
|
||||||
|
|
||||||
|
|
||||||
|
class _Dummy(SimpleTestCase):
|
||||||
|
def nop():
|
||||||
|
pass
|
||||||
|
|
||||||
|
dummy_testcase = _Dummy('nop')
|
||||||
|
|
||||||
|
|
||||||
|
@Vows.assertion
|
||||||
|
def redirects_to(*args, **kwargs):
|
||||||
|
return dummy_testcase.assertRedirects(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@Vows.assertion
|
||||||
|
def contains(*args, **kwargs):
|
||||||
|
return dummy_testcase.assertContains(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@Vows.assertion
|
||||||
|
def with_form_error(*args, **kwargs):
|
||||||
|
return dummy_testcase.assertFormError(*args, **kwargs)
|
|
@ -1,13 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from urls import *
|
|
||||||
from models import *
|
|
||||||
from templates import *
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from pyvows import Vows
|
|
||||||
|
|
||||||
class Model(object):
|
|
||||||
def __init__(self, context, model):
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
self.context = context
|
|
||||||
if isinstance(model, models.Model):
|
|
||||||
model = model.__class__
|
|
||||||
self.model = model
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
return self.model(*args, **kwargs)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def admin(self):
|
|
||||||
from django.contrib import admin
|
|
||||||
if self.model not in admin.site._registry:
|
|
||||||
raise admin.sites.NotRegistered('The model %s is not registered' % self.model.__name__)
|
|
||||||
return admin.site._registry[self.model]
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_be_in_admin(topic):
|
|
||||||
from django.contrib import admin
|
|
||||||
try:
|
|
||||||
assert topic.admin
|
|
||||||
except admin.sites.NotRegistered:
|
|
||||||
assert False, "The model %s isn't registered in admin." % topic.model.__name__
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_have_field(topic, field_name, field_class=None, **kwargs):
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
if isinstance(topic, Model):
|
|
||||||
topic = topic.model
|
|
||||||
|
|
||||||
if isinstance(topic, models.Model):
|
|
||||||
topic = topic.__class__
|
|
||||||
|
|
||||||
if not field_class:
|
|
||||||
field_class = models.Field
|
|
||||||
|
|
||||||
field = topic._meta.get_field(field_name)
|
|
||||||
assert isinstance(field, field_class), "The '%s.%s' is not an instance of '%s'" % (topic.__name__, field_name, field_class.__name__)
|
|
||||||
if kwargs:
|
|
||||||
for attr, value in kwargs.items():
|
|
||||||
field_value = getattr(field, attr)
|
|
||||||
assert field_value == value, "The field option '%s' should be equal to '%s', but it's equal to '%s'" % (attr, value, field_value)
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_be_cruddable(topic, defaults={}):
|
|
||||||
import django.db.models.fields as fields
|
|
||||||
instance = __create_or_update_instance(topic, None, defaults)
|
|
||||||
|
|
||||||
assert instance, "An instance could not be created for model %s" % topic.model.__name__
|
|
||||||
|
|
||||||
retrieved = topic.model.objects.get(id=instance.id)
|
|
||||||
assert retrieved.id == instance.id, "An instance could not be retrieved for model %s with id %d" % (topic.model.__name__, instance.id)
|
|
||||||
|
|
||||||
for key, value in defaults.iteritems():
|
|
||||||
assert value == getattr(retrieved, key), "The default specified value of '%s' should have been set in the '%s' property of the instance but it was not" % (value, key)
|
|
||||||
|
|
||||||
updated = __create_or_update_instance(topic, retrieved, defaults)
|
|
||||||
|
|
||||||
for field, value in topic.model._meta._field_cache:
|
|
||||||
if field.__class__ == fields.AutoField:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if field.name in defaults:
|
|
||||||
continue
|
|
||||||
|
|
||||||
assert getattr(updated, field.name) != getattr(instance, field.name), "The instance should have been updated but the field %s is the same in both the original instance and the updated one (%s)." % (field.name, getattr(updated, field.name))
|
|
||||||
|
|
||||||
instance.delete()
|
|
||||||
object_count = topic.model.objects.count()
|
|
||||||
assert object_count == 0, "Object should have been deleted, but it wasn't (count: %d)" % object_count
|
|
||||||
|
|
||||||
def __create_or_update_instance(topic, instance, defaults):
|
|
||||||
import django.db.models.fields as fields
|
|
||||||
arguments = {}
|
|
||||||
for field, value in topic.model._meta._field_cache:
|
|
||||||
if field.__class__ == fields.AutoField:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if field.name in defaults:
|
|
||||||
arguments[field.name] = defaults[field.name]
|
|
||||||
continue
|
|
||||||
|
|
||||||
if field.__class__ == fields.CharField:
|
|
||||||
__add_char_value_for(field, instance, arguments)
|
|
||||||
|
|
||||||
if instance:
|
|
||||||
for key, value in arguments.iteritems():
|
|
||||||
setattr(instance, key, value)
|
|
||||||
|
|
||||||
instance.save()
|
|
||||||
return instance
|
|
||||||
|
|
||||||
return topic.model.objects.create(**arguments)
|
|
||||||
|
|
||||||
def __add_char_value_for(field, instance, arguments):
|
|
||||||
value = "monty python"
|
|
||||||
if instance:
|
|
||||||
value = getattr(instance, field.name) + '2'
|
|
||||||
if field.max_length:
|
|
||||||
if instance:
|
|
||||||
value = value[:len(value) - 2] + '2'
|
|
||||||
value = (value * field.max_length)[:field.max_length]
|
|
||||||
arguments[field.name] = value
|
|
|
@ -1,57 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from lxml.etree import fromstring
|
|
||||||
from lxml.cssselect import CSSSelector
|
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
|
||||||
from django.template.loader import render_to_string
|
|
||||||
|
|
||||||
|
|
||||||
class Template(object):
|
|
||||||
def __init__(self, template_name, context):
|
|
||||||
self.template_name = template_name
|
|
||||||
self.context = context
|
|
||||||
self.doc = None
|
|
||||||
|
|
||||||
def load(self):
|
|
||||||
if self.doc is None:
|
|
||||||
self.doc = fromstring(render_to_string(self.template_name, self.context))
|
|
||||||
return self.doc
|
|
||||||
|
|
||||||
def select_element(self, selector):
|
|
||||||
sel = CSSSelector(selector)
|
|
||||||
return sel(self.load())
|
|
||||||
|
|
||||||
def _to_contain(self, selector):
|
|
||||||
return len(self.select_element(selector)) > 0
|
|
||||||
|
|
||||||
def get_text(self, selector):
|
|
||||||
return "".join((c.text for c in self.select_element(selector)))
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return self.template_name
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_have_contents_of(topic, expected):
|
|
||||||
expect(topic.content).to_be_like(expected)
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_contain(topic, selector):
|
|
||||||
assert isinstance(topic, Template), "Only django_pyvows.Template items can be verified for mapping"
|
|
||||||
assert topic._to_contain(selector), "Expected template(%s) to have an element(%s), but it don't have" % \
|
|
||||||
(unicode(topic), selector)
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def not_to_contain(topic, selector):
|
|
||||||
assert isinstance(topic, Template), "Only django_pyvows.Template items can be verified for mapping"
|
|
||||||
assert not topic._to_contain(selector), "Expected template(%s) to not have an element(%s), but it have" % \
|
|
||||||
(unicode(topic), selector)
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
|
||||||
from django.http import HttpResponse
|
|
||||||
|
|
||||||
|
|
||||||
class Url(object):
|
|
||||||
def __init__(self, context, path):
|
|
||||||
self.context = context
|
|
||||||
self.path = path
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_be_mapped(topic):
|
|
||||||
verify_url_is_mapped_to_method(topic)
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_match_view(topic, view):
|
|
||||||
verify_url_is_mapped_to_method(topic, view, True)
|
|
||||||
|
|
||||||
@Vows.assertion
|
|
||||||
def to_be_http_response(topic):
|
|
||||||
expect(topic).to_be_instance_of(HttpResponse)
|
|
||||||
|
|
||||||
def verify_url_is_mapped_to_method(topic, method=None, assert_method_as_well=False):
|
|
||||||
assert isinstance(topic, Url), "Only django_pyvows.Url items can be verified for mapping"
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
project_urls = settings.ROOT_URLCONF
|
|
||||||
|
|
||||||
urlpatterns = __import__(project_urls).urls.urlpatterns
|
|
||||||
|
|
||||||
found = False
|
|
||||||
matches_method = False
|
|
||||||
for urlpattern in urlpatterns:
|
|
||||||
regex = urlpattern.regex
|
|
||||||
pattern = regex.pattern
|
|
||||||
actual_method = urlpattern.callback
|
|
||||||
|
|
||||||
if topic.path == pattern:
|
|
||||||
found = True
|
|
||||||
if method == actual_method:
|
|
||||||
matches_method = True
|
|
||||||
|
|
||||||
assert found, "Expected url(%s) to be mapped but it wasn't"
|
|
||||||
if assert_method_as_well:
|
|
||||||
assert matches_method, "Expected url(%s) to match method(%s), but it didn't"
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# django-pyvows extensions
|
# django-pyvows extensions
|
||||||
|
@ -9,101 +8,35 @@
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
|
|
||||||
|
import django
|
||||||
from pyvows import Vows
|
from pyvows import Vows
|
||||||
from django.http import HttpRequest
|
|
||||||
|
|
||||||
from django_pyvows import http_helpers
|
from django_pyvows.http_helpers import HttpClientSupport
|
||||||
from django_pyvows.assertions import Url, Model, Template
|
from django_pyvows.settings_helpers import SettingsOverrideSupport
|
||||||
from django_pyvows.server import DjangoServer
|
|
||||||
from django_pyvows.settings_manager import settings_tracker
|
|
||||||
|
|
||||||
DEFAULT_PORT = 3331
|
|
||||||
DEFAULT_HOST = '127.0.0.1'
|
|
||||||
|
|
||||||
class DjangoContext(Vows.Context):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def start_environment(cls, settings_path):
|
|
||||||
if not settings_path:
|
|
||||||
raise RuntimeError('The settings_path argument is required.')
|
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = settings_path
|
|
||||||
settings_tracker.install()
|
|
||||||
|
|
||||||
|
class DjangoContext(Vows.Context, HttpClientSupport, SettingsOverrideSupport):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(DjangoContext, self).__init__(parent)
|
super(DjangoContext, self).__init__(parent)
|
||||||
self.ignore('get_settings', 'template', 'request', 'model', 'url', 'find_in_parent',
|
|
||||||
'start_environment', 'port', 'host', 'get_url', 'get', 'post')
|
|
||||||
|
|
||||||
def setup(self):
|
HttpClientSupport.__init__(self)
|
||||||
DjangoContext.start_environment(self.get_settings())
|
SettingsOverrideSupport.__init__(self)
|
||||||
|
|
||||||
def get_settings(self):
|
self.ignore('setup_environment', 'settings_module')
|
||||||
return os.environ.get('DJANGO_SETTINGS_MODULE', 'settings')
|
|
||||||
|
|
||||||
def url(self, path):
|
DjangoContext.setup_environment(self.settings_module())
|
||||||
return Url(self, path)
|
|
||||||
|
|
||||||
def template(self, template_name, context):
|
def settings_module(self):
|
||||||
return Template(template_name, context)
|
return 'settings'
|
||||||
|
|
||||||
def request(self, **kw):
|
@classmethod
|
||||||
return HttpRequest(**kw)
|
def setup_environment(cls, settings_module):
|
||||||
|
if not settings_module:
|
||||||
|
raise ValueError('The settings_path argument is required.')
|
||||||
|
|
||||||
def model(self, model_class):
|
os.environ.update({'DJANGO_SETTINGS_MODULE': settings_module})
|
||||||
return Model(self, model_class)
|
django.setup()
|
||||||
|
|
||||||
def get(self, path):
|
|
||||||
return http_helpers.get(self.get_url(path))
|
|
||||||
|
|
||||||
def post(self, path, params):
|
|
||||||
return http_helpers.post(self.get_url(path), params)
|
|
||||||
|
|
||||||
def find_in_parent(self, attr_name):
|
|
||||||
ctx = self.parent
|
|
||||||
while ctx:
|
|
||||||
if hasattr(ctx, attr_name):
|
|
||||||
return getattr(ctx, attr_name)
|
|
||||||
ctx = ctx.parent
|
|
||||||
raise ValueError('Host could not be found in the context or any of its parents')
|
|
||||||
|
|
||||||
def get_url(self, path):
|
|
||||||
try:
|
|
||||||
return self.find_in_parent('get_url')(path)
|
|
||||||
except ValueError:
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoHTTPContext(DjangoContext):
|
|
||||||
|
|
||||||
def start_server(self, host=None, port=None, settings={}, threads=1):
|
|
||||||
if not port: port = DEFAULT_PORT
|
|
||||||
if not host: host = DEFAULT_HOST
|
|
||||||
|
|
||||||
self.address = (host, port)
|
|
||||||
self.server = DjangoServer(host, port)
|
|
||||||
self.server.start(settings,threads)
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
super(DjangoHTTPContext, self).__init__(parent)
|
|
||||||
self.ignore('start_server', 'settings')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host(self):
|
|
||||||
if hasattr(self, 'address'):
|
|
||||||
return self.address[0]
|
|
||||||
return self.find_in_parent('host')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def port(self):
|
|
||||||
if hasattr(self, 'address'):
|
|
||||||
return self.address[1]
|
|
||||||
return self.find_in_parent('port')
|
|
||||||
|
|
||||||
def get_url(self, path):
|
|
||||||
if re.match('^https?:\/\/', path):
|
|
||||||
return path
|
|
||||||
return 'http://%s:%d%s' % (self.host, self.port, path)
|
|
||||||
|
|
||||||
|
from django.test.utils import setup_test_environment
|
||||||
|
setup_test_environment()
|
||||||
|
|
|
@ -1,101 +1,27 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import httplib2
|
# django-pyvows extensions
|
||||||
|
# https://github.com/rafaelcaricio/django-pyvows
|
||||||
|
|
||||||
import mimetypes
|
# Licensed under the MIT license:
|
||||||
import mimetools
|
# http://www.opensource.org/licenses/mit-license
|
||||||
import itertools
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
class MultiPartForm(object):
|
|
||||||
"""Accumulate the data to be used when posting a form."""
|
|
||||||
|
|
||||||
|
class HttpClientSupport(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.form_fields = []
|
self._client = None
|
||||||
self.files = []
|
self.ignore('get', 'post')
|
||||||
self.boundary = mimetools.choose_boundary()
|
|
||||||
return
|
|
||||||
|
|
||||||
def get_content_type(self):
|
@property
|
||||||
return 'multipart/form-data; boundary=%s' % self.boundary
|
def client(self):
|
||||||
|
if self._client is None:
|
||||||
|
from django.test.client import Client # Needs to be lazy loaded due settings config
|
||||||
|
self._client = Client()
|
||||||
|
return self._client
|
||||||
|
|
||||||
def add_field(self, name, value):
|
def get(self, *args, **kwargs):
|
||||||
"""Add a simple field to the form data."""
|
return self.client.get(*args, **kwargs)
|
||||||
self.form_fields.append((name, value))
|
|
||||||
return
|
|
||||||
|
|
||||||
def add_file(self, fieldname, filename, fileHandle, mimetype=None):
|
|
||||||
"""Add a file to be uploaded."""
|
|
||||||
body = fileHandle.read()
|
|
||||||
if mimetype is None:
|
|
||||||
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
|
||||||
self.files.append((fieldname, filename, mimetype, body))
|
|
||||||
return
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Return a string representing the form data, including attached files."""
|
|
||||||
# Build a list of lists, each containing "lines" of the
|
|
||||||
# request. Each part is separated by a boundary string.
|
|
||||||
# Once the list is built, return a string where each
|
|
||||||
# line is separated by '\r\n'.
|
|
||||||
parts = []
|
|
||||||
part_boundary = '--' + self.boundary
|
|
||||||
|
|
||||||
# Add the form fields
|
|
||||||
parts.extend(
|
|
||||||
[ part_boundary,
|
|
||||||
'Content-Disposition: form-data; name="%s"' % name,
|
|
||||||
'',
|
|
||||||
value,
|
|
||||||
]
|
|
||||||
for name, value in self.form_fields
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add the files to upload
|
|
||||||
parts.extend(
|
|
||||||
[ part_boundary,
|
|
||||||
'Content-Disposition: file; name="%s"; filename="%s"' % \
|
|
||||||
(field_name, filename),
|
|
||||||
'Content-Type: %s' % content_type,
|
|
||||||
'',
|
|
||||||
body,
|
|
||||||
]
|
|
||||||
for field_name, filename, content_type, body in self.files
|
|
||||||
)
|
|
||||||
|
|
||||||
# Flatten the list and add closing boundary marker,
|
|
||||||
# then return CR+LF separated data
|
|
||||||
flattened = list(itertools.chain(*parts))
|
|
||||||
flattened.append('--' + self.boundary + '--')
|
|
||||||
flattened.append('')
|
|
||||||
return '\r\n'.join(flattened)
|
|
||||||
|
|
||||||
|
|
||||||
def get(url):
|
|
||||||
h = httplib2.Http()
|
|
||||||
resp, content = h.request(url)
|
|
||||||
return resp, content
|
|
||||||
|
|
||||||
def post(url, data):
|
|
||||||
h = httplib2.Http()
|
|
||||||
form = MultiPartForm()
|
|
||||||
|
|
||||||
for field, value in data.iteritems():
|
|
||||||
if hasattr(value, "read"):
|
|
||||||
form.add_file(field, value.name, value)
|
|
||||||
else:
|
|
||||||
form.add_field(field, str(value))
|
|
||||||
|
|
||||||
body = str(form)
|
|
||||||
headers = {
|
|
||||||
'Content-type': form.get_content_type(),
|
|
||||||
'Content-length': str(len(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = h.request(url, 'POST', headers=headers, body=body)
|
|
||||||
except httplib2.HttpLib2Error, err:
|
|
||||||
response = err
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
def post(self, *args, **kwargs):
|
||||||
|
return self.client.post(*args, **kwargs)
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from threading import Thread, current_thread, local
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
from cherrypy import wsgiserver
|
|
||||||
|
|
||||||
from django.core.handlers.wsgi import WSGIHandler
|
|
||||||
|
|
||||||
|
|
||||||
def run_app(host, port, thread_count):
|
|
||||||
server = wsgiserver.CherryPyWSGIServer(
|
|
||||||
(host, port),
|
|
||||||
WSGIHandler(),
|
|
||||||
server_name='tornado-pyvows',
|
|
||||||
numthreads = thread_count
|
|
||||||
)
|
|
||||||
|
|
||||||
my_thread = current_thread()
|
|
||||||
my_thread.server = server
|
|
||||||
|
|
||||||
try:
|
|
||||||
server.start()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
server.stop()
|
|
||||||
|
|
||||||
class DjangoServer(object):
|
|
||||||
|
|
||||||
def __init__(self, host, port):
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
|
|
||||||
def start(self, settings, thread_count=1):
|
|
||||||
self.thr = Thread(target= run_app, args=(self.host, self.port, thread_count))
|
|
||||||
self.thr.daemon = True
|
|
||||||
self.thr.settings = {}
|
|
||||||
for k, v in settings.iteritems():
|
|
||||||
self.thr.settings[k] = v
|
|
||||||
|
|
||||||
self.thr.start()
|
|
||||||
|
|
||||||
while not len(self.thr.server.requests._threads):
|
|
||||||
sleep(0.1)
|
|
||||||
|
|
||||||
for _thread in self.thr.server.requests._threads:
|
|
||||||
_thread.settings = {}
|
|
||||||
for k, v in settings.iteritems():
|
|
||||||
_thread.settings[k] = v
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# django-pyvows extensions
|
# django-pyvows extensions
|
||||||
|
@ -8,11 +7,11 @@
|
||||||
# http://www.opensource.org/licenses/mit-license
|
# http://www.opensource.org/licenses/mit-license
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
from sandbox.main.models import StringModel
|
class SettingsOverrideSupport(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.ignore('settings')
|
||||||
|
|
||||||
class StringModelAdmin(admin.ModelAdmin):
|
def settings(self, **kwargs):
|
||||||
list_display = ('name', )
|
from django.test.utils import override_settings
|
||||||
|
return override_settings(**kwargs)
|
||||||
admin.site.register(StringModel, StringModelAdmin)
|
|
|
@ -1,44 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from threading import current_thread
|
|
||||||
|
|
||||||
class SettingsTracker(object):
|
|
||||||
|
|
||||||
def install(self):
|
|
||||||
actual_import = __builtins__['__import__']
|
|
||||||
if actual_import != self._import:
|
|
||||||
self.real_import = actual_import
|
|
||||||
__builtins__['__import__'] = self._import
|
|
||||||
|
|
||||||
def _import(self, name, globals=None, locals=None, fromlist=[], level=-1):
|
|
||||||
result = apply(self.real_import, (name, globals, locals, fromlist, level))
|
|
||||||
fromlist = (fromlist or [])
|
|
||||||
if name == 'django.conf' and 'settings' in fromlist:
|
|
||||||
if type(result.settings) != VowsSettings:
|
|
||||||
result.settings = VowsSettings(result.settings)
|
|
||||||
elif name == 'django' and 'conf' in fromlist:
|
|
||||||
if type(result.conf.settings) != VowsSettings:
|
|
||||||
result.conf.settings = VowsSettings(result.conf.settings)
|
|
||||||
return result
|
|
||||||
|
|
||||||
class VowsSettings(object):
|
|
||||||
|
|
||||||
def __init__(self, original_settings):
|
|
||||||
self.original_settings = original_settings
|
|
||||||
|
|
||||||
def __getattr__(self, attr_name):
|
|
||||||
thread = current_thread()
|
|
||||||
if hasattr(thread, 'settings'):
|
|
||||||
if attr_name in thread.settings:
|
|
||||||
return thread.settings[attr_name]
|
|
||||||
return getattr(self.original_settings, attr_name)
|
|
||||||
|
|
||||||
settings_tracker = SettingsTracker()
|
|
|
@ -1,4 +1,3 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# django-pyvows extensions
|
# django-pyvows extensions
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
django==1.3.1
|
Django==1.8.3
|
||||||
pyvows
|
pyVows==2.0.6
|
||||||
coverage==3.5.1
|
coverage==3.5.1
|
||||||
httplib2
|
lxml==3.4.4
|
||||||
lxml
|
cssselect==0.9.1
|
||||||
cssselect
|
|
||||||
cherrypy
|
|
||||||
|
|
0
sandbox/main/__init__.py
Normal file
0
sandbox/main/__init__.py
Normal file
9
sandbox/main/admin.py
Normal file
9
sandbox/main/admin.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from models import StringModel
|
||||||
|
|
||||||
|
|
||||||
|
class StringModelAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', )
|
||||||
|
|
||||||
|
admin.site.register(StringModel, StringModelAdmin)
|
5
sandbox/main/forms.py
Normal file
5
sandbox/main/forms.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
|
||||||
|
class NameForm(forms.Form):
|
||||||
|
your_name = forms.CharField(label='Your name', max_length=100, required=True)
|
5
sandbox/main/models.py
Normal file
5
sandbox/main/models.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class StringModel(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
|
@ -1,32 +1,43 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from .forms import NameForm
|
||||||
|
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
return HttpResponse('hello world')
|
return HttpResponse('hello world')
|
||||||
|
|
||||||
|
|
||||||
def say_hello(request):
|
def say_hello(request):
|
||||||
SAY_HELLO_WITHOUT_NAME = getattr(settings, "SAY_HELLO_WITHOUT_NAME", False)
|
SAY_HELLO_WITHOUT_NAME = getattr(settings, "SAY_HELLO_WITHOUT_NAME", False)
|
||||||
if 'name' in request.GET:
|
if 'name' in request.GET:
|
||||||
name = request.GET['name']
|
name = request.GET['name']
|
||||||
elif SAY_HELLO_WITHOUT_NAME:
|
elif SAY_HELLO_WITHOUT_NAME:
|
||||||
name = 'guess'
|
name = 'guest'
|
||||||
else:
|
else:
|
||||||
return HttpResponse("What's your name?")
|
return HttpResponse("What's your name?")
|
||||||
return HttpResponse("Hello, %s!" % name)
|
return HttpResponse("Hello, %s!" % name)
|
||||||
|
|
||||||
|
|
||||||
def post_it(request):
|
def post_it(request):
|
||||||
return HttpResponse(request.POST['value'])
|
return HttpResponse(request.POST['value'])
|
||||||
|
|
||||||
|
|
||||||
def post_file(request):
|
def post_file(request):
|
||||||
return HttpResponse(request.FILES['the_file'].read().strip())
|
return HttpResponse(request.FILES['the_file'].read().strip())
|
||||||
|
|
||||||
|
|
||||||
|
def post_name(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = NameForm(request.POST)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
return HttpResponseRedirect(
|
||||||
|
'/say/?name={}'.format(form.cleaned_data['your_name']))
|
||||||
|
|
||||||
|
else:
|
||||||
|
form = NameForm()
|
||||||
|
|
||||||
|
return render(request, 'name.html', {'form': form})
|
10
sandbox/manage.py
Executable file
10
sandbox/manage.py
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sandbox.settings")
|
||||||
|
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
execute_from_command_line(sys.argv)
|
0
sandbox/sandbox/__init__.py
Normal file
0
sandbox/sandbox/__init__.py
Normal file
95
sandbox/sandbox/settings.py
Normal file
95
sandbox/sandbox/settings.py
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
"""
|
||||||
|
Django settings for sandbox project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 1.8.3.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/1.8/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
|
SECRET_KEY = '+1e*=5h9ri-$#@xmgs*9wrm&@d#li6d9u3e&atmzo5s*6k%_#o'
|
||||||
|
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
|
||||||
|
'main',
|
||||||
|
)
|
||||||
|
|
||||||
|
MIDDLEWARE_CLASSES = (
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
)
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'sandbox.urls'
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [
|
||||||
|
os.path.join(BASE_DIR, "templates"),
|
||||||
|
],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'sandbox.wsgi.application'
|
||||||
|
|
||||||
|
# Database
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
# Custom configs
|
||||||
|
SAY_HELLO_WITHOUT_NAME = False
|
11
sandbox/sandbox/urls.py
Normal file
11
sandbox/sandbox/urls.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from django.conf.urls import url
|
||||||
|
from main.views import home, say_hello, post_it, post_file, post_name
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', home, name='home'),
|
||||||
|
url(r'^say/$', say_hello, name='say_hello'),
|
||||||
|
url(r'^post_it/$', post_it, name='post_it'),
|
||||||
|
url(r'^post_file/$', post_file, name='post_file'),
|
||||||
|
url(r'^post-name/$', post_name, name='post_name'),
|
||||||
|
]
|
16
sandbox/sandbox/wsgi.py
Normal file
16
sandbox/sandbox/wsgi.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
WSGI config for sandbox project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sandbox.settings")
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
5
sandbox/templates/name.html
Normal file
5
sandbox/templates/name.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<form action="/post-name/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Submit" />
|
||||||
|
</form>
|
0
vows/__init__.py
Normal file
0
vows/__init__.py
Normal file
37
vows/assertions_vows.py
Normal file
37
vows/assertions_vows.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# django-pyvows extensions
|
||||||
|
# https://github.com/rafaelcaricio/django-pyvows
|
||||||
|
|
||||||
|
# Licensed under the MIT license:
|
||||||
|
# http://www.opensource.org/licenses/mit-license
|
||||||
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
|
from pyvows import Vows, expect
|
||||||
|
|
||||||
|
from test_config import ConfiguredVowsContext as DjangoContext
|
||||||
|
|
||||||
|
|
||||||
|
@Vows.batch
|
||||||
|
class DjangoAssertionsVows(DjangoContext):
|
||||||
|
|
||||||
|
class RedirectsTo(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.get("/say")
|
||||||
|
|
||||||
|
def should_redirect(self, topic):
|
||||||
|
expect(topic).redirects_to('/say/', status_code=301)
|
||||||
|
|
||||||
|
class Contains(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.get('/say/')
|
||||||
|
|
||||||
|
def should_work(self, topic):
|
||||||
|
expect(topic).contains('name')
|
||||||
|
|
||||||
|
class WithFormError(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.post('/post-name/', {'another_field': 'filled'})
|
||||||
|
|
||||||
|
def should_work(self, topic):
|
||||||
|
expect(topic).with_form_error('form', 'your_name', 'This field is required.')
|
55
vows/client_vows.py
Normal file
55
vows/client_vows.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# django-pyvows extensions
|
||||||
|
# https://github.com/rafaelcaricio/django-pyvows
|
||||||
|
|
||||||
|
# Licensed under the MIT license:
|
||||||
|
# http://www.opensource.org/licenses/mit-license
|
||||||
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
|
from pyvows import Vows, expect
|
||||||
|
|
||||||
|
from test_config import ConfiguredVowsContext as DjangoContext
|
||||||
|
|
||||||
|
|
||||||
|
@Vows.batch
|
||||||
|
class DjangoHTTPTestClientCompatibilityVows(DjangoContext):
|
||||||
|
|
||||||
|
class SimpleGet(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.get('/say/')
|
||||||
|
|
||||||
|
def should_be_ok(self, topic):
|
||||||
|
expect(topic.status_code).to_equal(200)
|
||||||
|
|
||||||
|
def should_ask_for_my_name(self, topic):
|
||||||
|
expect(topic).contains('What\'s your name?')
|
||||||
|
|
||||||
|
class SimpleGetWithParams(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.get('/say/?name=Rafael')
|
||||||
|
|
||||||
|
def should_say_hello_to_me(self, topic):
|
||||||
|
expect(topic).contains('Hello, Rafael!')
|
||||||
|
|
||||||
|
class SimplePost(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.post('/post_it/', {'value': 'posted!'})
|
||||||
|
|
||||||
|
def should_be_posted(self, topic):
|
||||||
|
expect(topic).contains('posted!')
|
||||||
|
|
||||||
|
class PostFile(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.post('/post_file/', {'the_file': open(self.TEST_FILE_PATH)})
|
||||||
|
|
||||||
|
def should_be_posted_to_the_server(self, topic):
|
||||||
|
expect(topic).contains("the contents")
|
||||||
|
|
||||||
|
class WhenNotFound(DjangoContext):
|
||||||
|
def topic(self):
|
||||||
|
return self.post('/post_/', {'the_file': open(self.TEST_FILE_PATH)})
|
||||||
|
|
||||||
|
def should_be_404(self, topic):
|
||||||
|
expect(topic.status_code).to_equal(404)
|
|
@ -9,109 +9,23 @@
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
from pyvows import Vows, expect
|
||||||
|
from pyvows.decorators import capture_error
|
||||||
|
|
||||||
|
from django_pyvows.context import DjangoContext
|
||||||
|
|
||||||
from django_pyvows.context import DjangoContext, DjangoHTTPContext
|
|
||||||
|
|
||||||
@Vows.batch
|
@Vows.batch
|
||||||
class ContextTest(Vows.Context):
|
class ContextTest(Vows.Context):
|
||||||
|
|
||||||
|
@capture_error
|
||||||
def topic(self):
|
def topic(self):
|
||||||
return DjangoContext.start_environment(None)
|
return DjangoContext.setup_environment(None)
|
||||||
|
|
||||||
def should_be_an_error(self, topic):
|
def should_be_an_error(self, topic):
|
||||||
expect(topic).to_be_an_error()
|
expect(topic).to_be_an_error()
|
||||||
|
|
||||||
def should_be_runtime_error(self, topic):
|
def should_be_runtime_error(self, topic):
|
||||||
expect(topic).to_be_an_error_like(RuntimeError)
|
expect(topic).to_be_an_error_like(ValueError)
|
||||||
|
|
||||||
def should_have_nice_error_message(self, topic):
|
def should_have_nice_error_message(self, topic):
|
||||||
expect(topic).to_have_an_error_message_of('The settings_path argument is required.')
|
expect(topic).to_have_an_error_message_of('The settings_path argument is required.')
|
||||||
|
|
||||||
class WithinANoDjangoContext(Vows.Context):
|
|
||||||
|
|
||||||
class TheGetUrlMethod(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.get_url('/')
|
|
||||||
|
|
||||||
def should_return_the_same_path(self, topic):
|
|
||||||
expect(topic).to_equal('/')
|
|
||||||
|
|
||||||
class TheHost(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.host
|
|
||||||
|
|
||||||
def should_return_an_error(self, topic):
|
|
||||||
expect(topic).to_be_an_error_like(ValueError)
|
|
||||||
|
|
||||||
class ThePort(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.port
|
|
||||||
|
|
||||||
def should_return_an_error(self, topic):
|
|
||||||
expect(topic).to_be_an_error_like(ValueError)
|
|
||||||
|
|
||||||
class WithinAServer(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
self.start_server(port=8085)
|
|
||||||
|
|
||||||
def should_default_to_one_thread(self,topic):
|
|
||||||
expect(self.server.thr.server._get_numthreads()).to_equal(1)
|
|
||||||
|
|
||||||
class WithinDjangoHTTPContextTheGetUrlMethod(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.get_url('http://127.0.0.1:8085/complete_url/')
|
|
||||||
|
|
||||||
def when_passed_a_complete_url_should_return_the_url_without_modification(self, topic):
|
|
||||||
expect(topic).to_equal('http://127.0.0.1:8085/complete_url/')
|
|
||||||
|
|
||||||
class InADjangoHTTPContext(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.get_url('/')
|
|
||||||
|
|
||||||
def the_get_url_should_return_a_well_formed_url(self, topic):
|
|
||||||
expect(topic).to_equal('http://127.0.0.1:8085/')
|
|
||||||
|
|
||||||
class ANoDjangoContext(Vows.Context):
|
|
||||||
|
|
||||||
class TheHost(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.host
|
|
||||||
|
|
||||||
def should_be_equal_to_the_host_in_out_context(self, topic):
|
|
||||||
expect(topic).to_equal('127.0.0.1')
|
|
||||||
|
|
||||||
class ThePort(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.port
|
|
||||||
|
|
||||||
def should_be_equal_to_the_port_in_out_context(self, topic):
|
|
||||||
expect(topic).to_equal(8085)
|
|
||||||
|
|
||||||
class AnDjangoContext(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.get_url('/')
|
|
||||||
|
|
||||||
def the_get_url_method_should_return_a_well_formed_url(self, topic):
|
|
||||||
expect(topic).to_equal('http://127.0.0.1:8085/')
|
|
||||||
|
|
||||||
class WithinAMultiThreadedServer(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
self.start_server(threads=5)
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.server
|
|
||||||
|
|
||||||
def should_allow_user_to_specify_number_of_threads(self,topic):
|
|
||||||
expect(topic.thr.server._get_numthreads()).to_equal(5)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
|
||||||
from django_pyvows.context import DjangoContext
|
|
||||||
|
|
||||||
DjangoContext.start_environment("sandbox.settings")
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from sandbox.main.models import StringModel
|
|
||||||
|
|
||||||
@Vows.batch
|
|
||||||
class ModelVows(DjangoContext):
|
|
||||||
|
|
||||||
class MainModel(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.model(StringModel)
|
|
||||||
|
|
||||||
def should_be_cruddable_when_model_only_has_a_string(self, topic):
|
|
||||||
expect(topic).to_be_cruddable()
|
|
||||||
|
|
||||||
def should_be_cruddable_when_string_passed(self, topic):
|
|
||||||
expect(topic).to_be_cruddable({
|
|
||||||
'name': 'something'
|
|
||||||
})
|
|
||||||
|
|
||||||
def should_be_possible_to_use_the_assertion_in_model_instance(self, topic):
|
|
||||||
expect(topic).to_have_field('name')
|
|
||||||
|
|
||||||
def should_have_a_method_to_call(self, topic):
|
|
||||||
expect(hasattr(topic, '__call__')).to_be_true()
|
|
||||||
|
|
||||||
class WhenICreateANewInstance(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self, model):
|
|
||||||
return model()
|
|
||||||
|
|
||||||
def should_be_an_instance_of_django_model_class(self, topic):
|
|
||||||
expect(isinstance(topic, models.Model)).to_be_true()
|
|
||||||
|
|
||||||
def should_have_a_name_field(self, topic):
|
|
||||||
expect(topic).to_have_field('name')
|
|
||||||
|
|
||||||
def should_have_a_name_field_as_charfield(self, topic):
|
|
||||||
expect(topic).to_have_field('name', models.CharField)
|
|
||||||
|
|
||||||
def should_have_a_name_field_as_charfield_and_max_length_100(self, topic):
|
|
||||||
expect(topic).to_have_field('name', models.CharField, max_length=100)
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
|
@ -1,14 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
class StringModel(models.Model):
|
|
||||||
name = models.CharField(max_length=100)
|
|
|
@ -1,16 +0,0 @@
|
||||||
"""
|
|
||||||
This file demonstrates writing tests using the unittest module. These will pass
|
|
||||||
when you run "manage.py test".
|
|
||||||
|
|
||||||
Replace this with more appropriate tests for your application.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
|
||||||
def test_basic_addition(self):
|
|
||||||
"""
|
|
||||||
Tests that 1 + 1 always equals 2.
|
|
||||||
"""
|
|
||||||
self.assertEqual(1 + 1, 2)
|
|
|
@ -1,14 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
from django.core.management import execute_manager
|
|
||||||
import imp
|
|
||||||
try:
|
|
||||||
imp.find_module('settings') # Assumed to be in the same directory.
|
|
||||||
except ImportError:
|
|
||||||
import sys
|
|
||||||
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
import settings
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
execute_manager(settings)
|
|
|
@ -1,153 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
# Django settings for sandbox project.
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
DEBUG = True
|
|
||||||
TEMPLATE_DEBUG = DEBUG
|
|
||||||
|
|
||||||
PROJECT_ROOT = os.path.realpath(os.path.dirname(__file__))
|
|
||||||
|
|
||||||
ADMINS = (
|
|
||||||
# ('Your Name', 'your_email@example.com'),
|
|
||||||
)
|
|
||||||
|
|
||||||
MANAGERS = ADMINS
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
|
|
||||||
'PORT': '', # Set to empty string for default. Not used with sqlite3.
|
|
||||||
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
|
||||||
'NAME': 'db.db', # Or path to database file if using sqlite3.
|
|
||||||
'USER': 'root', # Not used with sqlite3.
|
|
||||||
'PASSWORD': '', # Not used with sqlite3.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Local time zone for this installation. Choices can be found here:
|
|
||||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
|
||||||
# although not all choices may be available on all operating systems.
|
|
||||||
# On Unix systems, a value of None will cause Django to use the same
|
|
||||||
# timezone as the operating system.
|
|
||||||
# If running in a Windows environment this must be set to the same as your
|
|
||||||
# system time zone.
|
|
||||||
TIME_ZONE = 'America/Chicago'
|
|
||||||
|
|
||||||
# Language code for this installation. All choices can be found here:
|
|
||||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
|
||||||
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
# If you set this to False, Django will make some optimizations so as not
|
|
||||||
# to load the internationalization machinery.
|
|
||||||
USE_I18N = True
|
|
||||||
|
|
||||||
# If you set this to False, Django will not format dates, numbers and
|
|
||||||
# calendars according to the current locale
|
|
||||||
USE_L10N = True
|
|
||||||
|
|
||||||
# Absolute filesystem path to the directory that will hold user-uploaded files.
|
|
||||||
# Example: "/home/media/media.lawrence.com/media/"
|
|
||||||
MEDIA_ROOT = ''
|
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
|
||||||
# trailing slash.
|
|
||||||
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
|
|
||||||
MEDIA_URL = ''
|
|
||||||
|
|
||||||
# Absolute path to the directory static files should be collected to.
|
|
||||||
# Don't put anything in this directory yourself; store your static files
|
|
||||||
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
|
|
||||||
# Example: "/home/media/media.lawrence.com/static/"
|
|
||||||
STATIC_ROOT = ''
|
|
||||||
|
|
||||||
# URL prefix for static files.
|
|
||||||
# Example: "http://media.lawrence.com/static/"
|
|
||||||
STATIC_URL = '/static/'
|
|
||||||
|
|
||||||
# URL prefix for admin static files -- CSS, JavaScript and images.
|
|
||||||
# Make sure to use a trailing slash.
|
|
||||||
# Examples: "http://foo.com/static/admin/", "/static/admin/".
|
|
||||||
ADMIN_MEDIA_PREFIX = '/static/admin/'
|
|
||||||
|
|
||||||
# Additional locations of static files
|
|
||||||
STATICFILES_DIRS = (
|
|
||||||
# Put strings here, like "/home/html/static" or "C:/www/django/static".
|
|
||||||
# Always use forward slashes, even on Windows.
|
|
||||||
# Don't forget to use absolute paths, not relative paths.
|
|
||||||
)
|
|
||||||
|
|
||||||
# List of finder classes that know how to find static files in
|
|
||||||
# various locations.
|
|
||||||
STATICFILES_FINDERS = (
|
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
|
||||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
|
||||||
)
|
|
||||||
|
|
||||||
# Make this unique, and don't share it with anybody.
|
|
||||||
SECRET_KEY = 'l7#du3ceob9^i^6^jambl@io7nxc^%&))b$uxlxa#-3lake5+w'
|
|
||||||
|
|
||||||
# List of callables that know how to import templates from various sources.
|
|
||||||
TEMPLATE_LOADERS = (
|
|
||||||
'django.template.loaders.filesystem.Loader',
|
|
||||||
'django.template.loaders.app_directories.Loader',
|
|
||||||
)
|
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
|
||||||
'django.middleware.common.CommonMiddleware',
|
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
|
||||||
)
|
|
||||||
|
|
||||||
ROOT_URLCONF = 'sandbox.urls'
|
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
|
||||||
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
|
||||||
# Always use forward slashes, even on Windows.
|
|
||||||
# Don't forget to use absolute paths, not relative paths.
|
|
||||||
os.path.join(PROJECT_ROOT, "templates"),
|
|
||||||
)
|
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
|
||||||
'sandbox.main',
|
|
||||||
# Uncomment the next line to enable the admin:
|
|
||||||
# 'django.contrib.admin',
|
|
||||||
# Uncomment the next line to enable admin documentation:
|
|
||||||
# 'django.contrib.admindocs',
|
|
||||||
)
|
|
||||||
|
|
||||||
SAY_HELLO_WITHOUT_NAME = False
|
|
||||||
|
|
||||||
# A sample logging configuration. The only tangible logging
|
|
||||||
# performed by this configuration is to send an email to
|
|
||||||
# the site admins on every HTTP 500 error.
|
|
||||||
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
|
||||||
# more details on how to customize your logging configuration.
|
|
||||||
LOGGING = {
|
|
||||||
'version': 1,
|
|
||||||
'disable_existing_loggers': False,
|
|
||||||
'handlers': {
|
|
||||||
'mail_admins': {
|
|
||||||
'level': 'ERROR',
|
|
||||||
'class': 'django.utils.log.AdminEmailHandler'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'loggers': {
|
|
||||||
'django.request': {
|
|
||||||
'handlers': ['mail_admins'],
|
|
||||||
'level': 'ERROR',
|
|
||||||
'propagate': True,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from django.conf.urls.defaults import patterns, include, url
|
|
||||||
|
|
||||||
# Uncomment the next two lines to enable the admin:
|
|
||||||
from django.contrib import admin
|
|
||||||
admin.autodiscover()
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
|
||||||
url(r'^$', 'sandbox.main.views.home', name='home'),
|
|
||||||
url(r'^say/$', 'sandbox.main.views.say_hello', name='say_hello'),
|
|
||||||
url(r'^post_it/$', 'sandbox.main.views.post_it', name='post_it'),
|
|
||||||
url(r'^post_file/$', 'sandbox.main.views.post_file', name='post_file'),
|
|
||||||
|
|
||||||
# url(r'^sandbox/', include('sandbox.foo.urls')),
|
|
||||||
|
|
||||||
# Uncomment the admin/doc line below to enable admin documentation:
|
|
||||||
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
|
||||||
|
|
||||||
# Uncomment the next line to enable the admin:
|
|
||||||
#url(r'^admin/', include('admin.site.urls')),
|
|
||||||
)
|
|
|
@ -1,83 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from os.path import abspath, join, dirname
|
|
||||||
|
|
||||||
import httplib2
|
|
||||||
|
|
||||||
from django_pyvows.context import DjangoContext, DjangoHTTPContext
|
|
||||||
from django_pyvows.assertions import *
|
|
||||||
|
|
||||||
TEST_FILE_PATH = abspath(join(dirname(__file__), 'fixtures/the_file.txt'))
|
|
||||||
|
|
||||||
DjangoContext.start_environment("sandbox.settings")
|
|
||||||
|
|
||||||
@Vows.batch
|
|
||||||
class HttpContextVows(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
self.start_server()
|
|
||||||
return self.get("/")
|
|
||||||
|
|
||||||
def the_return_code_should_be_200(self, (topic, content)):
|
|
||||||
expect(topic.status).to_equal(200)
|
|
||||||
|
|
||||||
def should_return_the_success_response(self, (topic, content)):
|
|
||||||
expect(content).to_equal("hello world")
|
|
||||||
|
|
||||||
class Methods(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.get('/?name=rafael')
|
|
||||||
|
|
||||||
def should_be_possible_to_pass_get_parameters(self, (topic, content)):
|
|
||||||
expect(topic.status).to_equal(200)
|
|
||||||
|
|
||||||
class AskMyName(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.get('/say/')
|
|
||||||
|
|
||||||
def should_ask_for_my_name(self, (topic, content)):
|
|
||||||
expect(content).to_equal('What\'s your name?')
|
|
||||||
|
|
||||||
class SayHelloToMe(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.get('/say/?name=Rafael')
|
|
||||||
|
|
||||||
def should_say_hello_to_me(self, (topic, content)):
|
|
||||||
expect(content).to_equal('Hello, Rafael!')
|
|
||||||
|
|
||||||
class PostIt(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.post('/post_it/', {'value': 'posted!'})
|
|
||||||
|
|
||||||
def should_be_posted(self, (topic, content)):
|
|
||||||
expect(content).to_equal('posted!')
|
|
||||||
|
|
||||||
class PostFile(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.post('/post_file/', {'the_file': open(TEST_FILE_PATH) })
|
|
||||||
|
|
||||||
def should_be_posted_to_the_server(self, (topic, content)):
|
|
||||||
expect(content).to_equal("the contents")
|
|
||||||
|
|
||||||
class PostToNotFound(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.post('/post_/', {'the_file': open(TEST_FILE_PATH) })
|
|
||||||
|
|
||||||
def should_be_404(self, (topic, content)):
|
|
||||||
expect(topic.status).to_equal(404)
|
|
||||||
|
|
||||||
|
|
|
@ -9,73 +9,40 @@
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
from pyvows import Vows, expect
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from django_pyvows.context import DjangoContext, DjangoHTTPContext
|
from test_config import ConfiguredVowsContext as DjangoContext
|
||||||
from django_pyvows.settings_manager import settings_tracker, VowsSettings
|
|
||||||
|
|
||||||
DjangoContext.start_environment("sandbox.settings")
|
|
||||||
|
|
||||||
@Vows.batch
|
@Vows.batch
|
||||||
class SettingsVows(DjangoContext):
|
class SettingsOverridingVows(DjangoContext):
|
||||||
|
|
||||||
class WhenIUseTheSettingsTracker(DjangoContext):
|
|
||||||
|
|
||||||
|
class CannotSayHelloWithoutName(DjangoContext):
|
||||||
def topic(self):
|
def topic(self):
|
||||||
settings_tracker.install()
|
with self.settings(SAY_HELLO_WITHOUT_NAME=False):
|
||||||
|
|
||||||
class WhenImportFromDjangoConf(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
from django.conf import settings
|
|
||||||
return settings
|
|
||||||
|
|
||||||
def should_be_the_vows_settings(self, topic):
|
|
||||||
expect(topic).to_be_instance_of(VowsSettings)
|
|
||||||
|
|
||||||
class WhenIImportOnlyConfAndThenUseSettings(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
from django import conf
|
|
||||||
return conf.settings
|
|
||||||
|
|
||||||
def should_be_the_vows_settings(self, topic):
|
|
||||||
expect(topic).to_be_instance_of(VowsSettings)
|
|
||||||
|
|
||||||
class WhenIImportTheCompletePathAndThenUseSettings(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
import django.conf
|
|
||||||
return django.conf.settings
|
|
||||||
|
|
||||||
def should_be_the_vows_settings(self, topic):
|
|
||||||
expect(topic).to_be_instance_of(VowsSettings)
|
|
||||||
|
|
||||||
class CannotSayHelloWithoutName(DjangoHTTPContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
self.start_server(port=9000, settings={
|
|
||||||
'SAY_HELLO_WITHOUT_NAME': False
|
|
||||||
})
|
|
||||||
|
|
||||||
return self.get('/say/')
|
return self.get('/say/')
|
||||||
|
|
||||||
def should_be_ok(self, (topic, content)):
|
def should_be_ok(self, topic):
|
||||||
expect(topic.status).to_equal(200)
|
expect(topic.status_code).to_equal(200)
|
||||||
|
|
||||||
def should_ask_for_my_name(self, (topic, content)):
|
def should_ask_for_my_name(self, topic):
|
||||||
expect(content).to_equal("What's your name?")
|
expect(topic).contains("What's your name?")
|
||||||
|
|
||||||
class SayHelloWithoutName(DjangoHTTPContext):
|
|
||||||
|
|
||||||
|
class SayHelloWithoutName(DjangoContext):
|
||||||
def topic(self):
|
def topic(self):
|
||||||
self.start_server(port=9001, settings={
|
with self.settings(SAY_HELLO_WITHOUT_NAME=True):
|
||||||
'SAY_HELLO_WITHOUT_NAME': True
|
|
||||||
})
|
|
||||||
return self.get('/say/')
|
return self.get('/say/')
|
||||||
|
|
||||||
def should_be_ok(self, (topic, content)):
|
def should_be_ok(self, topic):
|
||||||
expect(topic.status).to_equal(200)
|
expect(topic.status_code).to_equal(200)
|
||||||
|
|
||||||
def should_(self, (topic, content)):
|
def should_(self, topic):
|
||||||
expect(content).to_equal("Hello, guess!")
|
expect(topic).contains("Hello, guest!")
|
||||||
|
|
||||||
|
class UseDecoratorToChangeSettings(DjangoContext):
|
||||||
|
@override_settings(SAY_HELLO_WITHOUT_NAME=True)
|
||||||
|
def topic(self):
|
||||||
|
return self.get('/say/')
|
||||||
|
|
||||||
|
def should_say_hello_to_guest(self, topic):
|
||||||
|
expect(topic).contains("Hello, guest!")
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
|
||||||
|
|
||||||
from django_pyvows.context import DjangoContext
|
|
||||||
from django_pyvows.assertions import *
|
|
||||||
|
|
||||||
@Vows.batch
|
|
||||||
class TemplateVows(DjangoContext):
|
|
||||||
|
|
||||||
def get_settings(self):
|
|
||||||
return 'sandbox.settings'
|
|
||||||
|
|
||||||
class IndexTemplate(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.template('index.html', {
|
|
||||||
'some': 'thing'
|
|
||||||
})
|
|
||||||
|
|
||||||
def should_have_container_div(self, topic):
|
|
||||||
expect(topic).to_contain('div.container')
|
|
||||||
|
|
||||||
def should_not_have_a_hello_div(self, topic):
|
|
||||||
expect(topic).Not.to_contain('div.hello')
|
|
||||||
|
|
||||||
def should_be_index_file(self, topic):
|
|
||||||
expect(unicode(topic)).to_equal('index.html')
|
|
||||||
|
|
||||||
class Paragraph(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self, template):
|
|
||||||
return template.get_text('p.my-text')
|
|
||||||
|
|
||||||
def should_have_paragraph_with_text(self, topic):
|
|
||||||
expect(topic).to_be_like('some text')
|
|
||||||
|
|
||||||
|
|
20
vows/test_config.py
Normal file
20
vows/test_config.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# django-pyvows extensions
|
||||||
|
# https://github.com/rafaelcaricio/django-pyvows
|
||||||
|
|
||||||
|
# Licensed under the MIT license:
|
||||||
|
# http://www.opensource.org/licenses/mit-license
|
||||||
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
|
from os.path import abspath, join, dirname
|
||||||
|
|
||||||
|
from django_pyvows.context import DjangoContext
|
||||||
|
|
||||||
|
|
||||||
|
class ConfiguredVowsContext(DjangoContext):
|
||||||
|
def settings_module(self):
|
||||||
|
return 'sandbox.settings'
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.TEST_FILE_PATH = abspath(join(dirname(__file__), 'fixtures/the_file.txt'))
|
|
@ -1,32 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
|
||||||
|
|
||||||
from django_pyvows.context import DjangoContext
|
|
||||||
from django_pyvows.assertions import *
|
|
||||||
|
|
||||||
DjangoContext.start_environment("sandbox.settings")
|
|
||||||
|
|
||||||
from sandbox.main.views import home
|
|
||||||
|
|
||||||
@Vows.batch
|
|
||||||
class UrlVows(DjangoContext):
|
|
||||||
|
|
||||||
class Home(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return self.url('^$')
|
|
||||||
|
|
||||||
def should_have_home_url_mapped(self, topic):
|
|
||||||
expect(topic).to_be_mapped()
|
|
||||||
|
|
||||||
def should_have_url_mapped_to_home_view(self, topic):
|
|
||||||
expect(topic).to_match_view(home)
|
|
|
@ -1,30 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# django-pyvows extensions
|
|
||||||
# https://github.com/rafaelcaricio/django-pyvows
|
|
||||||
|
|
||||||
# Licensed under the MIT license:
|
|
||||||
# http://www.opensource.org/licenses/mit-license
|
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
|
||||||
|
|
||||||
from pyvows import Vows, expect
|
|
||||||
from django_pyvows.context import DjangoContext
|
|
||||||
|
|
||||||
DjangoContext.start_environment("sandbox.settings")
|
|
||||||
|
|
||||||
from sandbox.main.views import home
|
|
||||||
|
|
||||||
@Vows.batch
|
|
||||||
class ViewVows(DjangoContext):
|
|
||||||
|
|
||||||
class Home(DjangoContext):
|
|
||||||
|
|
||||||
def topic(self):
|
|
||||||
return home(self.request())
|
|
||||||
|
|
||||||
def should_be_instance_of_http_response(self, topic):
|
|
||||||
expect(topic).to_be_http_response()
|
|
||||||
|
|
||||||
def should_be_hello_world(self, topic):
|
|
||||||
expect(topic).to_have_contents_of('Hello World')
|
|
Reference in a new issue