ec5167de3a
The package comment, the embedder log and the startup line all said enrolment was live and only recognition was blocked. Enroll embeds every sample before it stores anything, so with no model on the box it fails on the first sample with ErrDisabled and nothing is ever stored. List then returns an empty list forever and Forget has nothing to delete. The shipped state was three methods, all no-ops, announced as a working half. SpeakerConfig.Recognizes was written as the gate for this and never called, so a block with enabled and no model_path wired everything and skipped the one warning the operator needed. It is the gate now, and that config shape logs why it stayed off. Three smaller repairs. ErrDisabled had no case in speakerErr and reached the surface as an opaque core failure, when it means the same thing ErrUnknownMethod does. Forget read the row first and answered ErrNotFound on a second call, so the layer documented as the one that must always work reintroduced a failure for a voiceprint that was already gone. And a row with unparsable metadata listed as a plausible profile named after its own id with 0 samples, which is what a real minimal enrolment looks like; it is reported as damaged now. Found in review of #74.
51 lines
1.7 KiB
Go
51 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/kami/maven/internal/config"
|
|
"github.com/kami/maven/internal/ipc"
|
|
"github.com/kami/maven/internal/speaker"
|
|
)
|
|
|
|
// "enabled": true with no model_path used to wire all three methods and log
|
|
// "enrolment on". Nothing behind them works without an embedder, so the
|
|
// capability stays off and the socket answers "no such method".
|
|
func TestSpeakerStaysOffWithoutAModelPath(t *testing.T) {
|
|
srv := &ipc.Server{}
|
|
cfg := &config.Config{Speaker: &config.SpeakerConfig{Enabled: true}}
|
|
|
|
wireSpeaker(srv, nil, cfg)
|
|
|
|
if srv.EnrollSpeakerFn != nil || srv.ListSpeakersFn != nil || srv.ForgetSpeakerFn != nil {
|
|
t.Error("speaker methods were wired with nothing to embed with")
|
|
}
|
|
}
|
|
|
|
// The gate is Recognizes(), so a disabled block with a model path is off too.
|
|
func TestSpeakerStaysOffWhenDisabled(t *testing.T) {
|
|
srv := &ipc.Server{}
|
|
cfg := &config.Config{Speaker: &config.SpeakerConfig{ModelPath: "/nope/ecapa.onnx"}}
|
|
|
|
wireSpeaker(srv, nil, cfg)
|
|
|
|
if srv.EnrollSpeakerFn != nil {
|
|
t.Error("speaker methods were wired for a disabled block")
|
|
}
|
|
}
|
|
|
|
// ErrDisabled is "this capability is off", not "core broke". It used to fall
|
|
// through speakerErr's default and reach the surface as an opaque failure.
|
|
func TestSpeakerErrMapsDisabledToUnknownMethod(t *testing.T) {
|
|
if got := speakerErr(speaker.ErrDisabled); !errors.Is(got, ipc.ErrUnknownMethod) {
|
|
t.Errorf("speakerErr(ErrDisabled) = %v, want ErrUnknownMethod", got)
|
|
}
|
|
if got := speakerErr(speaker.ErrNotFound); !errors.Is(got, ipc.ErrNoFact) {
|
|
t.Errorf("speakerErr(ErrNotFound) = %v, want ErrNoFact", got)
|
|
}
|
|
if got := speakerErr(nil); got != nil {
|
|
t.Errorf("speakerErr(nil) = %v", got)
|
|
}
|
|
}
|