Skip to content

Commit 6b063db

Browse files
author
Elias Nygren
authored
Merge pull request #23 from UpCloudLtd/0.3.6-devel
merge 0.3.6 devel into master
2 parents 99f48b3 + 7248b22 commit 6b063db

32 files changed

+2032
-2017
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.gitignore
12
__pycache__
23
ENV/
34
.DS_Store
@@ -9,7 +10,10 @@ dist/
910
*.sublime-workspace
1011
docs/html/
1112
.tox
13+
.cache
1214

1315
# pyenv
1416
.python-version
1517

18+
# local
19+
.test-snippets

circle.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
machine:
2+
python:
3+
# we want to run integration tests with 2.7.x
4+
# as it's the most important one due to Ansible
5+
version: 2.7.11
6+
7+
dependencies:
8+
override:
9+
- pip install tox tox-pyenv
10+
- pyenv install 2.6.9
11+
- pyenv local 2.6.9 2.7.11 3.3.6 3.4.4 3.5.1
12+
13+
test:
14+
override:
15+
- tox
16+
- tox -e py27 -- -x --integration-tests

requirements-dev.txt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1-
pytest==2.6.4
2-
py==1.4.26
1+
pytest>=2.9.2
2+
py>=1.4.26
3+
mock>=1.0.1
4+
responses>=0.3.0
5+
6+
# flake8
7+
flake8>=2.6.2
8+
flake8-docstrings>=0.2.8
9+
hacking>=0.11.0

requirements.txt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
1-
future==0.14.3
2-
mock==1.0.1
3-
requests==2.6.0
4-
responses==0.3.0
5-
six==1.9.0
6-
wheel==0.24.0
1+
requests>=2.6.0
2+
six>=1.9.0

test/conftest.py

Lines changed: 69 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,21 @@
33
from __future__ import division
44
from __future__ import absolute_import
55
from builtins import object, open
6-
from future import standard_library
7-
standard_library.install_aliases()
6+
import json
7+
import os
8+
import pytest
9+
import responses
10+
import sys
11+
12+
13+
# make files under helpers available for import
14+
HELPERS_PATH = os.path.join(os.path.dirname(__file__), 'helpers')
15+
sys.path.append(HELPERS_PATH)
16+
17+
18+
def pytest_addoption(parser):
19+
parser.addoption('--integration-tests', action='store_true', help='run integration tests')
820

9-
import json, os, pytest, responses
1021

1122
@pytest.fixture(scope='module')
1223
def manager():
@@ -15,80 +26,76 @@ def manager():
1526

1627

1728
class Mock(object):
18-
base_url = 'https://api.upcloud.com/1.2'
19-
20-
@staticmethod
21-
def read_from_file(filename):
22-
23-
filename = filename.replace("/", "_")
24-
25-
cwd = os.path.dirname(__file__)
26-
f = open(cwd + '/json_data/'+filename, 'r')
27-
return f.read()
29+
base_url = 'https://api.upcloud.com/1.2'
2830

29-
@staticmethod
30-
def mock_get(target, response_file=None):
31-
if not response_file:
32-
response_file = target + '.json'
31+
@staticmethod
32+
def read_from_file(filename):
3333

34-
data = Mock.read_from_file(response_file)
35-
responses.add(responses.GET, Mock.base_url + '/' + target,
36-
body=data,
37-
status=200,
38-
content_type='application/json')
39-
return data
34+
filename = filename.replace("/", "_")
4035

41-
@staticmethod
42-
def __put_post_callback(request, target, data):
43-
data_field = target.split("/")[0]
44-
payload = json.loads(request.body)
36+
cwd = os.path.dirname(__file__)
37+
f = open(cwd + '/json_data/'+filename, 'r')
38+
return f.read()
4539

46-
for field in data[data_field]:
47-
if field in payload[data_field]:
48-
data[data_field][field] = payload[data_field][field]
49-
return(200, {}, json.dumps(data))
40+
@staticmethod
41+
def mock_get(target, response_file=None):
42+
if not response_file:
43+
response_file = target + '.json'
5044

51-
@staticmethod
52-
def mock_post(target):
53-
data = json.loads( Mock.read_from_file(target + '_post.json') )
45+
data = Mock.read_from_file(response_file)
46+
responses.add(responses.GET, Mock.base_url + '/' + target,
47+
body=data,
48+
status=200,
49+
content_type='application/json')
50+
return data
5451

