OLD | NEW |
1 # -*- encoding: utf-8 -*- | 1 # -*- encoding: utf-8 -*- |
2 | 2 |
3 from StringIO import StringIO | 3 from StringIO import StringIO |
4 import base64 | 4 import base64 |
5 import json | 5 import json |
6 import logging | 6 import logging |
7 import os | 7 import os |
8 import stat | 8 import stat |
9 import sys | 9 import sys |
10 | 10 |
11 from twisted.internet import defer | 11 from twisted.internet import defer |
12 from twisted.internet.process import Process | 12 from twisted.internet.process import Process |
13 | 13 |
14 import juju | 14 import juju |
15 from juju import errors | 15 from juju import errors |
16 from juju.control.tests.test_status import StatusTestBase | 16 from juju.control.tests.test_status import StatusTestBase |
17 from juju.environment.tests.test_config import EnvironmentsConfigTestBase | 17 from juju.environment.tests.test_config import EnvironmentsConfigTestBase |
18 from juju.lib.pick import pick_attr | 18 from juju.lib.pick import pick_attr |
19 from juju.hooks import invoker | 19 from juju.hooks import invoker |
20 from juju.hooks import commands | 20 from juju.hooks import commands |
21 from juju.hooks.protocol import UnitSettingsFactory | 21 from juju.hooks.protocol import UnitSettingsFactory |
22 from juju.lib import serializer | 22 from juju.lib import serializer |
23 from juju.lib.mocker import MATCH | 23 from juju.lib.mocker import MATCH |
24 from juju.lib.twistutils import get_module_directory | 24 from juju.lib.twistutils import get_module_directory |
25 from juju.state import hook | 25 from juju.state import hook |
26 from juju.state.endpoint import RelationEndpoint | 26 from juju.state.endpoint import RelationEndpoint |
27 from juju.state.errors import RelationStateNotFound | 27 from juju.state.errors import RelationIdentNotFound |
28 from juju.state.relation import RelationStateManager | 28 from juju.state.relation import RelationStateManager |
29 from juju.state.tests.test_relation import RelationTestBase | 29 from juju.state.tests.test_relation import RelationTestBase |
30 | 30 |
31 | 31 |
32 class MockUnitAgent(object): | 32 class MockUnitAgent(object): |
33 """Pretends to implement the client state cache, and the UA hook socket. | 33 """Pretends to implement the client state cache, and the UA hook socket. |
34 """ | 34 """ |
35 def __init__(self, client, socket_path, charm_dir): | 35 def __init__(self, client, socket_path, charm_dir): |
36 self.client = client | 36 self.client = client |
37 self.socket_path = socket_path | 37 self.socket_path = socket_path |
(...skipping 1001 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1039 self.assertEqual(db1.relation_ident, "db:1") | 1039 self.assertEqual(db1.relation_ident, "db:1") |
1040 self.assertEqual( | 1040 self.assertEqual( |
1041 set((yield db1.get_relation_idents("db"))), | 1041 set((yield db1.get_relation_idents("db"))), |
1042 set(["db:0", "db:1"])) | 1042 set(["db:0", "db:1"])) |
1043 self.assertEqual( | 1043 self.assertEqual( |
1044 db1, | 1044 db1, |
1045 exe.get_cached_relation_hook_context("db:1")) | 1045 exe.get_cached_relation_hook_context("db:1")) |
1046 | 1046 |
1047 # Not yet visible relation | 1047 # Not yet visible relation |
1048 self.assertRaises( | 1048 self.assertRaises( |
1049 RelationStateNotFound, | 1049 RelationIdentNotFound, |
1050 exe.get_cached_relation_hook_context, "db:2") | 1050 exe.get_cached_relation_hook_context, "db:2") |
1051 | 1051 |
1052 # Nonexistent relation idents | 1052 # Nonexistent relation idents |
1053 self.assertRaises( | 1053 self.assertRaises( |
1054 RelationStateNotFound, | 1054 RelationIdentNotFound, |
1055 exe.get_cached_relation_hook_context, "db:12345") | 1055 exe.get_cached_relation_hook_context, "db:12345") |
1056 | 1056 |
1057 # Reread parent and child contexts | 1057 # Reread parent and child contexts |
1058 exe = yield self.ua.get_invoker( | 1058 exe = yield self.ua.get_invoker( |
1059 "db:0", "add", "mysql/0", self.relation, client_id="client_id") | 1059 "db:0", "add", "mysql/0", self.relation, client_id="client_id") |
1060 db0 = yield exe.get_context() | 1060 db0 = yield exe.get_context() |
1061 db1 = exe.get_cached_relation_hook_context("db:1") | 1061 db1 = exe.get_cached_relation_hook_context("db:1") |
1062 db2 = exe.get_cached_relation_hook_context("db:2") | 1062 db2 = exe.get_cached_relation_hook_context("db:2") |
1063 | 1063 |
1064 # Verify that any changes are written out; write directly here | 1064 # Verify that any changes are written out; write directly here |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 " Setting changed: u'd'=u'99' (was unset) on 'db:2'"]) | 1149 " Setting changed: u'd'=u'99' (was unset) on 'db:2'"]) |
1150 | 1150 |
1151 # Reread parent and child contexts, verify db:1 relation has | 1151 # Reread parent and child contexts, verify db:1 relation has |
1152 # disappeared from topology | 1152 # disappeared from topology |
1153 exe = yield self.ua.get_invoker( | 1153 exe = yield self.ua.get_invoker( |
1154 "db:0", "add", "mysql/0", self.relation, client_id="client_id") | 1154 "db:0", "add", "mysql/0", self.relation, client_id="client_id") |
1155 self.assertEqual( | 1155 self.assertEqual( |
1156 set((yield exe.get_context().get_relation_idents("db"))), | 1156 set((yield exe.get_context().get_relation_idents("db"))), |
1157 set(["db:0", "db:2"])) | 1157 set(["db:0", "db:2"])) |
1158 yield self.assertRaises( | 1158 yield self.assertRaises( |
1159 RelationStateNotFound, | 1159 RelationIdentNotFound, |
1160 exe.get_cached_relation_hook_context, "db:1") | 1160 exe.get_cached_relation_hook_context, "db:1") |
1161 | 1161 |
1162 @defer.inlineCallbacks | 1162 @defer.inlineCallbacks |
1163 def test_relation_ids(self): | 1163 def test_relation_ids(self): |
1164 """Verify `relation-ids` command returns ids separated by newlines.""" | 1164 """Verify `relation-ids` command returns ids separated by newlines.""" |
1165 yield self.add_a_blog("wordpress2") | 1165 |
1166 hook_log = self.capture_logging("hook") | 1166 hook_log = self.capture_logging("hook") |
1167 | 1167 |
1168 # Invoker will be in the context of the mysql/0 service unit | 1168 # Invoker will be in the context of the mysql/0 service unit |
1169 exe = yield self.ua.get_invoker( | 1169 exe = yield self.ua.get_invoker( |
1170 "db:0", "add", "mysql/0", self.relation, | 1170 "db:0", "add", "mysql/0", self.relation, |
1171 client_id="client_id") | 1171 client_id="client_id") |
1172 | 1172 |
| 1173 # Invoker has already been started, verify cache coherence by |
| 1174 # adding another relation. |
| 1175 yield self.add_a_blog("wordpress2") |
| 1176 |
1173 # Then verify the hook lists the relation ids corresponding to | 1177 # Then verify the hook lists the relation ids corresponding to |
1174 # the relation name `db` | 1178 # the relation name `db` |
1175 hook = self.create_hook("relation-ids", "db") | 1179 hook = self.create_hook("relation-ids", "db") |
1176 result = yield exe(hook) | 1180 result = yield exe(hook) |
1177 self.assertEqual(result, 0) | 1181 self.assertEqual(result, 0) |
1178 yield exe.ended | 1182 yield exe.ended |
1179 # Smart formtting outputs one id per line | 1183 # Smart formtting outputs one id per line |
1180 self.assertEqual( | 1184 self.assertEqual( |
1181 hook_log.getvalue(), "db:0\ndb:1\n\n") | 1185 hook_log.getvalue(), "db:0\n\n") |
1182 # But newlines are just whitespace to the shell or to Python, | 1186 # But newlines are just whitespace to the shell or to Python, |
1183 # so they can be split accordingly, adhering to the letter of | 1187 # so they can be split accordingly, adhering to the letter of |
1184 # the spec | 1188 # the spec |
1185 self.assertEqual( | 1189 self.assertEqual( |
1186 hook_log.getvalue().split(), ["db:0", "db:1"]) | 1190 hook_log.getvalue().split(), ["db:0"]) |
1187 | 1191 |
1188 @defer.inlineCallbacks | 1192 @defer.inlineCallbacks |
1189 def test_relation_ids_json_format(self): | 1193 def test_relation_ids_json_format(self): |
1190 """Verify `relation-ids --format=json` command returns ids in json.""" | 1194 """Verify `relation-ids --format=json` command returns ids in json.""" |
1191 yield self.add_a_blog("wordpress2") | 1195 yield self.add_a_blog("wordpress2") |
1192 yield self.add_db_admin_tool("admin") | 1196 yield self.add_db_admin_tool("admin") |
1193 hook_log = self.capture_logging("hook") | 1197 hook_log = self.capture_logging("hook") |
1194 | 1198 |
1195 # Invoker will be in the context of the mysql/0 service unit | 1199 # Invoker will be in the context of the mysql/0 service unit |
1196 exe = yield self.ua.get_invoker( | 1200 exe = yield self.ua.get_invoker( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1287 client_id="client_id") | 1291 client_id="client_id") |
1288 | 1292 |
1289 # But set from db:1 | 1293 # But set from db:1 |
1290 hook = self.create_hook("relation-set", "-r db:1 a=42 b=xyz") | 1294 hook = self.create_hook("relation-set", "-r db:1 a=42 b=xyz") |
1291 result = yield exe(hook) | 1295 result = yield exe(hook) |
1292 self.assertEqual(result, 0) | 1296 self.assertEqual(result, 0) |
1293 yield exe.ended | 1297 yield exe.ended |
1294 | 1298 |
1295 db1 = exe.get_cached_relation_hook_context("db:1") | 1299 db1 = exe.get_cached_relation_hook_context("db:1") |
1296 yield self.assert_zk_data(db1, { | 1300 yield self.assert_zk_data(db1, { |
1297 "a": "42", | 1301 "a": "42", |
1298 "b": "xyz", | 1302 "b": "xyz", |
1299 "private-address": "mysql-0.example.com"}) | 1303 "private-address": "mysql-0.example.com"}) |
1300 self.assertLogLines( | 1304 self.assertLogLines( |
1301 self.log.getvalue(), | 1305 self.log.getvalue(), |
1302 ["Cached relation hook contexts on 'db:0': ['db:1']", | 1306 ["Cached relation hook contexts on 'db:0': ['db:1']", |
1303 "Flushed values for hook %r on 'db:0'" % os.path.basename(hook), | 1307 "Flushed values for hook %r on 'db:0'" % os.path.basename(hook), |
1304 " Setting changed: u'a'=u'42' (was unset) on 'db:1'", | 1308 " Setting changed: u'a'=u'42' (was unset) on 'db:1'", |
1305 " Setting changed: u'b'=u'xyz' (was unset) on 'db:1'"]) | 1309 " Setting changed: u'b'=u'xyz' (was unset) on 'db:1'"]) |
1306 | 1310 |
1307 @defer.inlineCallbacks | 1311 @defer.inlineCallbacks |
1308 def test_relation_set_with_nonexistent_relation_id(self): | 1312 def test_relation_set_with_nonexistent_relation_id(self): |
1309 """Verify error put on stderr when using nonexistent relation id.""" | 1313 """Verify error put on stderr when using nonexistent relation id.""" |
1310 hook_log = self.capture_logging("hook", level=logging.DEBUG) | 1314 hook_log = self.capture_logging("hook", level=logging.DEBUG) |
1311 yield self.add_a_blog("wordpress2") | 1315 yield self.add_a_blog("wordpress2") |
1312 exe = yield self.ua.get_invoker( | 1316 exe = yield self.ua.get_invoker( |
1313 "db:0", "add", "mysql/0", self.relation, | 1317 "db:0", "add", "mysql/0", self.relation, |
1314 client_id="client_id") | 1318 client_id="client_id") |
1315 hook, args = self.create_capturing_hook( | 1319 hook, args = self.create_capturing_hook( |
1316 "#!/bin/bash\n" | 1320 "#!/bin/bash\n" |
1317 "set -eu\n" | 1321 "set -eu\n" |
1318 "data=$({bin-path}/relation-set -r db:12345 " | 1322 "data=$({bin-path}/relation-set -r db:12345 " |
1319 "k1=v1 k2=v2 2> {stderr})\n" | 1323 "k1=v1 k2=v2 2> {stderr})\n" |
1320 "echo -n $data > {stdout}\n", | 1324 "echo -n $data > {stdout}\n", |
1321 files=["stdout", "stderr"]) | 1325 files=["stdout", "stderr"]) |
1322 result = yield exe(hook) | 1326 result = yield exe(hook) |
1323 self.assertEqual(result, 0) | 1327 self.assertEqual(result, 0) |
1324 yield exe.ended | 1328 yield exe.ended |
1325 self.assert_file(args["stdout"], "") | 1329 self.assert_file(args["stdout"], "") |
1326 self.assert_file(args["stderr"], "Relation not found\n") | 1330 self.assert_file(args["stderr"], "Relation not found for - db:12345\n") |
1327 self.assertEqual( | 1331 self.assertEqual( |
1328 hook_log.getvalue(), | 1332 hook_log.getvalue(), |
1329 "Cached relation hook contexts on 'db:0': ['db:1']\n" | 1333 "Cached relation hook contexts on 'db:0': ['db:1']\n" |
1330 "hook {} exited, exit code 0.\n".format(os.path.basename(hook))) | 1334 "hook {} exited, exit code 0.\n".format(os.path.basename(hook))) |
1331 | 1335 |
1332 @defer.inlineCallbacks | 1336 @defer.inlineCallbacks |
1333 def test_relation_set_with_invalid_relation_id(self): | 1337 def test_relation_set_with_invalid_relation_id(self): |
1334 """Verify message is written to stderr for invalid formatted id.""" | 1338 """Verify message is written to stderr for invalid formatted id.""" |
1335 hook_log = self.capture_logging("hook", level=logging.DEBUG) | 1339 hook_log = self.capture_logging("hook", level=logging.DEBUG) |
1336 yield self.add_a_blog("wordpress2") | 1340 yield self.add_a_blog("wordpress2") |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1393 "#!/bin/bash\n" | 1397 "#!/bin/bash\n" |
1394 "set -eu\n" | 1398 "set -eu\n" |
1395 "settings=$({bin-path}/relation-get -r db:12345 - mysql/0 " | 1399 "settings=$({bin-path}/relation-get -r db:12345 - mysql/0 " |
1396 "2> {stderr})\n" | 1400 "2> {stderr})\n" |
1397 "echo -n $settings > {settings}\n", | 1401 "echo -n $settings > {settings}\n", |
1398 files=["settings", "stderr"]) | 1402 files=["settings", "stderr"]) |
1399 result = yield exe(hook) | 1403 result = yield exe(hook) |
1400 self.assertEqual(result, 0) | 1404 self.assertEqual(result, 0) |
1401 yield exe.ended | 1405 yield exe.ended |
1402 self.assert_file(args["settings"], "") | 1406 self.assert_file(args["settings"], "") |
1403 self.assert_file(args["stderr"], "Relation not found\n") | 1407 self.assert_file(args["stderr"], "Relation not found for - db:12345\n") |
1404 self.assertEqual( | 1408 self.assertEqual( |
1405 hook_log.getvalue(), | 1409 hook_log.getvalue(), |
1406 "Cached relation hook contexts on 'db:0': ['db:1']\n" | 1410 "Cached relation hook contexts on 'db:0': ['db:1']\n" |
1407 "hook {} exited, exit code 0.\n".format(os.path.basename(hook))) | 1411 "hook {} exited, exit code 0.\n".format(os.path.basename(hook))) |
1408 | 1412 |
1409 @defer.inlineCallbacks | 1413 @defer.inlineCallbacks |
1410 def test_relation_get_with_invalid_relation_id(self): | 1414 def test_relation_get_with_invalid_relation_id(self): |
1411 """Verify message is written to stderr for invalid formatted id.""" | 1415 """Verify message is written to stderr for invalid formatted id.""" |
1412 hook_log = self.capture_logging("hook", level=logging.DEBUG) | 1416 hook_log = self.capture_logging("hook", level=logging.DEBUG) |
1413 yield self.add_a_blog("wordpress2") | 1417 yield self.add_a_blog("wordpress2") |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1486 hook, args = self.create_capturing_hook( | 1490 hook, args = self.create_capturing_hook( |
1487 "#!/bin/bash\n" | 1491 "#!/bin/bash\n" |
1488 "set -eu\n" | 1492 "set -eu\n" |
1489 "data=$({bin-path}/relation-list -r db:12345 2> {stderr})\n" | 1493 "data=$({bin-path}/relation-list -r db:12345 2> {stderr})\n" |
1490 "echo -n $data > {stdout}\n", | 1494 "echo -n $data > {stdout}\n", |
1491 files=["stdout", "stderr"]) | 1495 files=["stdout", "stderr"]) |
1492 result = yield exe(hook) | 1496 result = yield exe(hook) |
1493 self.assertEqual(result, 0) | 1497 self.assertEqual(result, 0) |
1494 yield exe.ended | 1498 yield exe.ended |
1495 self.assert_file(args["stdout"], "") | 1499 self.assert_file(args["stdout"], "") |
1496 self.assert_file(args["stderr"], "Relation not found\n") | 1500 self.assert_file(args["stderr"], "Relation not found for - db:12345\n") |
1497 self.assertEqual( | 1501 self.assertEqual( |
1498 hook_log.getvalue(), | 1502 hook_log.getvalue(), |
1499 "Cached relation hook contexts on 'db:0': ['db:1']\n" | 1503 "Cached relation hook contexts on 'db:0': ['db:1']\n" |
1500 "hook {} exited, exit code 0.\n".format(os.path.basename(hook))) | 1504 "hook {} exited, exit code 0.\n".format(os.path.basename(hook))) |
1501 | 1505 |
1502 @defer.inlineCallbacks | 1506 @defer.inlineCallbacks |
1503 def test_relation_list_with_invalid_relation_id(self): | 1507 def test_relation_list_with_invalid_relation_id(self): |
1504 """Verify message is written to stderr for invalid formatted id.""" | 1508 """Verify message is written to stderr for invalid formatted id.""" |
1505 hook_log = self.capture_logging("hook", level=logging.DEBUG) | 1509 hook_log = self.capture_logging("hook", level=logging.DEBUG) |
1506 yield self.add_a_blog("wordpress2") | 1510 yield self.add_a_blog("wordpress2") |
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2137 self.assertEqual(result, 0) | 2141 self.assertEqual(result, 0) |
2138 self.assertEqual(hook_log.getvalue(), "abc\n") | 2142 self.assertEqual(hook_log.getvalue(), "abc\n") |
2139 | 2143 |
2140 @defer.inlineCallbacks | 2144 @defer.inlineCallbacks |
2141 def test_config_get_unicode(self): | 2145 def test_config_get_unicode(self): |
2142 """Validate that config-get returns raw strings containing UTF-8.""" | 2146 """Validate that config-get returns raw strings containing UTF-8.""" |
2143 exe, hook_log = yield self.setup_config() | 2147 exe, hook_log = yield self.setup_config() |
2144 result = yield exe(self.create_hook("config-get", "u")) | 2148 result = yield exe(self.create_hook("config-get", "u")) |
2145 self.assertEqual(result, 0) | 2149 self.assertEqual(result, 0) |
2146 self.assertEqual(hook_log.getvalue(), "中文\n") | 2150 self.assertEqual(hook_log.getvalue(), "中文\n") |
OLD | NEW |