New validation logic for addon metadata can be added by creating a validator under the validator package. Please check however to see if the validation you are implementing already fits under an existing validator. In that case it would be appropriate to just extend the functionality of the exising validator instead of creating a new one.
First determine the unique code to assign to the validator. This code will
be selected based on the existing validators and any validators that are
still works in progress. The code should equal n+1
where n
is the
current greatest validator code. Then choose a meaningful name and
description to describe the validator to end users as this is what
they will see when a validation result is returned to them.
Under the validator package create a subpackage named
for the unique code of your validator. For example, a validator with code
AM9999
will have a full import path of
github.com/mt-sre/addon-metadata-operator/pkg/validator/am9999
.
Within this package you should have at least two .go
files. One file
will implement the validator and the second will implement unit tests for
that validator.
Every validator must implement the validator.Validator
interface:
type Validator interface {
Code() Code
Name() string
Description() string
Run(context.Context, types.MetaBundle) Result
}
This is partially achieved by including a *validator.Base
as a
member of your validator. However the Run
method is up to you
to define. Luckily, the *validator.Base
helps with that by
providing some helper functions
(Success
, Fail
, Error
, RetryableError
) that ensures you
return a proper validator.Result
based on the logic of
your validator.
In addition to the validator itself your package must provide
an initializer type Initializer func(Dependencies) (Validator, error)
which injects dependencies from a validator.Runner
instance
and either returns an initialized validator.Validator
or an error.
This initializer must then be passed to the validator.Register
function
which should be called at the top of your validator implementation file.
Once your validator is implemented a minimum of two tests are required.
One test should validate at least one valid types.MetaBundle
that
will result in a success. A second test should do the same, but with
invalid bundles which produce a fail result. The
testutils package provides some helpers
to assist with this testing. Calling testutils.DefaultValidBundleMap
will provide bundles which should always pass validation. Additionally,
calling testutils.NewValidatorTester
will initialize your validator
with configuratble dependencies and offers two methods,
TestValidBundles
and TestInvalidBundles
which both accept a map
of descriptive names to bundles and ensure they are valid or invalid
respectively.
Once your validator is ready it must be imported within the
register package as a blank import.
Any packages which then import the register
package will register
the included validators with a validator.Runner
instance. This makes
it possible to isolate side-effectual imports during testing or other
unwanted scenarios.
Unit tests can be run using ./mage test:unit
and the go test
command
can be used to run specific tests directly.