Skip to content

Declared validation rules that no test exercises #572

Description

@retr0h

Most domains declare validation the tests never exercise. Removing one of those tags from a spec would change nothing a test could see.

Corrected method

This issue originally counted test methods named ValidationHTTP and concluded log had none. That was wrong: log tested valid_target and the priority oneof inside a method named TestGetNodeLogHTTP. Counting names measures naming, not coverage.

The right comparison is the validate: tags each spec declares against the rule names the tests assert:

python3 - <<'PY'
import pathlib, re
for d in sorted(pathlib.Path('internal/controller/api/node').iterdir()):
    spec = d/'gen'/'api.yaml'
    if not spec.is_file(): continue
    rules = {p.strip().split('=')[0]
             for m in re.findall(r'validate:\s*"?([^"\n]+)"?', spec.read_text())
             for p in m.split(',')
             if p.strip() and p.strip().split('=')[0] not in ('omitempty','required')}
    asserted = {m for t in d.glob('*_test.go')
                  for m in re.findall(r'Body\.String\(\), "([a-z_]+)"', t.read_text())}
    print(f"{d.name:14} {len(rules):5} {len(rules & asserted):6}  {' '.join(sorted(rules - asserted)) or '-'}")
PY

What it finds

domain         rules tested  untested
hostname           3      0  max min valid_target
schedule           7      1  cron_schedule excluded_with max min oneof required_without
file               5      1  file_mode max min oneof
user               4      1  account_name dive min
container          6      3  dive min oneof
network           12      6  dive ipv4 ipv6 max min required_without
process            3      1  min oneof
certificate        2      1  min
command            3      2  min
ntp                2      1  min
package            2      1  min
power              2      1  min
service            2      1  min
sysctl             4      3  min
timezone           2      1  min
log                4      4  -

log is covered as of #578. Everything else has a gap.

Priority

hostname is the worst at 0 of 3, and it is the one the original method-name count missed completely, because it has a method named ValidationHTTP that asserts no rule by name.

After that, by how much a missed rule would cost:

  1. valid_target, oneof, ipv4, ipv6, file_mode, cron_schedule, account_name reject input that would otherwise reach a provider and fail somewhere less legible.
  2. excluded_with and required_without encode a relationship between two fields, which is the kind of rule that quietly stops working when a field is renamed.
  3. min and max are the most commonly untested and the least costly. min=1 beside required is close to redundant; max on a bounded query parameter is not.

The obligation

osapi-io/specs#244 states it: the test asserts 400 and that the body names the rule that rejected it. A test checking only the status code passes when the handler rejects for an unrelated reason, which is the failure it exists to catch.

name: "when lines below the minimum returns 400",
path: "/api/node/server1/log?lines=0",
    s.Equal(http.StatusBadRequest, rec.Code)
    s.Contains(rec.Body.String(), "min")

Asserting the rule name is also what makes the audit above possible, since it is what the script greps for.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions