Run the conformance harness¶
The compiler checks that your provider has the right methods. It cannot check
that those methods behave the way a consumer relies on: that a read-only
config yields nothing to post through, that Close is safe twice, that the
capabilities you declare are the ones you have.
RunProviderConformance checks that, and it runs without a network.
Add it to your provider's tests¶
package myplatform_test
import (
"testing"
chatplatform "gitlab.com/phpboyscout/go/chat-platform"
chatplatformtest "gitlab.com/phpboyscout/go/chat-platform/test"
myplatform "gitlab.com/phpboyscout/go/chat-platform-myplatform"
)
func TestConformance(t *testing.T) {
t.Parallel()
chatplatformtest.RunProviderConformance(t, chatplatformtest.ConformanceConfig{
NewClient: func(cfg chatplatform.ClientConfig) (chatplatform.Client, error) {
return myplatform.New(cfg)
},
Capabilities: chatplatformtest.Capabilities{
Moderator: true,
MemberInspector: true,
Interactive: true,
Commands: true,
},
Space: "1531227937678954747",
AllowedChannel: "1531227938622800055",
})
}
Space and AllowedChannel must be syntactically valid identifiers for your
platform. They are never dialled; the harness only needs values your
constructor will accept.
Declare capabilities honestly¶
Capabilities exists so the harness can tell "correctly does not offer this"
apart from "should and does not". It is checked in both directions:
- Claim one you lack, and the harness looks for something impossible.
- Omit one you have, and it tells you, because a capability nobody declares is a capability nobody discovers.
Declare what you can never serve¶
A transport that carries audio only (a voice node with no gateway) cannot
serve NeedMessages, and the contract says it refuses that at construction
rather than carrying it onto a scope whose Messages() never yields. Tell the
harness with Refuses:
chatplatformtest.ConformanceConfig{
NewClient: func(cfg chatplatform.ClientConfig) (chatplatform.Client, error) {
// Discord's node takes no ClientConfig at all; only the needs cross.
return voicenode.New(voicenode.Config{Control: fakeLink, Self: self, Needs: cfg.Needs})
},
Refuses: []chatplatform.Need{chatplatform.NeedMessages},
Capabilities: chatplatformtest.Capabilities{VoiceReceiver: true, VoiceSender: true},
// ...
}
For each need named, the harness asks for a client with that need alone and
requires a nil Client and an error matching ErrUnsupported that names the
need. The rest of the run declares every need except those, so the transport is
tested for what it serves. Like Capabilities, it is trusted: a transport that
should refuse and names nothing here is not caught.
Why it runs offline¶
Because it has to run in CI, on a fork, and on a laptop with no credentials.
That constraint is load-bearing rather than a convenience, and it is worth
stating plainly: if your provider cannot be constructed without a real token,
it cannot be conformance-tested. The Discord provider failed its very first
run for exactly this reason, and the fix was to move client construction out of
New and into Connect, which is a better contract anyway. See
Author a provider.
What belongs elsewhere¶
Behaviour needing a live platform (that a thread is really created, that the allowlist really filters an inbound feed, that a dropped connection really resumes) belongs in your own integration tests, gated behind an environment variable or a build tag.
The chat-platform-discord module keeps its forced-disconnect regression test
behind an integration build tag for this reason: it cuts a real TCP
connection and needs live credentials, so it is run locally and before a
release rather than on every merge.
Reading a failure¶
Failures are reported as method: message. Treat one as a finding about your
provider before you treat it as one about the harness.
On the Discord provider's first run the harness reported that the provider could not be constructed at all, and that an implemented capability was not declared. Both were real.
What the harness checks, and what it leaves to you¶
Every assertion it makes, the exact message each produces, and the list of real
contract behaviour it cannot check offline (the allowlist, ErrNotConnected,
Connect itself) are in
the conformance harness reference.
Passing means the contract a consumer depends on before a single message arrives is honoured. It does not mean the provider works.