solar/solar/test/test_signals.py

649 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.
import pytest
import base
from solar.core import signals as xs
class TestBaseInput(base.BaseResourceTest):
def test_no_self_connection(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
value:
schema: str!
value:
""")
sample = self.create_resource('sample', sample_meta_dir,
{'value': 'x'})
with self.assertRaisesRegexp(Exception,
'Trying to connect value-.* to itself'):
xs.connect(sample, sample, {'value'})
def test_input_dict_type(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
values:
schema: {a: int, b: int}
value: {}
""")
sample1 = self.create_resource('sample1', sample_meta_dir, {'values':
{'a': 1,
'b': 2}})
sample2 = self.create_resource('sample2', sample_meta_dir)
xs.connect(sample1, sample2)
self.assertEqual(sample1.args['values'], sample2.args['values'])
# Check update
sample1.update({'values': {'a': 2}})
self.assertEqual(sample1.args['values'], {'a': 2})
self.assertEqual(sample1.args['values'], sample2.args['values'], )
# Check disconnect
# TODO: should sample2.value be reverted to original value?
sample1.disconnect(sample2)
sample1.update({'values': {'a': 3}})
self.assertEqual(sample1.args['values'], {'a': 3})
def test_multiple_resource_disjoint_connect(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str
value:
port:
schema: int
value:
""")
sample_ip_meta_dir = self.make_resource_meta("""
id: sample-ip
handler: ansible
version: 1.0.0
input:
ip:
schema: str
value:
""")
sample_port_meta_dir = self.make_resource_meta("""
id: sample-port
handler: ansible
version: 1.0.0
input:
port:
schema: int
value:
""")
sample = self.create_resource('sample', sample_meta_dir,
{'ip': None,
'port': None})
sample_ip = self.create_resource('sample-ip', sample_ip_meta_dir,
{'ip': '10.0.0.1'})
sample_port = self.create_resource('sample-port', sample_port_meta_dir,
{'port': 8000})
self.assertNotEqual(sample.resource_inputs()['ip'],
sample_ip.resource_inputs()['ip'], )
xs.connect(sample_ip, sample)
xs.connect(sample_port, sample)
self.assertEqual(sample.args['ip'], sample_ip.args['ip'])
self.assertEqual(sample.args['port'], sample_port.args['port'])
def test_simple_observer_unsubscription(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str
value:
""")
sample = self.create_resource('sample', sample_meta_dir, {'ip': None})
sample1 = self.create_resource('sample1', sample_meta_dir,
{'ip': '10.0.0.1'})
sample2 = self.create_resource('sample2', sample_meta_dir,
{'ip': '10.0.0.2'})
xs.connect(sample1, sample)
self.assertEqual(sample1.args['ip'], sample.args['ip'])
xs.connect(sample2, sample)
self.assertEqual(sample2.args['ip'], sample.args['ip'])
# sample should be unsubscribed from sample1 and subscribed to sample2
sample2.update({'ip': '10.0.0.3'})
self.assertEqual(sample2.args['ip'], sample.args['ip'])
@pytest.mark.xfail(reason="No cycle detection in new_db")
def test_circular_connection_prevention(self):
# TODO: more complex cases
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str
value:
""")
sample1 = self.create_resource('sample1', sample_meta_dir,
{'ip': '10.0.0.1'})
sample2 = self.create_resource('sample2', sample_meta_dir,
{'ip': '10.0.0.2'})
xs.connect(sample1, sample2)
with self.assertRaises(Exception): # NOQA
xs.connect(sample2, sample1)
class TestListInput(base.BaseResourceTest):
def test_list_input_single(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str
value:
""")
list_input_single_meta_dir = self.make_resource_meta("""
id: list-input-single
handler: ansible
version: 1.0.0
input:
ips:
schema: [str]
value: []
""")
sample1 = self.create_resource('sample1', sample_meta_dir,
{'ip': '10.0.0.1'})
sample2 = self.create_resource('sample2', sample_meta_dir,
{'ip': '10.0.0.2'})
list_input_single = self.create_resource(
'list-input-single', list_input_single_meta_dir, {'ips': []})
sample1.connect(list_input_single, mapping={'ip': 'ips'})
self.assertItemsEqual(list_input_single.args['ips'], [
sample1.args['ip'],
])
sample2.connect(list_input_single, mapping={'ip': 'ips'})
self.assertItemsEqual(list_input_single.args['ips'], [
sample1.args['ip'],
sample2.args['ip'],
])
# Test update
sample2.update({'ip': '10.0.0.3'})
self.assertItemsEqual(list_input_single.args['ips'], [
sample1.args['ip'],
sample2.args['ip'],
])
# Test disconnect
sample2.disconnect(list_input_single)
self.assertItemsEqual(list_input_single.args['ips'], [
sample1.args['ip'],
])
def test_list_input_multi(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str
value:
port:
schema: int
value:
""")
list_input_multi_meta_dir = self.make_resource_meta("""
id: list-input-multi
handler: ansible
version: 1.0.0
input:
ips:
schema: [str]
value:
ports:
schema: [int]
value:
""")
sample1 = self.create_resource('sample1', sample_meta_dir,
{'ip': '10.0.0.1',
'port': 1000})
sample2 = self.create_resource('sample2', sample_meta_dir,
{'ip': '10.0.0.2',
'port': 1001})
list_input_multi = self.create_resource('list-input-multi',
list_input_multi_meta_dir,
args={'ips': [],
'ports': []})
xs.connect(sample1,
list_input_multi,
mapping={
'ip': 'ips',
'port': 'ports'
})
self.assertItemsEqual(
list_input_multi.args['ips'],
[sample1.args['ip']])
self.assertItemsEqual(
list_input_multi.args['ports'],
[sample1.args['port']])
xs.connect(sample2,
list_input_multi,
mapping={
'ip': 'ips',
'port': 'ports'
})
self.assertItemsEqual(
list_input_multi.args['ips'],
[
sample1.args['ip'],
sample2.args['ip'],
])
self.assertItemsEqual(
list_input_multi.args['ports'],
[
sample1.args['port'],
sample2.args['port'],
])
# Test disconnect
sample2.disconnect(list_input_multi)
self.assertItemsEqual(
list_input_multi.args['ips'],
[sample1.args['ip']])
self.assertItemsEqual(
list_input_multi.args['ports'],
[sample1.args['port']])
# XXX: not used for now, not implemented in new db (jnowak)
# @pytest.mark.xfail(reason="Nested lists are not supported in new_db")
# def test_nested_list_input(self):
# """
# Make sure that single input change is propagated along the chain of
# lists.
# """
# sample_meta_dir = self.make_resource_meta("""
# id: sample
# handler: ansible
# version: 1.0.0
# input:
# ip:
# schema: str
# value:
# port:
# schema: int
# value:
# """)
# list_input_meta_dir = self.make_resource_meta("""
# id: list-input
# handler: ansible
# version: 1.0.0
# input:
# ips:
# schema: [str]
# value: []
# ports:
# schema: [int]
# value: []
# """)
# list_input_nested_meta_dir = self.make_resource_meta("""
# id: list-input-nested
# handler: ansible
# version: 1.0.0
# input:
# ipss:
# schema: [[str]]
# value: []
# portss:
# schema: [[int]]
# value: []
# """)
# sample1 = self.create_resource(
# 'sample1', sample_meta_dir, {'ip': '10.0.0.1', 'port': 1000}
# )
# sample2 = self.create_resource(
# 'sample2', sample_meta_dir, {'ip': '10.0.0.2', 'port': 1001}
# )
# list_input = self.create_resource(
# 'list-input', list_input_meta_dir,
# )
# list_input_nested = self.create_resource(
# 'list-input-nested', list_input_nested_meta_dir,
# )
# sample1.connect(list_input, mapping={'ip': 'ips', 'port': 'ports'})
# sample2.connect(list_input, mapping={'ip': 'ips', 'port': 'ports'})
# list_input.connect(list_input_nested,
# mapping={'ips': 'ipss', 'ports': 'portss'})
# self.assertListEqual(
# list_input_nested.args['ipss'],
# [list_input.args['ips']]
# )
# self.assertListEqual(
# list_input_nested.args['portss'],
# [list_input.args['ports']]
# )
# # Test disconnect
# xs.disconnect(sample1, list_input)
# self.assertListEqual(
# list_input_nested.args['ipss'],
# [[sample2.args['ip']]]
# )
# self.assertListEqual(
# list_input_nested.args['portss'],
# [[sample2.args['port']]]
# )
class TestHashInput(base.BaseResourceTest):
@pytest.mark.xfail(
reason="Connect should raise an error if already connected")
def test_hash_input_basic(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str!
value:
port:
schema: int!
value:
""")
receiver_meta_dir = self.make_resource_meta("""
id: receiver
handler: ansible
version: 1.0.0
input:
server:
schema: {ip: str!, port: int!}
""")
sample1 = self.create_resource('sample1',
sample_meta_dir,
args={'ip': '10.0.0.1',
'port': 5000})
sample2 = self.create_resource('sample2',
sample_meta_dir,
args={'ip': '10.0.0.2',
'port': 5001})
sample3 = self.create_resource('sample3',
sample_meta_dir,
args={'ip': '10.0.0.3',
'port': 5002})
receiver = self.create_resource('receiver', receiver_meta_dir)
xs.connect(sample1,
receiver,
mapping={
'ip': 'server:ip',
'port': 'server:port'
})
self.assertDictEqual(
{'ip': sample1.args['ip'],
'port': sample1.args['port']},
receiver.args['server'], )
sample1.update({'ip': '10.0.0.2'})
self.assertDictEqual(
{'ip': sample1.args['ip'],
'port': sample1.args['port']},
receiver.args['server'], )
# XXX: We need to disconnect first
# XXX: it should raise error when connecting already connected inputs
xs.connect(sample2, receiver, mapping={'ip': 'server:ip'})
self.assertDictEqual(
{'ip': sample2.args['ip'],
'port': sample1.args['port']},
receiver.args['server'], )
xs.connect(sample3,
receiver,
mapping={
'ip': 'server:ip',
'port': 'server:port'
})
self.assertDictEqual(
{'ip': sample3.args['ip'],
'port': sample3.args['port']},
receiver.args['server'], )
def test_hash_input_mixed(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str!
value:
port:
schema: int!
value:
""")
receiver_meta_dir = self.make_resource_meta("""
id: receiver
handler: ansible
version: 1.0.0
input:
server:
schema: {ip: str!, port: int!}
""")
sample = self.create_resource('sample',
sample_meta_dir,
args={'ip': '10.0.0.1',
'port': 5000})
receiver = self.create_resource('receiver',
receiver_meta_dir,
args={'server': {'port': 5001}})
sample.connect(receiver, mapping={'ip': 'server:ip'})
self.assertDictEqual(
{'ip': sample.args['ip'],
'port': 5001},
receiver.args['server'], )
sample.update({'ip': '10.0.0.2'})
self.assertDictEqual(
{'ip': sample.args['ip'],
'port': 5001},
receiver.args['server'], )
def test_hash_input_with_list(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str!
value:
port:
schema: int!
value:
""")
receiver_meta_dir = self.make_resource_meta("""
id: receiver
handler: ansible
version: 1.0.0
input:
server:
schema: [{ip: str!, port: int!}]
""")
sample1 = self.create_resource('sample1',
sample_meta_dir,
args={'ip': '10.0.0.1',
'port': 5000})
receiver = self.create_resource('receiver', receiver_meta_dir)
xs.connect(sample1,
receiver,
mapping={
'ip': 'server:ip',
'port': 'server:port'
})
self.assertItemsEqual(
[{'ip': sample1.args['ip'],
'port': sample1.args['port']}],
receiver.args['server'], )
sample2 = self.create_resource('sample2',
sample_meta_dir,
args={'ip': '10.0.0.2',
'port': 5001})
xs.connect(sample2,
receiver,
mapping={
'ip': 'server:ip',
'port': 'server:port'
})
self.assertItemsEqual(
[{'ip': sample1.args['ip'],
'port': sample1.args['port']}, {'ip': sample2.args['ip'],
'port': sample2.args['port']}],
receiver.args['server'], )
sample1.disconnect(receiver)
self.assertItemsEqual(
[{'ip': sample2.args['ip'],
'port': sample2.args['port']}],
receiver.args['server'], )
def test_hash_input_with_multiple_connections(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str!
value:
""")
receiver_meta_dir = self.make_resource_meta("""
id: receiver
handler: ansible
version: 1.0.0
input:
ip:
schema: str!
value:
server:
schema: {ip: str!}
""")
sample = self.create_resource('sample',
sample_meta_dir,
args={'ip': '10.0.0.1'})
receiver = self.create_resource('receiver', receiver_meta_dir)
xs.connect(sample, receiver, mapping={'ip': ['ip', 'server:ip']})
self.assertEqual(sample.args['ip'], receiver.args['ip'])
self.assertDictEqual({'ip': sample.args['ip']},
receiver.args['server'], )
def test_hash_input_multiple_resources_with_tag_connect(self):
sample_meta_dir = self.make_resource_meta("""
id: sample
handler: ansible
version: 1.0.0
input:
ip:
schema: str!
value:
port:
schema: int!
value:
""")
receiver_meta_dir = self.make_resource_meta("""
id: receiver
handler: ansible
version: 1.0.0
input:
server:
schema: [{ip: str!, port: int!}]
""")
sample1 = self.create_resource('sample1',
sample_meta_dir,
args={'ip': '10.0.0.1',
'port': 5000})
sample2 = self.create_resource('sample2',
sample_meta_dir,
args={'ip': '10.0.0.2',
'port': 5001})
receiver = self.create_resource('receiver', receiver_meta_dir)
sample1.connect(receiver, mapping={'ip': 'server:ip'})
sample2.connect(receiver, mapping={'port': 'server:port|sample1'})
self.assertItemsEqual(
[{'ip': sample1.args['ip'],
'port': sample2.args['port']}],
receiver.args['server'], )
sample3 = self.create_resource('sample3',
sample_meta_dir,
args={'ip': '10.0.0.3',
'port': 5002})
sample3.connect(receiver,
mapping={
'ip': 'server:ip',
'port': 'server:port'
})
self.assertItemsEqual(
[{'ip': sample1.args['ip'],
'port': sample2.args['port']}, {'ip': sample3.args['ip'],
'port': sample3.args['port']}],
receiver.args['server'], )
sample4 = self.create_resource('sample4',
sample_meta_dir,
args={'ip': '10.0.0.4',
'port': 5003})
sample4.connect(receiver, mapping={'port': 'server:port|sample3'})
self.assertItemsEqual(
[{'ip': sample1.args['ip'],
'port': sample2.args['port']}, {'ip': sample3.args['ip'],
'port': sample4.args['port']}],
receiver.args['server'], )
# There can be no sample3 connections left now
sample4.connect(receiver, mapping={'ip': 'server:ip|sample3'})
self.assertItemsEqual(
[{'ip': sample1.args['ip'],
'port': sample2.args['port']}, {'ip': sample4.args['ip'],
'port': sample4.args['port']}],
receiver.args['server'], )