Return ConditionUnknown from Unknown() - #72
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @thc1006. Thanks for your PR. I'm waiting for a nephio-project member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
cf57207 to
587bcfc
Compare
Unknown() is named, documented and reasoned as reporting an unknown state,
but it returned metav1.ConditionFalse. Failed() a few lines below returns the
same status, so the two were distinguishable only by their Reason, and a
consumer switching on Status read "not known yet" as "definitely failed".
metav1.ConditionUnknown exists for exactly the state this constructor names.
The generated CRDs already advertise the third state. The manifests under
config/crd/bases whose status is built from these packages carry
status:
description: status of the condition, one of True, False, Unknown.
enum: ["True", "False", Unknown]
so the published schema promises a tri-state that the one constructor meant
to produce it could not emit. ConditionReasonUnknown was declared and used
while metav1.ConditionUnknown appeared nowhere in either package.
This is not a regression. infra/v1alpha1/condition.go was introduced by
3316d8b (nephio-project#23) on 2023-05-11 and the line has not been modified since;
cfg/v1alpha1/condition.go is a later whole-file copy of it, added by ceb0d10
(nephio-project#46) on 2023-06-15.
Both packages are fixed together. They export a helper of the same name with
the same documented contract, so correcting only one would make the returned
status depend on which package a caller imports, which is worse than the
uniform defect it replaces. cfg/v1alpha1 has no importers I could find while
infra/v1alpha1 has many, but both are published API.
TestUnknown asserts the status alone, which is the field this change alters.
The constructors were already executed by TestConditionedStatusEqual and
TestSetConditions, so they were at 100% statement coverage before this change;
what was missing was any assertion on the value they return.
No in-tree or publicly indexed caller of Unknown() was found, in this
repository, in nephio, in oai, or in the public importers of this module.
That is a narrower claim than no impact: this changes the observable
behaviour of an exported function, and unindexed consumers may exist.
Left alone deliberately. ConditionedStatus.GetCondition() collapses the same
tri-state in the other direction by synthesising ConditionFalse when no
condition of the requested type exists, which is a separate API decision. The
whole-file duplication between the two packages is the reason one defect
could exist twice, but deduplicating them is a refactor. The pinned
nokia/k8s-ipam dependency carries the same defect in its own copy and has
active callers that persist it; that belongs upstream, not here.
Signed-off-by: thc1006 <hctsai1006@cs.nctu.edu.tw>
587bcfc to
719180f
Compare
|
Both API packages now return I have also corrected several factual errors in the description: the implementation being changed came from The full Go suite, a race run, vet, golangci-lint, gosec, gofmt and diff checks are clean locally. Sonar is green, though I have noted in the description that this is because it skips duplication and coverage conditions below 20 new lines, not because the two packages stopped being whole-file duplicates. Could a project member please |
|



This patch makes
Unknown()returnmetav1.ConditionUnknownin bothcfg/v1alpha1andinfra/v1alpha1. It previously returnedmetav1.ConditionFalse, which is the statusFailed()returns a few lines below, so the two were distinguishable only by theirReasonand a consumer switching onStatusread "not known yet" as "definitely failed".metav1.ConditionUnknownexists for exactly the state this constructor names.The generated schema already promises the third state
Quoting
config/crd/bases/infra.nephio.org_repositories.yaml, and the other manifests whose status is built from these packages:The published contract is a tri-state, while the one constructor meant to produce the third value could not emit it.
ConditionReasonUnknownwas declared and used;metav1.ConditionUnknownappeared nowhere in either package.This is not a regression.
infra/v1alpha1/condition.gowas introduced by3316d8b(#23) on 2023-05-11 and the line has not been modified since.cfg/v1alpha1/condition.gois a later whole-file copy of it, added byceb0d10(#46) on 2023-06-15.Why both packages
An earlier revision of this PR fixed
infra/v1alpha1only. That was wrong, and I have corrected it.The two packages export a helper of the same name with the same documented contract. Fixing one would make
Unknown().Statusdepend on which package a caller imports, which is a worse state than the uniform defect it replaces — andNetworkappears to be moving frominfra.nephio.orgtoconfig.nephio.org, so the migration target would have been the broken one.cfg/v1alpha1has no importers I could find andinfra/v1alpha1has many, but both are published API.Impact
No in-tree or publicly indexed caller of
Unknown()was found — not in this repository, innephio-project/nephio, innephio-project/oai, or among the public importers of this module. That is deliberately narrower than saying there is no impact: this changes the observable behaviour of an exported function in a published module, and unindexed consumers may exist.Worth flagging separately: the pinned
nokia/k8s-ipamdependency carries the same defect in its own copy of this file, and unlike here it has roughly twenty-seven live callers across six reconcilers that persist the result throughStatus().Update(). So resources written by that controller do carrystatus: Falsewithreason: Unknowntoday. That is not affected by this PR and should be raised upstream, but it means any ecosystem-wide claim about serialised conditions would be wrong.About the SonarCloud result
The gate is green, but not because the duplication went away. On this revision Sonar reports 14 new lines, 14 duplicated new lines, and a density of 100%, against a threshold of 3. It passes only because it returns
ignoredConditions: true: per the SonarQube Cloud documentation, "Conditions on Coverage and Duplicated lines are not calculated when there are fewer than 20 lines."cfg/v1alpha1/condition.goandinfra/v1alpha1/condition.goare whole-file duplicates of each other, as are their tests, so anything added to both lands inside a matching block. An earlier revision added a thirteen-line testify-based test to each file, came to 30 new lines, lost the exemption and failed the gate outright. The density is the same either way; only the line count changed.I would rather state that than let a green check imply the duplication was resolved. Deduplicating the two packages is the real fix and is out of scope here.
What is deliberately left alone
ConditionedStatus.GetCondition()collapses the same tri-state in the other direction: it synthesisesConditionFalsewhen no condition of the requested type exists, while its doc comment says it "returns nil". Whether absence should read as unknown is a separate decision about public API semantics.The whole-file duplication between the two packages, and the same defect in the upstream copies this file descends from, are likewise out of scope.
Proof
The new test asserts the status alone, which is the field this change alters:
It was run with
-vto confirm it executes rather than silently matching nothing, and checked against the unfixed code in both packages. Reverting eitherStatusline fails that package's test:go test ./... -count=1(three consecutive runs),go test -race ./cfg/v1alpha1 ./infra/v1alpha1 -count=10,TestUnknown -count=100,go vet ./...,golangci-lint run ./...(0 issues),gosec ./...(0 issues),gofmt -l, andgit diff --checkare all clean.make unitandmake lintshell out to a container runtime that is not available here, so the commands from their non-container branches were run directly.Note that
.golangci.ymlsetsskip-files: ".*_test.go$", so the added test is not linted or gofmt-checked by CI;gofmt -lwas run on it directly.A note on the test placement
The regression check could instead be folded into the existing
DifferentStatuscase inTestConditionEqual, by settinga: Unknown()against a literalConditionFalsecondition. I built that variant from4827d95and measured it: it is+6/-6across the same four files, it passes, and reverting either production line does fail that package's test. So it works, and it is eight lines lighter.I kept the standalone test for one reason that survived the comparison. Both variants sit at 100% duplicated new lines and both are green only through the under-20-lines exemption, so neither actually reduces duplication — but they differ in what a future failure tells you. This version reports
Unknown().Status = "False", want "Unknown", which names the defect. The folded version reportsTestConditionEqual/DifferentStatus, which points a reader atEqual()rather than at the constructor that regressed, and it converts a case that currently exercisesEqual()with plainTrue/Falsefixtures into one that also depends onUnknown().That is a judgement call rather than a clear win, and the eight lines are a real cost. Happy to switch if you prefer the shorter diff.