lists functional tests passing
This commit is contained in:
parent
4c7c5b5505
commit
3e246f9fe0
4
TODO.md
4
TODO.md
|
@ -147,3 +147,7 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
|
||||
|
||||
* POST only fields (account, username, name) etc
|
||||
|
||||
* for list virtual_domains cleaning up we need to know the old domain name when a list changes its address domain, but this is not possible with the current design.
|
||||
|
||||
* update_fields=[] doesn't trigger post save!
|
||||
|
|
|
@ -11,11 +11,20 @@ class SetPasswordApiMixin(object):
|
|||
obj = self.get_object()
|
||||
data = request.DATA
|
||||
if isinstance(data, basestring):
|
||||
data = {'password': data}
|
||||
data = {
|
||||
'password': data
|
||||
}
|
||||
serializer = SetPasswordSerializer(data=data)
|
||||
if serializer.is_valid():
|
||||
obj.set_password(serializer.data['password'])
|
||||
obj.save(update_fields=['password'])
|
||||
return Response({'status': 'password changed'})
|
||||
try:
|
||||
obj.save(update_fields=['password'])
|
||||
except ValueError:
|
||||
# Some services don't store the password on the database
|
||||
# update_fields=[] doesn't trigger post save!
|
||||
obj.save()
|
||||
return Response({
|
||||
'status': 'password changed'
|
||||
})
|
||||
else:
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
|
|
@ -74,6 +74,7 @@ class MySQLUserBackend(ServiceController):
|
|||
}
|
||||
|
||||
|
||||
# TODO https://docs.djangoproject.com/en/1.7/ref/signals/#m2m-changed
|
||||
class MySQLPermissionBackend(ServiceController):
|
||||
model = 'databases.UserDatabaseRelation'
|
||||
verbose_name = "MySQL permission"
|
||||
|
|
|
@ -70,6 +70,9 @@ class DatabaseTestMixin(object):
|
|||
self.validate_login_error(dbname, username, password)
|
||||
self.validate_create_table(dbname, username, new_password)
|
||||
|
||||
# TODO test add user
|
||||
# TODO remove user
|
||||
# TODO remove all users
|
||||
|
||||
class MySQLBackendMixin(object):
|
||||
db_type = 'mysql'
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.conf.urls import patterns
|
|||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||
from orchestra.admin.utils import admin_link
|
||||
from orchestra.apps.accounts.admin import SelectAccountAdminMixin
|
||||
|
||||
|
@ -11,7 +11,7 @@ from .forms import ListCreationForm, ListChangeForm
|
|||
from .models import List
|
||||
|
||||
|
||||
class ListAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||
class ListAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||
list_display = ('name', 'address_name', 'address_domain_link', 'account_link')
|
||||
add_fieldsets = (
|
||||
(None, {
|
||||
|
@ -38,7 +38,7 @@ class ListAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
}),
|
||||
(_("Admin"), {
|
||||
'classes': ('wide',),
|
||||
'fields': ('admin_email', 'password',),
|
||||
'fields': ('password',),
|
||||
}),
|
||||
)
|
||||
readonly_fields = ('account_link',)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import re
|
||||
import textwrap
|
||||
|
||||
from django.utils import timezone
|
||||
|
@ -12,8 +13,23 @@ from .models import List
|
|||
class MailmanBackend(ServiceController):
|
||||
verbose_name = "Mailman"
|
||||
model = 'lists.List'
|
||||
addresses = [
|
||||
'',
|
||||
'-admin',
|
||||
'-bounces',
|
||||
'-confirm',
|
||||
'-join',
|
||||
'-leave',
|
||||
'-owner',
|
||||
'-request',
|
||||
'-subscribe',
|
||||
'-unsubscribe'
|
||||
]
|
||||
|
||||
def include_virtual_alias_domain(self, context):
|
||||
# TODO for list virtual_domains cleaning up we need to know the old domain name when a list changes its address
|
||||
# domain, but this is not possible with the current design.
|
||||
# sync the whole file everytime?
|
||||
if context['address_domain']:
|
||||
self.append(textwrap.dedent("""
|
||||
[[ $(grep "^\s*%(address_domain)s\s*$" %(virtual_alias_domains)s) ]] || {
|
||||
|
@ -29,42 +45,62 @@ class MailmanBackend(ServiceController):
|
|||
|
||||
def get_virtual_aliases(self, context):
|
||||
aliases = []
|
||||
addresses = [
|
||||
'',
|
||||
'-admin',
|
||||
'-bounces',
|
||||
'-confirm',
|
||||
'-join',
|
||||
'-leave',
|
||||
'-owner',
|
||||
'-request',
|
||||
'-subscribe',
|
||||
'-unsubscribe'
|
||||
]
|
||||
for address in addresses:
|
||||
for address in self.addresses:
|
||||
context['address'] = address
|
||||
aliases.append("%(address_name)s%(address)s@%(domain)s\t%(name)s%(address)s" % context)
|
||||
return '\n'.join(aliases)
|
||||
|
||||
def save(self, mail_list):
|
||||
if not getattr(mail_list, 'password', None):
|
||||
# TODO
|
||||
# Create only support for now
|
||||
return
|
||||
context = self.get_context(mail_list)
|
||||
self.append("newlist --quiet --emailhost='%(domain)s' '%(name)s' '%(admin)s' '%(password)s'" % context)
|
||||
# Create list
|
||||
self.append(textwrap.dedent("""\
|
||||
[[ ! -e %(mailman_root)s/lists/%(name)s ]] && {
|
||||
newlist --quiet --emailhost='%(domain)s' '%(name)s' '%(admin)s' '%(password)s'
|
||||
}""" % context))
|
||||
# Custom domain
|
||||
if mail_list.address:
|
||||
context['aliases'] = self.get_virtual_aliases(context)
|
||||
self.append(
|
||||
"if [[ ! $(grep '^\s*%(name)s\s' %(virtual_alias)s) ]]; then\n"
|
||||
" echo '# %(banner)s\n%(aliases)s\n' >> %(virtual_alias)s\n"
|
||||
" UPDATED_VIRTUAL_ALIAS=1\n"
|
||||
"fi" % context
|
||||
)
|
||||
aliases = self.get_virtual_aliases(context)
|
||||
# Preserve indentation
|
||||
spaces = ' '*4
|
||||
context['aliases'] = spaces + aliases.replace('\n', '\n'+spaces)
|
||||
self.append(textwrap.dedent("""\
|
||||
if [[ ! $(grep '\s\s*%(name)s\s*$' %(virtual_alias)s) ]]; then
|
||||
echo '# %(banner)s\n%(aliases)s
|
||||
' >> %(virtual_alias)s
|
||||
UPDATED_VIRTUAL_ALIAS=1
|
||||
else
|
||||
if [[ ! $(grep '^\s*%(address_name)s@%(address_domain)s\s\s*%(name)s\s*$' %(virtual_alias)s) ]]; then
|
||||
sed -i "s/^.*\s%(name)s\s*$//" %(virtual_alias)s
|
||||
echo '# %(banner)s\n%(aliases)s
|
||||
' >> %(virtual_alias)s
|
||||
UPDATED_VIRTUAL_ALIAS=1
|
||||
fi
|
||||
fi""" % context
|
||||
))
|
||||
self.append('echo "require_explicit_destination = 0" | '
|
||||
'%(mailman_root)s/bin/config_list -i /dev/stdin %(name)s' % context)
|
||||
self.append(textwrap.dedent("""\
|
||||
echo "host_name = '%(address_domain)s'" | \
|
||||
%(mailman_root)s/bin/config_list -i /dev/stdin %(name)s""" % context))
|
||||
else:
|
||||
# Cleanup shit
|
||||
self.append(textwrap.dedent("""\
|
||||
if [[ ! $(grep '\s\s*%(name)s\s*$' %(virtual_alias)s) ]]; then
|
||||
sed -i "s/^.*\s%(name)s\s*$//" %(virtual_alias)s
|
||||
fi""" % context
|
||||
))
|
||||
# Update
|
||||
if context['password'] is not None:
|
||||
self.append('%(mailman_root)s/bin/change_pw --listname="%(name)s" --password="%(password)s"' % context)
|
||||
self.include_virtual_alias_domain(context)
|
||||
|
||||
def delete(self, mail_list):
|
||||
pass
|
||||
context = self.get_context(mail_list)
|
||||
self.exclude_virtual_alias_domain(context)
|
||||
for address in self.addresses:
|
||||
context['address'] = address
|
||||
self.append('sed -i "s/^.*\s%(name)s%(address)s\s*$//" %(virtual_alias)s' % context)
|
||||
self.append("rmlist -a %(name)s" % context)
|
||||
|
||||
def commit(self):
|
||||
context = self.get_context_files()
|
||||
|
@ -77,7 +113,7 @@ class MailmanBackend(ServiceController):
|
|||
def get_context_files(self):
|
||||
return {
|
||||
'virtual_alias': settings.LISTS_VIRTUAL_ALIAS_PATH,
|
||||
'virtual_alias_domains': settings.MAILS_VIRTUAL_ALIAS_DOMAINS_PATH,
|
||||
'virtual_alias_domains': settings.LISTS_VIRTUAL_ALIAS_DOMAINS_PATH,
|
||||
}
|
||||
|
||||
def get_context(self, mail_list):
|
||||
|
@ -90,6 +126,7 @@ class MailmanBackend(ServiceController):
|
|||
'address_name': mail_list.address_name,
|
||||
'address_domain': mail_list.address_domain,
|
||||
'admin': mail_list.admin_email,
|
||||
'mailman_root': settings.LISTS_MAILMAN_ROOT_PATH,
|
||||
})
|
||||
return context
|
||||
|
||||
|
@ -101,7 +138,7 @@ class MailmanTraffic(ServiceMonitor):
|
|||
def prepare(self):
|
||||
current_date = timezone.localtime(self.current_date)
|
||||
current_date = current_date.strftime("%b %d %H:%M:%S")
|
||||
self.append(textwrap.dedent("""
|
||||
self.append(textwrap.dedent("""\
|
||||
function monitor () {
|
||||
OBJECT_ID=$1
|
||||
LAST_DATE=$2
|
||||
|
|
|
@ -21,6 +21,8 @@ class List(models.Model):
|
|||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||
related_name='lists')
|
||||
|
||||
password = None
|
||||
|
||||
class Meta:
|
||||
unique_together = ('address_name', 'address_domain')
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from django.conf import settings
|
||||
|
||||
|
||||
|
||||
LISTS_DOMAIN_MODEL = getattr(settings, 'LISTS_DOMAIN_MODEL', 'domains.Domain')
|
||||
|
||||
|
||||
|
@ -12,9 +11,13 @@ LISTS_MAILMAN_POST_LOG_PATH = getattr(settings, 'LISTS_MAILMAN_POST_LOG_PATH',
|
|||
'/var/log/mailman/post')
|
||||
|
||||
|
||||
LISTS_MAILMAN_ROOT_PATH = getattr(settings, 'LISTS_MAILMAN_ROOT_PATH',
|
||||
'/var/lib/mailman/')
|
||||
|
||||
|
||||
LISTS_VIRTUAL_ALIAS_PATH = getattr(settings, 'LISTS_VIRTUAL_ALIAS_PATH',
|
||||
'/etc/postfix/mailman_virtual_aliases')
|
||||
|
||||
|
||||
MAILS_VIRTUAL_ALIAS_DOMAINS_PATH = getattr(settings, 'MAILS_VIRTUAL_ALIAS_DOMAINS_PATH',
|
||||
LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = getattr(settings, 'LISTS_VIRTUAL_ALIAS_DOMAINS_PATH',
|
||||
'/etc/postfix/mailman_virtual_domains')
|
||||
|
|
|
@ -3,6 +3,7 @@ import os
|
|||
import smtplib
|
||||
import time
|
||||
import textwrap
|
||||
import requests
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
from django.conf import settings as djsettings
|
||||
|
@ -11,12 +12,14 @@ from django.core.management.base import CommandError
|
|||
from django.core.urlresolvers import reverse
|
||||
from selenium.webdriver.support.select import Select
|
||||
|
||||
from orchestra.admin.utils import change_url
|
||||
from orchestra.apps.accounts.models import Account
|
||||
from orchestra.apps.domains.models import Domain
|
||||
from orchestra.apps.orchestration.models import Server, Route
|
||||
from orchestra.apps.resources.models import Resource
|
||||
from orchestra.utils.system import run, sshrun
|
||||
from orchestra.utils.tests import BaseLiveServerTestCase, random_ascii, snapshot_on_error, save_response_on_error
|
||||
from orchestra.utils.tests import (BaseLiveServerTestCase, random_ascii, snapshot_on_error,
|
||||
save_response_on_error)
|
||||
|
||||
from ... import backends, settings
|
||||
from ...models import List
|
||||
|
@ -40,10 +43,30 @@ class ListMixin(object):
|
|||
if not address:
|
||||
address = "%s@%s" % (name, settings.LISTS_DEFAULT_DOMAIN)
|
||||
subscribe_address = "{}-subscribe@{}".format(*address.split('@'))
|
||||
request_address = "{}-request@{}".format(name, address.split('@')[1])
|
||||
self.subscribe(subscribe_address)
|
||||
time.sleep(2)
|
||||
time.sleep(3)
|
||||
sshrun(self.MASTER_SERVER,
|
||||
'grep -v ":\|^\s\|^$\|-\|\.\|\s" /var/spool/mail/nobody | base64 -d | grep "%s"' % address, display=False)
|
||||
'grep -v ":\|^\s\|^$\|-\|\.\|\s" /var/spool/mail/nobody | base64 -d | grep "%s"'
|
||||
% request_address, display=False)
|
||||
|
||||
def validate_login(self, name, password):
|
||||
url = 'http://%s/cgi-bin/mailman/admin/%s' % (settings.LISTS_DEFAULT_DOMAIN, name)
|
||||
self.assertEqual(200, requests.post(url, data={'adminpw': password}).status_code)
|
||||
|
||||
def validate_delete(self, name):
|
||||
context = {
|
||||
'name': name,
|
||||
'domain': Domain.objects.get().name,
|
||||
'virtual_domain': settings.LISTS_VIRTUAL_ALIAS_DOMAINS_PATH,
|
||||
'virtual_alias': settings.LISTS_VIRTUAL_ALIAS_PATH,
|
||||
}
|
||||
self.assertRaises(CommandError, sshrun, self.MASTER_SERVER,
|
||||
'grep "\s%(name)s\s*" %(virtual_alias)s' % context, display=False)
|
||||
self.assertRaises(CommandError, sshrun, self.MASTER_SERVER,
|
||||
'grep "^\s*$(domain)s\s*$" %(virtual_domain)s' % context, display=False)
|
||||
self.assertRaises(CommandError, sshrun, self.MASTER_SERVER,
|
||||
'list_lists | grep -i "^\s*%(name)s\s"' % context, display=False)
|
||||
|
||||
def subscribe(self, subscribe_address):
|
||||
msg = MIMEText('')
|
||||
|
@ -70,18 +93,74 @@ class ListMixin(object):
|
|||
admin_email = 'root@test3.orchestra.lan'
|
||||
self.add(name, password, admin_email)
|
||||
self.validate_add(name)
|
||||
# self.addCleanup(self.delete, username)
|
||||
self.validate_login(name, password)
|
||||
self.addCleanup(self.delete, name)
|
||||
|
||||
def test_add_with_address(self):
|
||||
name = '%s_list' % random_ascii(10)
|
||||
password = '@!?%spppP001' % random_ascii(5)
|
||||
print password
|
||||
admin_email = 'root@test3.orchestra.lan'
|
||||
address_name = '%s_name' % random_ascii(10)
|
||||
domain_name = '%sdomain.lan' % random_ascii(10)
|
||||
address_domain = Domain.objects.create(name=domain_name, account=self.account)
|
||||
self.add(name, password, admin_email, address_name=address_name, address_domain=address_domain)
|
||||
self.addCleanup(self.delete, name)
|
||||
# Mailman doesn't support changing the address, only the domain
|
||||
self.validate_add(name, address="%s@%s" % (address_name, address_domain))
|
||||
|
||||
def test_change_password(self):
|
||||
name = '%s_list' % random_ascii(10)
|
||||
password = '@!?%spppP001' % random_ascii(5)
|
||||
admin_email = 'root@test3.orchestra.lan'
|
||||
self.add(name, password, admin_email)
|
||||
self.addCleanup(self.delete, name)
|
||||
self.validate_login(name, password)
|
||||
new_password = '@!?%spppP001' % random_ascii(5)
|
||||
self.change_password(name, new_password)
|
||||
self.validate_login(name, new_password)
|
||||
|
||||
def test_change_domain(self):
|
||||
name = '%s_list' % random_ascii(10)
|
||||
password = '@!?%spppP001' % random_ascii(5)
|
||||
admin_email = 'root@test3.orchestra.lan'
|
||||
address_name = '%s_name' % random_ascii(10)
|
||||
domain_name = '%sdomain.lan' % random_ascii(10)
|
||||
address_domain = Domain.objects.create(name=domain_name, account=self.account)
|
||||
self.add(name, password, admin_email, address_name=address_name, address_domain=address_domain)
|
||||
self.addCleanup(self.delete, name)
|
||||
# Mailman doesn't support changing the address, only the domain
|
||||
domain_name = '%sdomain.lan' % random_ascii(10)
|
||||
address_domain = Domain.objects.create(name=domain_name, account=self.account)
|
||||
self.update_domain(name, domain_name)
|
||||
self.validate_add(name, address="%s@%s" % (address_name, address_domain))
|
||||
|
||||
def test_change_address_name(self):
|
||||
name = '%s_list' % random_ascii(10)
|
||||
password = '@!?%spppP001' % random_ascii(5)
|
||||
admin_email = 'root@test3.orchestra.lan'
|
||||
address_name = '%s_name' % random_ascii(10)
|
||||
domain_name = '%sdomain.lan' % random_ascii(10)
|
||||
address_domain = Domain.objects.create(name=domain_name, account=self.account)
|
||||
self.add(name, password, admin_email, address_name=address_name, address_domain=address_domain)
|
||||
# self.addCleanup(self.delete, name)
|
||||
# Mailman doesn't support changing the address, only the domain
|
||||
address_name = '%s_name' % random_ascii(10)
|
||||
self.update_address_name(name, address_name)
|
||||
self.validate_add(name, address="%s@%s" % (address_name, address_domain))
|
||||
|
||||
def test_delete(self):
|
||||
name = '%s_list' % random_ascii(10)
|
||||
password = '@!?%spppP001' % random_ascii(5)
|
||||
admin_email = 'root@test3.orchestra.lan'
|
||||
address_name = '%s_name' % random_ascii(10)
|
||||
domain_name = '%sdomain.lan' % random_ascii(10)
|
||||
address_domain = Domain.objects.create(name=domain_name, account=self.account)
|
||||
self.add(name, password, admin_email, address_name=address_name, address_domain=address_domain)
|
||||
# Mailman doesn't support changing the address, only the domain
|
||||
self.validate_add(name, address="%s@%s" % (address_name, address_domain))
|
||||
self.delete(name)
|
||||
self.assertRaises(AssertionError, self.validate_login, name, password)
|
||||
self.validate_delete(name)
|
||||
|
||||
|
||||
class RESTListMixin(ListMixin):
|
||||
|
@ -101,8 +180,23 @@ class RESTListMixin(ListMixin):
|
|||
|
||||
@save_response_on_error
|
||||
def delete(self, name):
|
||||
list = self.rest.lists.retrieve(name=name).get()
|
||||
list.delete()
|
||||
self.rest.lists.retrieve(name=name).delete()
|
||||
|
||||
@save_response_on_error
|
||||
def change_password(self, name, password):
|
||||
mail_list = self.rest.lists.retrieve(name=name).get()
|
||||
mail_list.set_password(password)
|
||||
|
||||
@save_response_on_error
|
||||
def update_domain(self, name, domain_name):
|
||||
mail_list = self.rest.lists.retrieve(name=name).get()
|
||||
domain = self.rest.domains.retrieve(name=domain_name).get()
|
||||
mail_list.update(address_domain=domain.url)
|
||||
|
||||
@save_response_on_error
|
||||
def update_address_name(self, name, address_name):
|
||||
mail_list = self.rest.lists.retrieve(name=name).get()
|
||||
mail_list.update(address_name=address_name)
|
||||
|
||||
|
||||
class AdminListMixin(ListMixin):
|
||||
|
@ -111,48 +205,76 @@ class AdminListMixin(ListMixin):
|
|||
self.admin_login()
|
||||
|
||||
@snapshot_on_error
|
||||
def add(self, name, password, admin_email):
|
||||
url = self.live_server_url + reverse('admin:mails_List_add')
|
||||
def add(self, name, password, admin_email, address_name=None, address_domain=None):
|
||||
url = self.live_server_url + reverse('admin:lists_list_add')
|
||||
self.selenium.get(url)
|
||||
|
||||
account_input = self.selenium.find_element_by_id('id_account')
|
||||
account_select = Select(account_input)
|
||||
account_select.select_by_value(str(self.account.pk))
|
||||
|
||||
name_field = self.selenium.find_element_by_id('id_name')
|
||||
name_field.send_keys(username)
|
||||
name_field.send_keys(name)
|
||||
|
||||
password_field = self.selenium.find_element_by_id('id_password1')
|
||||
password_field.send_keys(password)
|
||||
password_field = self.selenium.find_element_by_id('id_password2')
|
||||
password_field.send_keys(password)
|
||||
|
||||
if quota is not None:
|
||||
quota_id = 'id_resources-resourcedata-content_type-object_id-0-allocated'
|
||||
quota_field = self.selenium.find_element_by_id(quota_id)
|
||||
quota_field.clear()
|
||||
quota_field.send_keys(quota)
|
||||
admin_email_field = self.selenium.find_element_by_id('id_admin_email')
|
||||
admin_email_field.send_keys(admin_email)
|
||||
|
||||
if filtering is not None:
|
||||
filtering_input = self.selenium.find_element_by_id('id_filtering')
|
||||
filtering_select = Select(filtering_input)
|
||||
filtering_select.select_by_value("CUSTOM")
|
||||
filtering_inline = self.selenium.find_element_by_id('fieldsetcollapser0')
|
||||
filtering_inline.click()
|
||||
time.sleep(0.5)
|
||||
filtering_field = self.selenium.find_element_by_id('id_custom_filtering')
|
||||
filtering_field.send_keys(filtering)
|
||||
if address_name:
|
||||
address_name_field = self.selenium.find_element_by_id('id_address_name')
|
||||
address_name_field.send_keys(address_name)
|
||||
|
||||
domain = Domain.objects.get(name=address_domain)
|
||||
domain_input = self.selenium.find_element_by_id('id_address_domain')
|
||||
domain_select = Select(domain_input)
|
||||
domain_select.select_by_value(str(domain.pk))
|
||||
|
||||
name_field.submit()
|
||||
self.assertNotEqual(url, self.selenium.current_url)
|
||||
|
||||
@snapshot_on_error
|
||||
def delete(self, name):
|
||||
mail_list = List.objects.get(name=name)
|
||||
self.admin_delete(mail_list)
|
||||
|
||||
@snapshot_on_error
|
||||
def change_password(self, name, password):
|
||||
mail_list = List.objects.get(name=name)
|
||||
self.admin_change_password(mail_list, password)
|
||||
|
||||
@snapshot_on_error
|
||||
def update_domain(self, name, domain_name):
|
||||
mail_list = List.objects.get(name=name)
|
||||
url = self.live_server_url + change_url(mail_list)
|
||||
self.selenium.get(url)
|
||||
|
||||
domain = Domain.objects.get(name=domain_name)
|
||||
domain_input = self.selenium.find_element_by_id('id_address_domain')
|
||||
domain_select = Select(domain_input)
|
||||
domain_select.select_by_value(str(domain.pk))
|
||||
|
||||
save = self.selenium.find_element_by_name('_save')
|
||||
save.submit()
|
||||
self.assertNotEqual(url, self.selenium.current_url)
|
||||
|
||||
@snapshot_on_error
|
||||
def update_address_name(self, name, address_name):
|
||||
mail_list = List.objects.get(name=name)
|
||||
url = self.live_server_url + change_url(mail_list)
|
||||
self.selenium.get(url)
|
||||
|
||||
address_name_field = self.selenium.find_element_by_id('id_address_name')
|
||||
address_name_field.clear()
|
||||
address_name_field.send_keys(address_name)
|
||||
|
||||
save = self.selenium.find_element_by_name('_save')
|
||||
save.submit()
|
||||
self.assertNotEqual(url, self.selenium.current_url)
|
||||
|
||||
|
||||
class RESTListTest(RESTListMixin, BaseLiveServerTestCase):
|
||||
pass
|
||||
|
||||
|
||||
#class AdminListTest(AdminListMixin, BaseLiveServerTestCase):
|
||||
# pass
|
||||
|
||||
|
||||
|
||||
class AdminListTest(AdminListMixin, BaseLiveServerTestCase):
|
||||
pass
|
||||
|
|
|
@ -233,6 +233,9 @@ class MailboxMixin(object):
|
|||
sshrun(self.MASTER_SERVER,
|
||||
"grep '%s' %s/Maildir/.%s/new/*" % (token, home, folder), display=False)
|
||||
|
||||
# TODO test update shit
|
||||
# TODO test autoreply
|
||||
|
||||
|
||||
class RESTMailboxMixin(MailboxMixin):
|
||||
def setUp(self):
|
||||
|
|
|
@ -24,6 +24,8 @@ def BashSSH(backend, log, server, cmds):
|
|||
log.script = script
|
||||
log.save(update_fields=['script'])
|
||||
logger.debug('%s is going to be executed on %s' % (backend, server))
|
||||
channel = None
|
||||
ssh = None
|
||||
try:
|
||||
# Avoid "Argument list too long" on large scripts by genereting a file
|
||||
# and scping it to the remote server
|
||||
|
@ -93,8 +95,10 @@ def BashSSH(backend, log, server, cmds):
|
|||
logger.debug(log.traceback)
|
||||
log.save()
|
||||
finally:
|
||||
channel.close()
|
||||
ssh.close()
|
||||
if channel is not None:
|
||||
channel.close()
|
||||
if ssh is not None:
|
||||
ssh.close()
|
||||
|
||||
|
||||
def Python(backend, log, server, cmds):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import copy
|
||||
from threading import local
|
||||
|
||||
from django.core.urlresolvers import resolve
|
||||
|
@ -16,12 +15,12 @@ from .models import BackendOperation as Operation
|
|||
|
||||
@receiver(post_save, dispatch_uid='orchestration.post_save_collector')
|
||||
def post_save_collector(sender, *args, **kwargs):
|
||||
if sender != BackendLog:
|
||||
if sender not in [BackendLog, Operation]:
|
||||
OperationsMiddleware.collect(Operation.SAVE, **kwargs)
|
||||
|
||||
@receiver(pre_delete, dispatch_uid='orchestration.pre_delete_collector')
|
||||
def pre_delete_collector(sender, *args, **kwargs):
|
||||
if sender != BackendLog:
|
||||
if sender not in [BackendLog, Operation]:
|
||||
OperationsMiddleware.collect(Operation.DELETE, **kwargs)
|
||||
|
||||
|
||||
|
@ -49,7 +48,6 @@ class OperationsMiddleware(object):
|
|||
request = getattr(cls.thread_locals, 'request', None)
|
||||
if request is None:
|
||||
return
|
||||
good_action = action
|
||||
pending_operations = cls.get_pending_operations()
|
||||
for backend in ServiceBackend.get_backends():
|
||||
instance = None
|
||||
|
@ -84,15 +82,13 @@ class OperationsMiddleware(object):
|
|||
break
|
||||
if not execute:
|
||||
continue
|
||||
instance = copy.copy(instance)
|
||||
good = instance
|
||||
operation = Operation.create(backend, instance, action)
|
||||
if action != Operation.DELETE:
|
||||
# usually we expect to be using last object state,
|
||||
# except when we are deleting it
|
||||
pending_operations.discard(operation)
|
||||
pending_operations.add(operation)
|
||||
|
||||
|
||||
def process_request(self, request):
|
||||
""" Store request on a thread local variable """
|
||||
type(self).thread_locals.request = request
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import copy
|
||||
import socket
|
||||
|
||||
from django.contrib.contenttypes import generic
|
||||
|
@ -124,6 +125,9 @@ class BackendOperation(models.Model):
|
|||
def create(cls, backend, instance, action):
|
||||
op = cls(backend=backend.get_name(), instance=instance, action=action)
|
||||
op.backend = backend
|
||||
# instance should maintain any dynamic attribute until backend execution
|
||||
# deep copy is prefered over copy otherwise objects will share same atributes (queryset cache)
|
||||
op.instance = copy.deepcopy(instance)
|
||||
return op
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -10,6 +10,7 @@ from django.core.management.base import CommandError
|
|||
from django.core.urlresolvers import reverse
|
||||
from selenium.webdriver.support.select import Select
|
||||
|
||||
from orchestra.admin.utils import change_url
|
||||
from orchestra.apps.accounts.models import Account
|
||||
from orchestra.apps.orchestration.models import Server, Route
|
||||
from orchestra.utils.system import run, sshrun
|
||||
|
@ -268,8 +269,7 @@ class AdminSystemUserMixin(SystemUserMixin):
|
|||
@snapshot_on_error
|
||||
def add_group(self, username, groupname):
|
||||
user = SystemUser.objects.get(username=username)
|
||||
change = reverse('admin:systemusers_systemuser_change', args=(user.pk,))
|
||||
url = self.live_server_url + change
|
||||
url = self.live_server_url + change_url(user)
|
||||
self.selenium.get(url)
|
||||
groups = self.selenium.find_element_by_id('id_groups_add_all_link')
|
||||
groups.click()
|
||||
|
@ -281,8 +281,7 @@ class AdminSystemUserMixin(SystemUserMixin):
|
|||
@snapshot_on_error
|
||||
def save(self, username):
|
||||
user = SystemUser.objects.get(username=username)
|
||||
change = reverse('admin:systemusers_systemuser_change', args=(user.pk,))
|
||||
url = self.live_server_url + change
|
||||
url = self.live_server_url + change_url(user)
|
||||
self.selenium.get(url)
|
||||
save = self.selenium.find_element_by_name('_save')
|
||||
save.submit()
|
||||
|
@ -367,3 +366,10 @@ class AdminSystemUserTest(AdminSystemUserMixin, BaseLiveServerTestCase):
|
|||
self.assertNotEqual(url, self.selenium.current_url)
|
||||
|
||||
self.assertRaises(ftplib.error_perm, self.validate_ftp, username, password)
|
||||
self.selenium.get(url)
|
||||
self.assertNotEqual(url, self.selenium.current_url)
|
||||
|
||||
# Reenable for test cleanup
|
||||
self.account.is_active = True
|
||||
self.account.save()
|
||||
# self.admin_login()
|
||||
|
|
|
@ -79,10 +79,7 @@ class RESTWebsiteMixin(RESTWebAppMixin):
|
|||
|
||||
@save_response_on_error
|
||||
def delete_website(self, name):
|
||||
print 'hola'
|
||||
pass
|
||||
self.rest.websites.retrieve(name=name).delete()
|
||||
# self.rest.websites.retrieve(name=name).delete()
|
||||
|
||||
@save_response_on_error
|
||||
def add_content(self, website, webapp, path):
|
||||
|
@ -94,6 +91,12 @@ class RESTWebsiteMixin(RESTWebAppMixin):
|
|||
})
|
||||
website.save()
|
||||
|
||||
# TODO test disable
|
||||
# TODO test https (refactor ssl)
|
||||
# TODO test php options
|
||||
# TODO read php-version /fpm/fcgid
|
||||
# TODO max_processes, timeouts, memory...
|
||||
|
||||
|
||||
class StaticRESTWebsiteTest(RESTWebsiteMixin, StaticWebAppMixin, WebsiteMixin, BaseLiveServerTestCase):
|
||||
def test_mix_webapps(self):
|
||||
|
|
|
@ -168,7 +168,8 @@ function install_requirements () {
|
|||
orchestra-orm==dev \
|
||||
django-debug-toolbar==1.2.1 \
|
||||
django-nose==1.2 \
|
||||
sqlparse"
|
||||
sqlparse
|
||||
requests"
|
||||
fi
|
||||
|
||||
# Make sure locales are in place before installing postgres
|
||||
|
|
|
@ -46,3 +46,9 @@ sed -i "s/DEFAULT_EMAIL_HOST\s*=\s*.*/DEFAULT_EMAIL_HOST = 'lists.orchestra.lan'
|
|||
sed -i "s/DEFAULT_URL_HOST\s*=\s*.*/DEFAULT_URL_HOST = 'lists.orchestra.lan'/" /etc/mailman/mm_cfg.py
|
||||
|
||||
|
||||
# apache
|
||||
cp /etc/mailman/apache.conf /etc/apache2/sites-available/mailman.conf
|
||||
a2ensite mailman.conf
|
||||
/etc/init.d/apache2 restart
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue