operator icon indicating copy to clipboard operation
operator copied to clipboard

`harness.get_relation_data()` returns `{}` although charm under test has set relation data

Open lourot opened this issue 3 years ago • 4 comments

Although the machine charm under test sets relation data to the other charm in the relation-joined hook, harness,get_relation_data() still returns {}, making it impossible to write corresponding test expectations.

This is hitting us while pulling the ops framework from source (master) on 2022-02-17.

# metadata.yaml
name: nova-compute-nvidia-vgpu
subordinate: true
provides:
  nova-vgpu:
    interface: nova-vgpu
    scope: container
requires:
  juju-info:
    interface: juju-info
    scope: container
# src/charm.py

class NovaComputeNvidiaVgpuCharm(CharmBase):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.framework.observe(self.on.nova_vgpu_relation_joined,
                               self._on_nova_vgpu_relation_joined_or_changed)
        self.framework.observe(self.on.nova_vgpu_relation_changed,
                               self._on_nova_vgpu_relation_joined_or_changed)

    def _on_nova_vgpu_relation_joined_or_changed(self, event):
        print('I HAVE BEEN CALLED')
        event.relation.data[self.unit]['hello'] = 'hi'
# unit_tests/test_charm.py

class TestNovaComputeNvidiaVgpuCharm(CharmTestCase):

    def setUp(self):
        self.harness = Harness(src.charm.NovaComputeNvidiaVgpuCharm)
        self.addCleanup(self.harness.cleanup)
        self.harness.begin()

    def test_nova_vgpu_relation_joined(self):
        self.harness.set_leader(True)
        relation_id = self.harness.add_relation('nova-vgpu', 'nova-compute')
        self.harness.add_relation_unit(relation_id, 'nova-compute/0')

        # PROBLEM: at this point this returns {} instead of {'hello': 'hi'}
        # although we know that _on_nova_vgpu_relation_joined_or_changed() has
        # been called:
        self.harness.get_relation_data(relation_id, 'nova-compute/0')

lourot avatar Feb 23 '22 11:02 lourot

Note that querying the other side of the relation also returns {}

unit_under_test = self.harness.charm.unit.name  # -> nova-compute-nvidia-vgpu/0
print(self.harness.get_relation_data(relation_id, unit_under_test))  # -> {}

lourot avatar Feb 23 '22 12:02 lourot

    def _on_nova_vgpu_relation_joined_or_changed(self, event):
        print('I HAVE BEEN CALLED')
        event.relation.data[self.unit]['hello'] = 'hi'

This is setting the data for self.unit which should be something named based on NovaComputeNvidiaVgpuCharm. I certainly wouldn't expect nova-compute/0 to have any data, as your unit doesn't get to set remote data (you should be able to Harness.update_relation_data if you want to provide data from the remote to your unit.

I would expect unit_under_test from above to work

jameinel avatar Feb 23 '22 15:02 jameinel

Thanks, yes you mean https://github.com/canonical/operator/issues/703#issuecomment-1048738575 should work, but doesn't for me

lourot avatar Feb 23 '22 16:02 lourot

The example here passes for me (with ops 1.3):

    def test_nova_vgpu_relation_joined(self):
        self.harness.set_leader(True)
        relation_id = self.harness.add_relation('nova-vgpu', 'nova-compute')
        self.harness.add_relation_unit(relation_id, 'nova-compute/0')

        unit_under_test = self.harness.charm.unit.name  # -> nova-compute-nvidia-vgpu/0
        self.assertEqual({'hello': 'hi'}, self.harness.get_relation_data(relation_id, unit_under_test))

@AurelienLourot - is there another issue that we have missed that needs to be addressed here?

rwcarlsen avatar Mar 25 '22 16:03 rwcarlsen

I believe this is not an issue anymore.

PietroPasotti avatar Oct 13 '22 13:10 PietroPasotti