55-
def callback(request):
56-
return Mock.__put_post_callback(request, target, data)
52+
@staticmethod
53+
def __put_post_callback(request, target, data):
54+
data_field = target.split("/")[0]
55+
payload = json.loads(request.body)
5756

58-
responses.add_callback(responses.POST, Mock.base_url + '/' + target,
59-
callback=callback,
60-
content_type='application/json')
57+
for field in data[data_field]:
58+
if field in payload[data_field]:
59+
data[data_field][field] = payload[data_field][field]
60+
return(200, {}, json.dumps(data))
6161

62-
@staticmethod
63-
def mock_put(target):
64-
data = json.loads( Mock.read_from_file(target + '.json') )
62+
@staticmethod
63+
def mock_post(target):
64+
data = json.loads(Mock.read_from_file(target + '_post.json'))
6565

66-
def callback(request):
67-
return Mock.__put_post_callback(request, target, data)
66+
def callback(request):
67+
return Mock.__put_post_callback(request, target, data)
6868

69-
responses.add_callback(responses.PUT, Mock.base_url + '/' + target,
70-
callback=callback,
71-
content_type='application/json')
72-
@staticmethod
73-
def mock_delete(target):
74-
# print(Mock.base_url + "/" + target)
75-
responses.add(responses.DELETE, Mock.base_url + "/" + target,
76-
status = 204 )
69+
responses.add_callback(responses.POST, Mock.base_url + '/' + target,
70+
callback=callback,
71+
content_type='application/json')
7772

78-
@staticmethod
79-
def mock_server_operation(target):
80-
# drop third (last) part of a string divided by two slashes ("/"); e.g "this/is/string" -> "this/is"
81-
targetsplit = target.split("/")
82-
targetfile = "/".join( targetsplit[:2] )
73+
@staticmethod
74+
def mock_put(target):
75+
data = json.loads(Mock.read_from_file(target + '.json'))
8376

84-
data = json.loads( Mock.read_from_file(targetfile + '.json') )
77+
def callback(request):
78+
return Mock.__put_post_callback(request, target, data)
8579

86-
# API will always respond state: "started", see: Server.stop, Server.start, Server,restart
87-
data["server"]["state"] = "started"
80+
responses.add_callback(responses.PUT, Mock.base_url + '/' + target,
81+
callback=callback,
82+
content_type='application/json')
8883

89-
data = json.dumps( data )
90-
responses.add(responses.POST, Mock.base_url + "/" + target, status=200, body = data, content_type='application/json')
84+
@staticmethod
85+
def mock_delete(target):
86+
responses.add(responses.DELETE, Mock.base_url + '/' + target,
87+
status=204)
9188

89+
@staticmethod
90+
def mock_server_operation(target):
91+
# drop third (last) part of a string divided by two slashes ("/"); e.g "this/is/string" -> "this/is"
92+
targetsplit = target.split('/')
93+
targetfile = '/'.join( targetsplit[:2] )
9294

95+
data = json.loads( Mock.read_from_file(targetfile + '.json') )
9396

97+
# API will always respond state: "started", see: Server.stop, Server.start, Server,restart
98+
data['server']['state'] = 'started'
9499

100+
data = json.dumps( data )
101+
responses.add(responses.POST, Mock.base_url + "/" + target, status=200, body = data, content_type='application/json')

