Test Harness with Custom Events

I’m trying to write some relation unit tests for this charm using the operator framework Test Harness.

This is my current code:

def test_main_with_relation(harness):
    harness.set_leader(True)
    harness.add_oci_resource('k8s-dashboard-image', {
        'registrypath': 'kubernetesui/dashboard:v2.0.4',
        'username': '',
        'password': '',
    })
    rel_id = harness.add_relation("metrics-scraper", "dashboard-metrics-scraper")
    harness.begin_with_initial_hooks()
    assert isinstance(harness.charm.model.unit.status, WaitingStatus)
    harness.add_relation_unit(rel_id, "dashboard-metrics-scraper/0")
    harness.update_relation_data(rel_id, "k8s-dashboard/0",
                                 {"service-name": "dashboard-metrics-scraper",
                                  "service-port": "8000"})
    assert isinstance(harness.charm.model.unit.status, ActiveStatus)

The relation in the charm uses the following interface. This interface should react to the relation_changed event which should be emmited by the update_relation_data method. Afterwards, the interface should emit the k8s_service_changed event and the charm should generate a new pod-spec with the new relation data and pass to an active state.

Unfortunately, with my current code the charm stays in a Waiting state. I’m wondering if this might be due to the k8s_service_changed event being ignored with the Harness or if I’m missing some steps.

on a quick walk through the code it seems it should work. I’ll take a deeper look as soon as I’m able.

So. First, you need to fix the interface you’re using so it is testable.

(the fact that it has 0 tests might have keyed you in to it not being suitable for production use).

Its use of cached_property means that your unit tests will fail. Change it to be just property and you’ll be a step closer. You can invalidate a cached_property by using del (i.e. if c.foo is a cached_property, del c.foo will trigger a recalculation on the next access), but I haven’t looked at how to make this do what you want in your tests.

Next, note that that interface uses app data, not unit data, so what you want is

    harness.update_relation_data(rel_id, "dashboard-metrics-scraper",
                                 {"service-name": "dashboard-metrics-scraper",
                                  "service-port": "8000"})

(note the lack of the /0 at the end of the app_or_unit parameter).

With these two changes, tests pass.

3 Likes

Thank you John! This fixed my issues.

Just for future reference, I now have the following unit test both on Charm and Interface side:

Provide Charm
Require Charm
Interface

1 Like