Skip to content

Add Connector Client Context tests - #9235

Merged
mandy-chessell merged 2 commits into
odpi:mainfrom
mandy-chessell:oak2026
Aug 22, 2026
Merged

Add Connector Client Context tests#9235
mandy-chessell merged 2 commits into
odpi:mainfrom
mandy-chessell:oak2026

Conversation

@mandy-chessell

Copy link
Copy Markdown
Contributor

Add client-fvt, fix the three defects it found, and update the project's front-door documents

client-fvt is a new Functional Verification Test suite for the connector context clients - the typed
clients (CollectionClient, AssetClient, ProjectClient, ...) that the platform hands to a connector
through its ConnectorContext. Each is driven through its own create / retrieve / search / update / delete
surface against a real PostgreSQL-backed repository.

./gradlew :open-metadata-test:open-metadata-fvt:client-fvt:test -PrunClientFvt

54 test cases - 53 passing, 1 disabled - covering every one of the 51 clients the connector context hands
out.
A full run takes about a minute. Like its sibling suites it is opt-in, and skipped by a normal build.

Writing it found three defects. Two are fixed here; the third is a feature that was never implemented, and is
reported rather than guessed at.

This PR also carries two unrelated documentation changes that were ready at the same time: a code of conduct
section on the use of AI tools, and a refresh of the top-level README.

It needs Kafka

This is the first FVT suite that does. query-fvt and type-fvt both run their access services without topics;
this one declares an event bus and uses configureAllAccessServices - with topics - under the topic root
egeria.omag.client-fvt, unique to the suite so its events cannot be confused with anything else on the same
broker. Exercising the clients with the event infrastructure switched on is the point: a client call that
behaves correctly against a silent server but trips over event publication is exactly the kind of fault this
suite exists to surface.

One environment detail is documented in application.properties because it costs an hour to work out
otherwise: the broker address must be Kafka's EXTERNAL advertised listener, not the internal one. The
suite runs on the host rather than inside the docker network, and a client that connects on the internal
listener is handed back an address it cannot resolve.

The platform listens on 9448 and the repository uses its own schema, so all three FVT suites can run side by
side.

Coverage that cannot silently fall behind

Unlike type-fvt, whose coverage follows the type system automatically, this suite has to be extended as the
client interfaces grow: every client has its own method names, its own properties bean and its own idea of a
sensible instance, so coverage cannot be derived.

ClientCatalog is the single file to edit, and ClientCoverageFVT enforces it:

  • a client on the connector context that the catalog does not mention fails the run, naming it - so a new
    client cannot be added without this suite noticing;
  • a catalog entry naming a client that no longer exists also fails, so entries cannot rot;
  • every client the catalog claims is under test must be obtainable from a live context, so a getter returning
    null cannot leave tests silently doing nothing.

What reflection cannot police is a new method on an already-listed client. That still needs an assertion
written by hand, and the README says so.

How the tests are organised

Class Cases Covers
ClientLifecycleFVT 35 the clients sharing the standard lifecycle surface
ReadAndReferenceClientFVT 7 generic store, types client, classification explorer, lineage, supply chains, specification properties, valid metadata values
FeedbackClientFVT 6 comments, likes, ratings, search keywords, property facets, note logs
AttachmentClientFVT 3 contribution records, translations, the template classification
ClientCoverageFVT 3 catalog and connector context agree, both directions

Thirty-five clients share a uniform shape - create<Stem>, get<Stem>ByGUID, get<Stem>sByName,
find<Stem>s, update<Stem>, delete<Stem> - so one ClientExerciser drives all of them rather than 35
near-identical test classes, with one named test case each. Arguments are bound by parameter type, not
position
, which absorbs the clients taking extra arguments the others do not (ProjectClient has an
additional classification name) instead of breaking on them.

The rest attach something to an element another client must create first, so each is driven against a host
element its test creates: attach, assert it appears on the element, remove, assert it is gone.

What the assertions prove

Worth stating, so a green run is not read as more than it is:

  • create, getByGUID and update are strict.
  • getByName and find check the call executes, not that it returns this run's element. Clients differ
    in which property their by-name search covers, so a generic driver cannot assert a hit without knowing each
    client's search property - and query-fvt already covers whether queries return the right results.
  • Only qualifiedName, displayName and name are set on each properties bean. Whether a type's own
    attributes round-trip is type-fvt's job, and it covers every attribute of every type.

The three defects

