self.ann_facade.connect(self.connection)
ann = client.EntityAnnotations(
- entity=self.name,
+ entity=self.tag,
annotations=annotations,
)
return await self.ann_facade.Set([ann])
import yaml
from juju import tag
-from juju.errors import JujuAPIError, JujuConnectionError
+from juju.errors import JujuAPIError, JujuConnectionError, JujuError
log = logging.getLogger("websocket")
outgoing = json.dumps(msg, indent=2, cls=encoder)
await self.ws.send(outgoing)
result = await self.recv()
- if result and 'error' in result:
+
+ if not result:
+ return result
+
+ if 'error' in result:
+ # API Error Response
raise JujuAPIError(result)
+
+ if not 'response' in result:
+ # This may never happen
+ return result
+
+ if 'results' in result['response']:
+ # Check for errors in a result list.
+ errors = []
+ for res in result['response']['results']:
+ if res.get('error', {}).get('message'):
+ errors.append(res['error']['message'])
+ if errors:
+ raise JujuError(errors)
+
+ elif result['response'].get('error', {}).get('message'):
+ raise JujuError(result['response']['error']['message'])
+
return result
def http_headers(self):
)
app.placement = placement
- result = await app_facade.Deploy([app])
- errors = [r.error.message for r in result.results if r.error]
- if errors:
- raise JujuError('\n'.join(errors))
+ await app_facade.Deploy([app])
return await self._wait_for_new('application', application_name)
def destroy(self):
self.plan = await self.client_facade.GetBundleChanges(
yaml.dump(self.bundle))
- if self.plan.errors:
- raise JujuError('\n'.join(self.plan.errors))
-
async def execute_plan(self):
for step in self.plan.changes:
method = getattr(self, step.method)
--- /dev/null
+import pytest
+
+from .. import base
+
+MB = 1
+GB = 1024
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_juju_api_error(event_loop):
+ '''
+ Verify that we raise a JujuAPIError for responses with an error in
+ a top level key (for completely invalid requests).
+
+ '''
+ from juju.errors import JujuAPIError
+
+ async with base.CleanModel() as model:
+ with pytest.raises(JujuAPIError):
+ await model.add_machine(constraints={'mem': 'foo'})
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_juju_error_in_results_list(event_loop):
+ '''
+ Replicate the code that caused
+ https://github.com/juju/python-libjuju/issues/67, and verify that
+ we get a JujuError instead of passing silently by the failure.
+
+ (We don't raise a JujuAPIError, because the request isn't
+ completely invalid -- it's just passing a tag that doesn't exist.)
+
+ This also verifies that we will raise a JujuError any time there
+ is an error in one of a list of results.
+
+ '''
+ from juju.errors import JujuError
+ from juju.client import client
+
+ async with base.CleanModel() as model:
+ # Replicate
+ ann_facade = client.AnnotationsFacade()
+ ann_facade.connect(model.connection)
+
+ ann = client.EntityAnnotations(
+ entity='badtag',
+ annotations={'gui-x': '1', 'gui-y': '1'},
+ )
+ with pytest.raises(JujuError):
+ return await ann_facade.Set([ann])
+
+
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_juju_error_in_result(event_loop):
+ '''
+ Verify that we raise a JujuError when appropraite when we are
+ looking at a single result coming back.
+
+ # TODO: write this!
+
+ '''
+ pass