solar/solar/dblayer/test/test_real.py

670 lines
20 KiB
Python

# Copyright 2015 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
import pytest
from solar.dblayer.model import check_state_for
from solar.dblayer.model import StrInt
from solar.dblayer.solar_models import DBLayerSolarException
from solar.dblayer.solar_models import Resource
def create_resource(key, data):
mi = data.get('meta_inputs', {})
for inp_name, inp_value in data.get('inputs', {}).items():
if isinstance(inp_value, list):
if len(inp_value) == 1 and isinstance(inp_value[0], dict):
schema = [{}]
else:
schema = ['str!']
elif isinstance(inp_value, dict):
schema = {}
else:
if inp_value is None:
mi.setdefault(inp_name, {})
continue
schema = '%s!' % type(inp_value).__name__
mi.setdefault(inp_name, {"schema": schema})
data['meta_inputs'] = mi
return Resource.from_dict(key, data)
@pytest.mark.xfail(reason="Not YET decided how it should work")
def test_changes_state(rk):
key = next(rk)
r = create_resource(key, {'name': 'a name'})
r.inputs['a'] = 1
with pytest.raises(Exception):
# raise exception when something is changed
r.inputs['a']
r.save()
check_state_for('index', r)
def test_basic_input(rk):
key = next(rk)
r = create_resource(key, {'name': 'a name'})
r.inputs['a'] = 1
r.save()
assert r.inputs['a'] == 1
assert len(r._riak_object.indexes) == 2
del r.inputs['a']
r.save()
with pytest.raises(DBLayerSolarException):
assert r.inputs['a'] == 1
assert len(r._riak_object.indexes) == 1
def test_input_in_dict(rk):
key = next(rk)
r = create_resource(key, {'name': 'a name',
'inputs': {'input1': 15,
'input2': None}})
r.save()
assert r._riak_object.data['inputs']['input1'] == 15
assert r.inputs['input1'] == 15
assert r._riak_object.data['inputs']['input2'] is None
assert r.inputs['input2'] is None
def test_basic_connect(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input1': None,
'input2': None}})
r1.connect(r2, {'input1': 'input1', 'input2': 'input2'})
r1.save()
r2.save()
assert r1._riak_object.data['inputs']['input1'] == 10
assert r1.inputs['input1'] == 10
assert r2._riak_object.data['inputs']['input1'] is None
assert r2.inputs['input1'] == 10
assert r1._riak_object.data['inputs']['input2'] == 15
assert r1.inputs['input2'] == 15
assert r2._riak_object.data['inputs']['input2'] is None
assert r2.inputs['input2'] == 15
@pytest.mark.parametrize('depth', (3, 4, 5, 10, 25, 50))
def test_adv_connect(rk, depth):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
prev = create_resource(k2, {'name': 'second',
'inputs': {'input1': None,
'input2': None,
'input3': 0}})
conn = {'input1': 'input1', 'input2': 'input2'}
r1.save()
r1.connect(prev, conn)
prev.save()
created = [prev]
for x in xrange(depth - 1):
k = next(rk)
res = create_resource(k, {'name': 'next %d' % (x + 1),
'inputs': {'input1': None,
'input2': None,
'input3': x + 1}})
created.append(res)
prev.connect(res, conn)
res.save()
prev = res
for i, c in enumerate(created):
assert c.inputs['input1'] == 10
assert c.inputs['input2'] == 15
assert c.inputs['input3'] == i
@pytest.mark.parametrize('depth', (1, 3, 5, 10, 50, 100))
def test_perf_inputs(rk, depth):
k1 = next(rk)
r1 = create_resource(k1, {'name': 'first', 'inputs': {'input1': 'target'}})
r1.save()
prev = r1
for x in xrange(depth):
k = next(rk)
res = create_resource(k, {'name': 'next %d' % (x + 1),
'inputs': {'input1': None}})
prev.connect(res, {'input1': 'input1'})
res.save()
prev = res
import time
st = time.time()
assert res.inputs['input1'] == 'target'
end = time.time()
print(end - st)
def test_change_connect(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input1': None,
'input2': None,
'input3': 0}})
r3 = create_resource(k3, {'name': 'first',
'inputs': {'input1': 30,
'input2': 35}})
r1.connect(r2, {'input1': 'input1', 'input2': 'input2'})
r3.connect(r2, {'input1': 'input1'})
r1.save()
r2.save()
r3.save()
assert r2.inputs['input1'] == 30
assert r2.inputs['input2'] == 15
def test_simple_tag(rk, rt):
k1 = next(rk)
tag = next(rt)
r1 = create_resource(k1, {'name': 'first',
'tags': ['%s' % tag, '%s=10' % tag]})
r1.save()
assert list(r1.tags) == ['%s=' % tag, '%s=10' % tag]
def test_list_by_tag(rk, rt):
k1 = next(rk)
k2 = next(rk)
tag1 = next(rt)
tag2 = next(rt)
r1 = create_resource(k1, {'name': 'first', 'tags': [tag1, '%s=10' % tag1]})
r1.save()
r2 = create_resource(k2, {'name': 'first', 'tags': [tag1, '%s=10' % tag2]})
r2.save()
assert len(Resource.tags.filter(tag1)) == 2
assert Resource.tags.filter(tag1) == set([k1, k2])
assert len(Resource.tags.filter('other_tag')) == 0
assert len(Resource.tags.filter(tag2)) == 0
assert len(Resource.tags.filter(tag2, 10)) == 1
assert Resource.tags.filter(tag2, 10) == set([k2])
assert len(Resource.tags.filter(tag2, '*')) == 1
def test_updated_behaviour(rk):
k1 = next(rk)
_cmp = StrInt()
r1 = create_resource(k1, {'name': 'blah'})
r1.save()
assert isinstance(r1._riak_object.data['updated'], basestring)
assert not isinstance(r1.updated, basestring)
assert r1.updated >= _cmp
assert k1 in Resource.updated.filter(StrInt.p_min(), StrInt.p_max())
def test_updated_only_last(rk):
for i in range(3):
r = create_resource(next(rk), {'name': str(i)})
r.save()
assert Resource.updated.filter(r.updated, StrInt.p_max()) == [r.key]
def test_list_inputs(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'second', 'inputs': {'input': []}})
r1.connect(r2, {'input1': 'input'})
r1.connect(r2, {'input2': 'input'})
r1.save()
r2.save()
assert r2.inputs['input'] == [10, 15]
def test_dict_to_dict_inputs(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input': {'input1': 10,
'input2': 15}}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input': {'input1': None,
'input2': None,
'input3': None}}})
r1.connect(r2, {'input': 'input'})
r1.save()
r2.save()
assert r2.inputs['input']['input1'] == 10
assert r2.inputs['input']['input2'] == 15
assert 'input3' not in r2.inputs['input']
def test_list_to_list_inputs(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first', 'inputs': {'input': [10, 15]}})
r2 = create_resource(k2, {'name': 'second', 'inputs': {'input': []}})
r1.connect(r2, {'input': 'input'})
r1.save()
r2.save()
assert r2.inputs['input'] == [10, 15]
def test_simple_to_dict_inputs(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input': {'input1': None,
'input2': None}}})
r1.connect(r2, {'input1': 'input:input1', 'input2': 'input:input2'})
r1.save()
r2.save()
assert r2.inputs['input']['input1'] == 10
assert r2.inputs['input']['input2'] == 15
def test_simple_to_dict_inputs_without_tag_single_key(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input': {'input1': None,
'input2': None}}})
r1.connect(r2, {'input1': 'input:input1'})
r1.save()
r2.save()
assert r2.inputs['input']['input1'] == 10
def test_simple_to_dict_inputs_without_tag(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r3 = create_resource(k3, {'name': 'third',
'inputs': {'input1': 110,
'input2': 115}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input': {'input1': None,
'input2': None}}})
r1.connect(r2, {'input1': 'input:input1'})
r3.connect(r2, {'input2': 'input:input2'})
r1.save()
r2.save()
r3.save()
assert r2.inputs['input']['input1'] == 10
assert r2.inputs['input']['input2'] == 115
def test_simple_to_dict_inputs_with_tag(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r3 = create_resource(k3, {'name': 'first',
'inputs': {'input1': 110,
'input2': 115}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input': {'input1': None,
'input2': None}}})
r1.connect(r2, {'input1': 'input:input1|tag'})
r3.connect(r2, {'input2': 'input:input2|tag'})
r1.save()
r2.save()
r3.save()
assert r2.inputs['input']['input1'] == 10
assert r2.inputs['input']['input2'] == 115
def test_simple_to_listdict_inputs(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
k4 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r3 = create_resource(k3, {'name': 'first',
'inputs': {'input1': 110,
'input2': 115}})
r4 = create_resource(k4, {'name': 'first',
'inputs': {'input1': 1110,
'input2': 1115}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input': [{'input1': None,
'input2': None}]}})
r1.connect(r2, {'input1': 'input:input1', 'input2': 'input:input2'})
r3.connect(r2, {'input2': 'input:input2|tag2',
'input1': 'input:input1|tag1'})
r4.connect(r2, {'input2': 'input:input2|tag1',
'input1': 'input:input1|tag2'})
r1.save()
r2.save()
r3.save()
r4.save()
inputs = set(pytest.dicts_to_hashable(r2.inputs['input']))
expected_inputs = set(pytest.dicts_to_hashable(
[{u'input2': 1115, u'input1': 110},
{u'input2': 115, u'input1': 1110},
{u'input2': 15, u'input1': 10}]))
assert inputs == expected_inputs
def test_dict_to_list_inputs(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first', 'inputs': {'modules': [{}]}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'module': {'name': 'blah2'}}})
r3 = create_resource(k3, {'name': 'third',
'inputs': {'module': {'name': 'blah3'}}})
r2.connect(r1, {'module': 'modules'})
r3.connect(r1, {'module': 'modules'})
r1.save()
r2.save()
r3.save()
assert sorted(r1.inputs['modules']) == sorted([{'name': 'blah2'},
{'name': 'blah3'}])
def test_passthrough_inputs(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'first',
'inputs': {'input1': None,
'input2': None}})
r3 = create_resource(k3, {'name': 'first',
'inputs': {'input1': None,
'input2': None}})
r2.connect(r3, {'input1': 'input1', 'input2': 'input2'})
r1.connect(r2, {'input1': 'input1', 'input2': 'input2'})
r1.save()
r2.save()
r3.save()
assert r3.inputs['input1'] == 10
assert r3.inputs['input2'] == 15
def test_disconnect_by_input(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'first',
'inputs': {'input1': None,
'input2': None}})
r3 = create_resource(k3, {'name': 'first',
'inputs': {'input1': None,
'input2': None}})
r2.connect(r3, {'input1': 'input1', 'input2': 'input2'})
r1.connect(r2, {'input1': 'input1', 'input2': 'input2'})
r1.save()
r2.save()
r3.save()
with pytest.raises(Exception):
r2.inputs['input1'] = 150
r2.inputs.disconnect('input1')
r2.save()
assert r2.inputs['input1'] is None
r2.inputs['input1'] = 150
r2.save()
assert r2.inputs['input1'] == 150
assert r2.inputs['input2'] == 15
assert r3.inputs['input1'] == 150
def test_resource_childs(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'first',
'inputs': {'input1': None,
'input2': None}})
r3 = create_resource(k3, {'name': 'first',
'inputs': {'input1': None,
'input2': None}})
r2.connect(r3, {'input1': 'input1'})
r1.connect(r2, {'input1': 'input1'})
r1.save()
r2.save()
r3.save()
assert set(Resource.childs([r1.key])) == {r1.key, r2.key, r3.key}
def test_events(rk):
k = next(rk)
r1 = Resource.from_dict(k, {'events': ['event1', 'event2']})
r1.save()
assert r1.events == ['event1', 'event2']
r1.events.pop()
assert r1.events == ['event1']
def test_delete(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'first',
'inputs': {'input1': None,
'input2': None}})
r1.connect(r2, {'input1': 'input1'})
r1.save()
r2.save()
r1.delete()
recv_emit_bin = []
for index in r2._riak_object.indexes:
if 'recv' in index[0] or 'emit' in index[0]:
recv_emit_bin.append(index)
assert recv_emit_bin == []
def test_delete_hash(rk):
k1 = next(rk)
k2 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'input1': 10,
'input2': 15}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {'input': {'input1': None,
'input2': None}}})
r1.connect(r2, {'input1': 'input:input1', 'input2': 'input:input2'})
r1.save()
r2.save()
r1.delete()
recv_emit_bin = []
for index in r2._riak_object.indexes:
if 'recv' in index[0] or 'emit' in index[0]:
recv_emit_bin.append(index)
assert recv_emit_bin == []
def test_nested_simple_listdict(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
k4 = next(rk)
k5 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'config': [{"backends": [{}],
'listen_port': 1}]}})
r2 = create_resource(k2, {'name': 'second', 'inputs': {'backend': {}}})
r3 = create_resource(k3, {'name': 'third', 'inputs': {'backend': {}}})
r5 = create_resource(k5, {'name': 'fifth',
'inputs': {"port": 5,
"host": "fifth_host"}})
r4 = create_resource(k4, {'name': 'fourth',
'inputs': {"port": 4,
"host": "fourth_host"}})
r4.connect(r2, {'port': "backend:port", 'host': 'backend:host'})
r5.connect(r3, {'port': "backend:port", 'host': 'backend:host'})
assert r2.inputs['backend'] == {'host': 'fourth_host', 'port': 4}
assert r3.inputs['backend'] == {'host': 'fifth_host', 'port': 5}
r2.connect(r1, {'backend': 'config:backends'})
r3.connect(r1, {'backend': 'config:backends'})
Resource.save_all_lazy()
backends = next(x['backends'] for x in r1.inputs['config']
if 'backends' in x)
assert len(backends) == 2
def test_nested_two_listdict(rk):
k1 = next(rk)
k2 = next(rk)
k3 = next(rk)
r1 = create_resource(k1, {'name': 'first',
'inputs': {'config': [{"backends": [{}],
'something': 0}]}})
r2 = create_resource(k2, {'name': 'second',
'inputs': {"backends": [{"host": "second_host",
"port": 2}],
'something': 1}})
r3 = create_resource(k3, {'name': 'third',
'inputs': {"backends": [{"host": "third_host",
"port": 3}],
'something': 2}})
r2.connect(r1, {'backends': 'config:backends',
'something': 'config:something'})
r3.connect(r1, {'backends': 'config:backends',
'something': 'config:something'})
Resource.save_all_lazy()
for sc in r1.inputs['config']:
assert 'something' in sc
assert 'backends' in sc
assert isinstance(sc['backends'], list)
assert isinstance(sc['something'], int)