1. TemplateClient.getTemplatesByName(...) failed with a 500 - fixed.

TemplateHandler.getSearchClassifications had a copy-paste fault: the block that should have populated the
resourceName condition set its property, operator and value on the displayName condition instead. Two
consequences, and they explain both symptoms - one condition went into the search completely empty, which
the repository rejects (OMRS-REPOSITORY-400-074, reported by the server as a 500), and displayName was
overwritten, so the property that actually identifies a template was never searched.

The resourceName condition should not have been there at all: resourceName is an Asset property, not one
of the four the Template classification declares. A template is identified by the displayName on the
Template classification, not on the entity - the entity's own properties describe what the template will
produce and are typically placeholders. The search now covers displayName, description and
versionIdentifier on the classification, built in a loop so the same fault cannot recur, and
AttachmentClientFVT asserts the full round trip: classify, find by name, declassify, no longer found.

2. ValidMetadataValuesClient threw a NullPointerException without an audit log - fixed.

The audit log is optional throughout the framework: ConnectorContextBase accepts null and the handlers guard
their logging with if (auditLog != null). ValidMetadataValueHandler's four calls did not, so any caller
without an audit log got an NPE instead of a valid metadata value.

The same latent fault was in OpenMetadataHandlerBase - one unguarded logException in the shared base class
that every handler inherits, on the path taken when an anchor cannot be retrieved during a governance-zone
check. That one is the more dangerous of the two: it sits in an error path, so it would turn a handled,
logged problem into an NPE at an unpredictable moment. It was only found by checking the convention rather
than patching the single call site that had failed.

All five call sites now follow the house style, and no unguarded auditLog.log* call remains in the handlers.
The suite passes a null audit log, like query-fvt and type-fvt, so the guard is what the run exercises.

3. The multi-language operations are not implemented on the server - reported, not fixed.

setTranslation, clearTranslation, getTranslation and getTranslations in OpenMetadataStoreRESTServices
are all // todo stubs: they log the call and return an empty response without touching the repository. So
setTranslation reports success while storing nothing, and getTranslation always returns null.

The type model already has what the feature needs - a TranslationDetail entity carrying language,
languageCode, locale, displayName, description and additionalTranslations, plus a TranslationLink
relationship. Only the service implementation is missing, and how translations should be anchored and matched
is a design decision rather than something to infer from an empty method.

AttachmentClientFVT's translation test is therefore @Disabled, with the four stubbed methods named in
the reason, and its body is the real round-trip test ready to run unchanged once the feature exists. It is
disabled rather than reduced to a call-completes check, because such a check would pass against the stubs and
prove nothing.

Project documents

Unrelated to the suite above, and reviewable on their own:

CODE_OF_CONDUCT.md gains a section on the use of AI tools. It states that their use is encouraged, and
that the human contributor is always responsible for the quality of what they produce with them - "the AI made
a mistake" is not an excuse. The attribution line now notes that the document has been modified from the
Hyperledger original to cover this.

README.md is tightened: the project description now says Egeria lets tools exchange "metadata and
context" rather than just metadata, several paragraphs that were split mid-sentence are joined up, the
getting-started blog link is replaced by a single pointer to the project website, and an acknowledgement is
added that Egeria is part of the Linux Foundation AI and Data Foundation.
Every link in the file resolves.

The YourKit acknowledgement is removed, since that licence has lapsed. It went from CodeQualitySecurity.md
as well as the README - that file listed the profiler among the tools "Egeria employs", so dropping only the
credit would have left the project still claiming a tool it no longer uses while no longer crediting it.

Testing

  • client-fvt: 54 cases, 53 passing, 1 disabled.
  • OpenMetadataTypeTest passes; the framework compiles clean.
  • The two fixes are verified by the suite itself - the template round trip and the null-audit-log path are
    both asserted rather than assumed.

Signed-off-by: Mandy Chessell <mandy.e.chessell@gmail.com>
@mandy-chessell
mandy-chessell merged commit 4e39f8e into odpi:main Aug 22, 2026
4 checks passed
* exercised somewhere. Kept so that a genuine future exclusion has an obvious, documented home rather
* than being hidden inside a test.
*/
private static final Map<String, String> NOT_YET_COVERED = new LinkedHashMap<>();
@Bean
public SecurityFilterChain clientFvtSecurityFilterChain(HttpSecurity http) throws Exception
{
http.csrf(csrf -> csrf.disable())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants