Skip to content

Commit

Permalink
Merge branch 'main' into remove-relation-broken-special-case-1128
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyandrewmeyer authored Feb 27, 2024
2 parents ce1cdba + 9664fd1 commit 03e22b6
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* `StopEvent`, `RemoveEvent`, and all `LifeCycleEvent`s are no longer deferrable, and will raise a `RuntimeError` if `defer()` is called on the event object.
* The remote app name (and its databag) is now consistently available in relation-broken events.
* Added `ActionEvent.id`, exposing the JUJU_ACTION_UUID environment variable.
* Added support for creating `pebble.Plan` objects by passing in a `pebble.PlanDict`, the
ability to compare two `Plan` objects with `==`, and the ability to create an empty Plan with `Plan()`.

# 2.10.0

Expand Down
14 changes: 12 additions & 2 deletions ops/pebble.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,11 @@ class Plan:
documented at https://github.com/canonical/pebble/#layer-specification.
"""

def __init__(self, raw: str):
d = yaml.safe_load(raw) or {} # type: ignore
def __init__(self, raw: Optional[Union[str, 'PlanDict']] = None):
if isinstance(raw, str): # noqa: SIM108
d = yaml.safe_load(raw) or {} # type: ignore
else:
d = raw or {}
d = typing.cast('PlanDict', d)

self._raw = raw
Expand Down Expand Up @@ -796,6 +799,13 @@ def to_yaml(self) -> str:

__str__ = to_yaml

def __eq__(self, other: Union['PlanDict', 'Plan']) -> bool:
if isinstance(other, dict):
return self.to_dict() == other
elif isinstance(other, Plan):
return self.to_dict() == other.to_dict()
return NotImplemented


class Layer:
"""Represents a Pebble configuration layer.
Expand Down
143 changes: 139 additions & 4 deletions test/test_pebble.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,10 +492,6 @@ def test_notice_from_dict(self):


class TestPlan(unittest.TestCase):
def test_no_args(self):
with self.assertRaises(TypeError):
pebble.Plan() # type: ignore

def test_services(self):
plan = pebble.Plan('')
self.assertEqual(plan.services, {})
Expand Down Expand Up @@ -589,6 +585,37 @@ def test_yaml(self):
self.assertEqual(plan.to_yaml(), reformed)
self.assertEqual(str(plan), reformed)

def test_plandict(self):
# Starting with nothing, we get the empty result.
plan = pebble.Plan({})
self.assertEqual(plan.to_dict(), {})
plan = pebble.Plan()
self.assertEqual(plan.to_dict(), {})

# With a service, we return validated yaml content.
raw: pebble.PlanDict = {
"services": {
"foo": {
"override": "replace",
"command": "echo foo",
},
},
"checks": {
"bar": {
"http": {"url": "https://example.com/"},
},
},
"log-targets": {
"baz": {
"override": "replace",
"type": "loki",
"location": "https://example.com:3100/loki/api/v1/push",
},
},
}
plan = pebble.Plan(raw)
self.assertEqual(plan.to_dict(), raw)

def test_service_equality(self):
plan = pebble.Plan("""
services:
Expand All @@ -610,6 +637,114 @@ def test_service_equality(self):
}
self.assertEqual(plan.services, services_as_dict)

def test_plan_equality(self):
plan1 = pebble.Plan('''
services:
foo:
override: replace
command: echo foo
''')
self.assertNotEqual(plan1, "foo")
plan2 = pebble.Plan('''
services:
foo:
command: echo foo
override: replace
''')
self.assertEqual(plan1, plan2)
plan1_as_dict = {
"services": {
"foo": {
"command": "echo foo",
"override": "replace",
},
},
}
self.assertEqual(plan1, plan1_as_dict)
plan3 = pebble.Plan('''
services:
foo:
override: replace
command: echo bar
''')
# Different command.
self.assertNotEqual(plan1, plan3)
plan4 = pebble.Plan('''
services:
foo:
override: replace
command: echo foo
checks:
bar:
http:
https://example.com/
log-targets:
baz:
override: replace
type: loki
location: https://example.com:3100/loki/api/v1/push
''')
plan5 = pebble.Plan('''
services:
foo:
override: replace
command: echo foo
checks:
bar:
http:
https://different.example.com/
log-targets:
baz:
override: replace
type: loki
location: https://example.com:3100/loki/api/v1/push
''')
# Different checks.bar.http
self.assertNotEqual(plan4, plan5)
plan6 = pebble.Plan('''
services:
foo:
override: replace
command: echo foo
checks:
bar:
http:
https://example.com/
log-targets:
baz:
override: replace
type: loki
location: https://example.com:3200/loki/api/v1/push
''')
# Reordered elements.
self.assertNotEqual(plan4, plan6)
plan7 = pebble.Plan('''
services:
foo:
command: echo foo
override: replace
log-targets:
baz:
type: loki
override: replace
location: https://example.com:3100/loki/api/v1/push
checks:
bar:
http:
https://example.com/
''')
# Reordered sections.
self.assertEqual(plan4, plan7)


class TestLayer(unittest.TestCase):
def _assert_empty(self, layer: pebble.Layer):
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ commands =
[testenv:lint]
description = Check code against coding style standards
deps =
ruff~=0.2.1
ruff~=0.2.2
commands =
ruff check --preview

Expand Down

0 comments on commit 03e22b6

Please sign in to comment.