69 lines
3.5 KiB
Go
69 lines
3.5 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-controller/internal/conditions"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
"github.com/novox/mesh-controller/internal/link"
|
|
)
|
|
|
|
// A provider whose wait fails the controller's check lists who waits on it (novox/hq issue 450).
|
|
//
|
|
// A wait that does not check out is judged unhealthy (ADR 0283 decision 3), so the provider raises its unhealthy
|
|
// condition and its consumers are held under it (ADR 0240 rule 5). What is stored is what the machine said, the
|
|
// wait unchecked: read as said, the provider seems to wait for the operator, and the held consumers were never
|
|
// listed on the condition that is open.
|
|
|
|
// refusedWait is a wait for a secret the database's manifest does not declare: it fails the check.
|
|
var refusedWait = inventory.Wait{Part: "postgres-database", Secret: "certificate", What: "the database's certificate"}
|
|
|
|
// judgedRefused is the provider's resource as the controller judges it: unhealthy, saying why.
|
|
func judgedRefused() inventory.ResourceHealth {
|
|
r := waitingDatabaseFor(refusedWait)
|
|
r.State, r.Waits = link.StateUnhealthy, nil
|
|
r.Reason = "says it waits for the secret certificate, which db does not declare"
|
|
return r
|
|
}
|
|
|
|
// The consumer's statement arrives after the provider's, so it is the consumer's judging (sayWaiters) that must list
|
|
// it at the provider's unhealthy condition, made urgent by who waits on it.
|
|
func TestAProviderWhoseWaitFailedItsCheckListsWhoWaitsOnIt(t *testing.T) {
|
|
k, _ := withConditionsInMemory(t)
|
|
stored := waitingDatabaseFor(refusedWait)
|
|
open := judgeBoth(t, k, []inventory.ResourceHealth{judgedRefused()},
|
|
map[string]inventory.NodeHealth{"anchor": {Node: "anchor", Resources: []inventory.ResourceHealth{stored}}},
|
|
shopFailingBeside(stored))
|
|
provider := conditionOf(open, moduleUnhealthyKey("db", "anchor"))
|
|
if len(open) != 1 || provider == nil {
|
|
t.Fatalf("a provider whose wait failed its check and a consumer of it raised %v; want the provider's "+
|
|
"unhealthy alone", openKeysOf(open))
|
|
}
|
|
if said := provider.Evidence[0].Said; !strings.Contains(said, "shop on laptop") {
|
|
t.Fatalf("the provider's unhealthy condition does not list shop on laptop as waiting on it: %s", said)
|
|
}
|
|
if provider.Severity != conditions.Urgent {
|
|
t.Fatalf("the provider's unhealthy condition is %s with a consumer waiting on it; want urgent", provider.Severity)
|
|
}
|
|
}
|
|
|
|
// A provider that waits for a secret already given is unhealthy to its consumers too, before its own condition opens:
|
|
// they are held under it as under any unhealthy provider, never as waiting for the operator, and its condition, when
|
|
// open, is said as unhealthy with who waits on it.
|
|
func TestAProviderWaitingForASecretAlreadyGivenIsUnhealthyToItsConsumers(t *testing.T) {
|
|
given := holdingOf(nil, shopFailingBeside(waitingDatabase()), shopOnTheDatabase)
|
|
given.waits.given["db@anchor"] = map[string]time.Time{"licence": time.Now().Add(-time.Hour)}
|
|
by, held := given.heldWith("laptop", "shop", []inventory.ResourceHealth{failingConsumer("shop")})
|
|
if !held || by.provider != theDatabase || len(by.waits) > 0 {
|
|
t.Fatalf("shop under a database waiting for a licence already given: held %v under %v with waits %v; want "+
|
|
"held under db on anchor as unhealthy, no waits", held, by.provider, by.waits)
|
|
}
|
|
if _, uncovered := given.waitingUncovered("laptop", "shop", []inventory.ResourceHealth{failingConsumer("shop")}); uncovered {
|
|
t.Fatalf("a provider whose wait failed its check is said as waiting for another part")
|
|
}
|
|
}
|