[Stash] Test case 通不过,import error

pull/828/merge
ibuler 2017-12-08 10:15:27 +08:00
parent 27a1849b1d
commit 18fd04d63c
21 changed files with 113 additions and 237 deletions

2
apps/assets/models.py Normal file
View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
#

View File

@ -1,9 +1,10 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
print("Import assets model")
from .user import AdminUser, SystemUser
from .cluster import *
from .user import *
from .group import *
from .asset import *
from .utils import *

View File

@ -2,15 +2,15 @@
# -*- coding: utf-8 -*-
#
from __future__ import unicode_literals
import uuid
from django.db import models
import logging
from django.utils.translation import ugettext_lazy as _
from . import Cluster, AssetGroup, AdminUser, SystemUser
from .cluster import Cluster
from .group import AssetGroup
from .user import AdminUser, SystemUser
__all__ = ['Asset']
logger = logging.getLogger(__name__)

View File

@ -10,7 +10,7 @@ from django.db import models
import logging
from django.utils.translation import ugettext_lazy as _
from . import SystemUser
from .user import SystemUser
__all__ = ['AssetGroup']
logger = logging.getLogger(__name__)

View File

@ -321,7 +321,7 @@ $(document).ready(function () {
var body = {};
var success = function() {
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
window.location.href="{% url 'assets:idc-list' %}";
window.location.href="{% url 'assets:cluster-list' %}";
};
var fail = function() {
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");

View File

@ -25,7 +25,7 @@
<div class="hr-line-dashed"></div>
<h3>{% trans 'Group' %}</h3>
{% bootstrap_field form.idc layout="horizontal" %}
{% bootstrap_field form.cluster layout="horizontal" %}
{% bootstrap_field form.groups layout="horizontal" %}
<div class="hr-line-dashed"></div>

View File

@ -7,15 +7,15 @@
{% block table_search %}{% endblock %}
{% block table_container %}
<div class="uc pull-left m-l-5 m-r-5">
<a href="{% url "assets:idc-create" %}" class="btn btn-sm btn-primary"> {% trans "Create Cluster" %} </a>
<a href="{% url "assets:cluster-create" %}" class="btn btn-sm btn-primary"> {% trans "Create Cluster" %} </a>
</div>
<table class="table table-striped table-bordered table-hover " id="idc_list_table" >
<table class="table table-striped table-bordered table-hover " id="cluster_list_table" >
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center"><a href="{% url 'assets:idc-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center"><a href="{% url 'assets:cluster-list' %}?sort=name">{% trans 'Name' %}</a></th>
<th class="text-center">{% trans 'Asset num' %}</th>
<th class="text-center">{% trans 'Contact' %}</th>
<th class="text-center">{% trans 'Phone' %}</th>
@ -44,19 +44,19 @@
<script>
$(document).ready(function(){
var options = {
ele: $('#idc_list_table'),
ele: $('#cluster_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "assets:idc-detail" pk=99991937 %}">' + cellData + '</a>';
var detail_btn = '<a href="{% url "assets:cluster-detail" pk=99991937 %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('99991937', rowData.id));
}},
{targets: 6, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:idc-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_idc_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
var update_btn = '<a href="{% url "assets:cluster-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_cluster_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
$(td).html(update_btn + del_btn)
}}],
ajax_url: '{% url "api-assets:idc-list" %}',
ajax_url: '{% url "api-assets:cluster-list" %}',
columns: [{data: function(){return ""}}, {data: "name" }, {data: "assets_amount" }, {data: "contact" }, {data: "phone" },
{data: "operator" }, {data: "id" }],
op_html: $('#actions').html()
@ -64,12 +64,12 @@ $(document).ready(function(){
jumpserver.initDataTable(options);
})
.on('click', '.btn_idc_delete', function () {
.on('click', '.btn_cluster_delete', function () {
var $this = $(this);
var $data_table = $('#idc_list_table').DataTable();
var $data_table = $('#cluster_list_table').DataTable();
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
var uid = $this.data('uid');
var the_url = '{% url "api-assets:idc-detail" pk=99991937 %}'.replace('99991937', uid);
var the_url = '{% url "api-assets:cluster-detail" pk=99991937 %}'.replace('99991937', uid);
objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload();
@ -78,7 +78,7 @@ $(document).ready(function(){
.on('click', '#btn_bulk_update', function () {
var action = $('#slct_bulk_update').val();
var $data_table = $('#idc_list_table').DataTable();
var $data_table = $('#cluster_list_table').DataTable();
var id_list = [];
var plain_id_list = [];
$data_table.rows({selected: true}).every(function(){
@ -88,11 +88,11 @@ $(document).ready(function(){
if (id_list === []) {
return false;
}
var the_url = "{% url 'api-assets:idc-list' %}";
var the_url = "{% url 'api-assets:cluster-list' %}";
function doDelete() {
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will delete the selected idc' %}",
text: "{% trans 'This will delete the selected cluster' %}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
@ -102,7 +102,7 @@ $(document).ready(function(){
var success = function() {
var msg = "{% trans 'Cluster Deleted.' %}";
swal("{% trans 'Cluster Delete' %}", msg, "success");
$('#idc_list_table').DataTable().ajax.reload();
$('#cluster_list_table').DataTable().ajax.reload();
};
var fail = function() {
var msg = "{% trans 'Cluster Deleting failed.' %}";

View File

@ -30,11 +30,12 @@ from ..hands import AdminUserRequiredMixin
from ..tasks import update_assets_hardware_info
__all__ = ['AssetListView', 'AssetCreateView', 'AssetUpdateView',
'UserAssetListView', 'AssetBulkUpdateView', 'AssetDetailView',
'AssetModalListView', 'AssetDeleteView', 'AssetExportView',
'BulkImportAssetView',
]
__all__ = [
'AssetListView', 'AssetCreateView', 'AssetUpdateView',
'UserAssetListView', 'AssetBulkUpdateView', 'AssetDetailView',
'AssetModalListView', 'AssetDeleteView', 'AssetExportView',
'BulkImportAssetView',
]
class AssetListView(AdminUserRequiredMixin, TemplateView):
@ -282,7 +283,7 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
asset = get_object_or_none(Asset, id=id_)
for k, v in asset_dict.items():
if k == 'idc':
if k == 'cluster':
v = get_object_or_none(Cluster, name=v)
elif k == 'is_active':
v = bool(v)

View File

@ -1108,7 +1108,7 @@ msgid "Create Cluster"
msgstr "创建Cluster"
#: assets/templates/assets/idc_list.html:95
msgid "This will delete the selected idc"
msgid "This will delete the selected cluster"
msgstr "删除选择Cluster"
#: assets/templates/assets/idc_list.html:103

View File

@ -18,7 +18,8 @@ class AdHoc(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, blank=True, verbose_name=_('Name'))
is_deleted = models.BooleanField(default=False)
date_create = models.DateTimeField(auto_created=True)
created_by = models.CharField(max_length=128, blank=True, default='')
date_create = models.DateTimeField(auto_now_add=True)
@property
def short_id(self):
@ -45,7 +46,7 @@ class AdHocData(models.Model):
_become_pass = models.CharField(default='', max_length=128)
pattern = models.CharField(max_length=64, default='', verbose_name=_('Pattern'))
created_by = models.CharField(max_length=64, verbose_name=_('Create by'))
date_created = models.DateTimeField(auto_created=True)
date_created = models.DateTimeField(auto_now_add=True)
@property
def tasks(self):

34
apps/ops/test_utils.py Normal file
View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
#
import sys
import os
from django.test import TestCase
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
from ops.models import AdHoc, AdHocData
from ops.utils import run_adhoc
class TestRunAdHoc(TestCase):
def setUp(self):
adhoc = AdHoc(name="Test run adhoc")
adhoc.save()
self.data = AdHocData(subject=adhoc, run_as_admin=True, pattern='all')
self.data.tasks = [
{'name': 'run ls', 'action': {'module': 'shell', 'args': 'ls'}},
{'name': 'echo ', 'action': {'module': 'shell', 'args': 'echo 123'}},
]
self.data.hosts = [
"testserver"
]
def test_run(self):
pass

View File

@ -1,16 +1,13 @@
# ~*~ coding: utf-8 ~*~
from __future__ import absolute_import, unicode_literals
import json
import re
import time
import uuid
import time
from django.utils import timezone
from common.utils import get_logger, get_object_or_none
from .ansible import AdHocRunner
from .ansible.exceptions import AnsibleError
from .models import AdHocRunHistory
from assets.utils import get_assets_by_hostname_list
logger = get_logger(__file__)
@ -82,16 +79,43 @@ def hosts_add_become(hosts, adhoc_data):
return hosts
def run_adhoc(adhoc_data, forks=10):
tasks = adhoc_data.tasks
def run_adhoc(adhoc_data, **options):
"""
:param adhoc_data: Instance of AdHocData
:param options: ansible support option, like forks ...
:return:
"""
name = adhoc_data.subject.name
hostname_list = adhoc_data.hosts
adhoc_name = adhoc_data.subject.name
if adhoc_data.run_as_admin:
hosts = get_hosts_with_admin(adhoc_data.hosts)
hosts = get_hosts_with_admin(hostname_list)
else:
hosts = get_hosts_with_run_user(hostname_list, adhoc_data.run_as)
hosts_add_become(hosts, adhoc_data) # admin user 自带become
runner = AdHocRunner(hosts)
runner.set_option('forks', forks)
for k, v in options:
runner.set_option(k, v)
record = AdHocRunHistory(adhoc=adhoc_data)
time_start = time.time()
try:
result = runner.run(adhoc_data.tasks, adhoc_data.pattern, name)
record.is_finished = True
if result.results_summary.get('dark'):
record.is_success = False
else:
record.is_success = True
record.result = result.results_raw
record.summary = result.results_summary
return result
except AnsibleError as e:
logger.error("Failed run adhoc {}, {}".format(name, e))
raise
finally:
record.date_finished = timezone.now()
record.timedelta = time.time() - time_start
record.save()

View File

@ -1,18 +1,15 @@
from __future__ import unicode_literals, absolute_import
import functools
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.db.models.signals import m2m_changed
from users.models import User, UserGroup
from assets.models import Asset, AssetGroup, SystemUser
from common.utils import date_expired_default, combine_seq
class AssetPermission(models.Model):
from users.models import User, UserGroup
from assets.models import Asset, AssetGroup, SystemUser
# PRIVATE_FOR_CHOICE = (
# ('N', 'None'),
# ('U', 'user'),

View File

@ -6,7 +6,7 @@ import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
from rest_framework.authtoken.models import Token
from . import User
from .user import User
__all__ = ['AccessKey', 'PrivateToken', 'LoginLog']

View File

@ -14,7 +14,7 @@ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.shortcuts import reverse
from . import UserGroup
from .group import UserGroup
from common.utils import signer, date_expired_default

View File

@ -2,7 +2,8 @@
# -*- coding: utf-8 -*-
#
from . import User, UserGroup
from .user import User
from .group import UserGroup
def init_model():

View File

@ -1,24 +0,0 @@
# ~*~ coding: utf-8 ~*~
from random import choice
import forgery_py
from users.models import User, UserGroup, init_all_models
def gen_username():
return forgery_py.internet.user_name(True)
def gen_email():
return forgery_py.internet.email_address()
def gen_name():
return forgery_py.name.full_name()
def get_role():
role = choice(dict(User.ROLE_CHOICES).keys())
return role

View File

@ -1,95 +0,0 @@
# ~*~ coding: utf-8 ~*~
from django.utils import timezone
from django.shortcuts import reverse
from django.test import TestCase, TransactionTestCase
from django.db import IntegrityError
from users.models import User, UserGroup, init_all_models
from django.contrib.auth.models import Permission
from .base import gen_name, gen_username, gen_email, get_role
class UserModelTest(TransactionTestCase):
def setUp(self):
init_all_models()
# 创建一个用户用于测试
role = get_role()
user = User(name='test', username='test', email='test@email.org', role=role)
user.save()
def test_initial(self):
self.assertEqual(User.objects.all().count(), 2)
@property
def role(self):
return get_role()
# 创建一个姓名一致的用户, 应该创建成功
def test_user_name_duplicate(self):
user1 = User(name='test', username=gen_username(), password_raw=gen_username(),
email=gen_email())
try:
user1.save()
user1.delete()
except IntegrityError:
self.assertTrue(0, 'Duplicate <name> not allowed.')
# 创建一个用户名一致的用户, 应该创建不成功
def test_user_username_duplicate(self):
user2 = User(username='test', email=gen_email(), role=self.role)
with self.assertRaises(IntegrityError):
user2.save()
# 创建一个Email一致的用户,应该创建不成功
def test_user_email_duplicate(self):
user3 = User(username=gen_username(), email='test@email.org', role=self.role)
with self.assertRaises(IntegrityError):
user3.save()
# 用户过期测试
def test_user_was_expired(self):
date = timezone.now() - timezone.timedelta(days=1)
user = User(name=gen_name(), username=gen_username(),
email=gen_email(), role=self.role, date_expired=date)
self.assertTrue(user.is_expired)
# 测试用户默认会输入All用户组
def test_user_with_default_group(self):
role = get_role()
user = User(username=gen_username(), email=gen_email(), role=role)
user.save()
self.assertEqual(user.groups.count(), 1)
self.assertEqual(user.groups.first().name, 'Default')
def test_user_password_authenticated(self):
password = gen_username() * 3
user = User(username=gen_username(), password_raw=password, role=self.role)
user.save()
self.assertTrue(user.check_password(password))
self.assertFalse(user.check_password(password*2))
def test_user_reset_password(self):
user = User.objects.first()
token = User.generate_reset_token(user.email)
new_password = gen_username()
User.reset_password(token, new_password)
user_ = User.objects.get(id=user.id)
self.assertTrue(user_.check_password(new_password))
def tearDown(self):
User.objects.all().delete()
UserGroup.objects.all().delete()
class UserGroupModelTestCase(TransactionTestCase):
pass

View File

@ -1,66 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from users.models import User, UserGroup, init_all_models
from django.shortcuts import reverse
from django.test import TestCase, Client, TransactionTestCase
from .base import gen_username, gen_name, gen_email, get_role
class UserListViewTests(TransactionTestCase):
def setUp(self):
init_all_models()
self.client.login(username='admin', password='admin')
def test_a_new_user_in_list(self):
username = gen_username()
user = User(username=username, email=gen_email(), role=get_role())
user.save()
response = self.client.get(reverse('users:user-list'))
self.assertContains(response, username)
def test_list_view_with_admin_user(self):
response = self.client.get(reverse('users:user-list'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Admin')
self.assertEqual(response.context['user_list'].count(), User.objects.all().count())
def test_pagination(self):
User.generate_fake(count=20)
response = self.client.get(reverse('users:user-list'))
self.assertEqual(response.context['is_paginated'], True)
def tearDown(self):
self.client.logout()
class UserAddTests(TestCase):
def setUp(self):
init_all_models()
self.client.login(username='admin', password='admin')
def test_add_a_new_user(self):
username = gen_username()
data = {
'username': username,
'comment': '',
'name': gen_name(),
'email': gen_email(),
'groups': [UserGroup.objects.first().id, ],
'role': get_role(),
'date_expired': '2086-08-06 19:12:22',
}
response = self.client.post(reverse('users:user-create'), data)
self.assertEqual(response.status_code, 302)
self.assertEqual(response['location'], reverse('users:user-list'))
response = self.client.get(reverse('users:user-list'))
self.assertContains(response, username)
def tearDown(self):
self.client.logout()