test/helpers/infra.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
from __future__ import print_function
2+
from __future__ import unicode_literals
3+
from __future__ import division
4+
from __future__ import absolute_import
5+
6+
from upcloud_api import CloudManager, Storage, FirewallRule, ZONE, Tag
7+
from upcloud_api.server import Server, login_user_block
8+
9+
10+
CLUSTER = {
11+
'web1': Server(
12+
core_number=1,
13+
memory_amount=512,
14+
hostname='web1.example.com',
15+
zone=ZONE.London,
16+
password_delivery='none',
17+
storage_devices=[
18+
Storage(os='Ubuntu 14.04', size=10),
19+
Storage(size=10, tier='maxiops')
20+
]),
21+
22+
'web2': Server(
23+
core_number=1,
24+
memory_amount=512,
25+
hostname='web2.example.com',
26+
zone=ZONE.London,
27+
password_delivery='none',
28+
storage_devices=[
29+
Storage(os='Ubuntu 14.04', size=10),
30+
Storage(size=10, tier='maxiops'),
31+
]),
32+
33+
'db': Server(
34+
core_number=1,
35+
memory_amount=512,
36+
hostname='db.example.com',
37+
zone=ZONE.London,
38+
password_delivery='none',
39+
storage_devices=[
40+
Storage(os='CentOS 7.0', size=10),
41+
Storage(size=10),
42+
],
43+
login_user=login_user_block('testuser', ['ssh-rsa AAAAB3NzaC1yc2EAA[...]ptshi44x [email protected]'], True),
44+
),
45+
46+
47+
'lb': Server(
48+
plan= '1xCPU-1GB',
49+
hostname='balancer.example.com',
50+
zone=ZONE.London,
51+
password_delivery='none',
52+
storage_devices=[
53+
Storage(os='Debian 7.8', size=30)
54+
],
55+
login_user=login_user_block('testuser', ['ssh-rsa AAAAB3NzaC1yc2EAA[...]ptshi44x [email protected]'], True),
56+
)
57+
}
58+
59+
60+
FIREWALL_RULES = [
61+
FirewallRule(
62+
position='1',
63+
direction='in',
64+
family='IPv4',
65+
protocol='tcp',
66+
source_address_start='192.168.1.1',
67+
source_address_end='192.168.1.255',
68+
destination_port_start='22',
69+
destination_port_end='22',
70+
action='accept'
71+
),
72+
FirewallRule(
73+
position='2',
74+
direction='in',
75+
family='IPv4',
76+
protocol='tcp',
77+
source_address_start='192.168.1.1',
78+
source_address_end='192.168.1.255',
79+
destination_port_start='21',
80+
destination_port_end='21',
81+
action='accept'
82+
)
83+
]
84+
85+
86+
TAGS = [
87+
Tag('testlb'),
88+
Tag('testdb'),
89+
Tag('testweb')
90+
]

test/helpers/infra_helpers.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from __future__ import print_function
2+
from __future__ import unicode_literals
3+
from __future__ import division
4+
from __future__ import absolute_import
5+
6+
from upcloud_api import ZONE, Tag
7+
8+
9+
def create_cluster(manager, cluster):
10+
"""Create all servers in cluster."""
11+
for server in cluster:
12+
s = manager.create_server(cluster[server])
13+
14+
for server in cluster:
15+
cluster[server].ensure_started()
16+
17+
return manager.get_servers()
18+
19+
20+
def firewall_test(manager, firewall_rules, server):
21+
"""Run tests on firewall rules."""
22+
# add 1 rule and remove it
23+
server.add_firewall_rule(firewall_rules[0])
24+
25+
fs = server.get_firewall_rules()
26+
assert len(fs) == 1
27+
28+
fs[0].destroy()
29+
fs = server.get_firewall_rules()
30+
assert len(fs) == 0
31+
32+
# add several rules and remove them
33+
server.configure_firewall(firewall_rules)
34+
35+
fs = server.get_firewall_rules()
36+
assert len(fs) == 2
37+
38+
for f in fs:
39+
manager.delete_firewall_rule(server.uuid, 1)
40+
41+
fs = server.get_firewall_rules()
42+
assert len(fs) == 0
43+
44+
45+
def server_test(manager, server):
46+
"""Run tests on a server instance."""
47+
server.populate()
48+
49+
server.core_number = '3'
50+
server.memory_amount = '1024'
51+
server.save()
52+
53+
server.add_IP()
54+
55+
storage = manager.create_storage(size=10, tier='maxiops', zone=ZONE.London)
56+
server.add_storage(storage)
57+
58+
server.start()
59+
60+
#sync new info from API and assert the changes from above have happened
61+
server.populate()
62+
assert server.core_number == '3'
63+
assert server.memory_amount == '1024'
64+
assert len(server.storage_devices) == 3
65+
assert len(server.ip_addresses) == 4
66+
67+
server.ensure_started()
68+
69+
70+
def tag_servers_test(manager, tags, cluster):
71+
"""Run tests on tags."""
72+
# create tags
73+
for t in tags:
74+
manager.create_tag(str(t))
75+
76+
cluster['web1'].add_tags(['testweb'])
77+
cluster['web2'].add_tags(['testweb'])
78+
cluster['lb'].add_tags([tags[1]]) # tags[1] is 'db'
79+
cluster['db'].add_tags(['testlb'])
80+
81+
fetched_servers = manager.get_servers(tags_has_one=['testlb'])
82+
assert len(fetched_servers) == 1
83+
assert fetched_servers[0].tags[0] == 'testlb'

0 commit comments

Comments
 (0)