mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
62e7f983ee
* test: assert the gateway->vpcd->OVN crossing in the integration tier
The tier already ran the real VPCServiceImpl for the AWS-facing half, but
nothing consumed the vpc.* events it published: the SG topics were answered
by a canned {"success":true} and the fire-and-forget topology topics were
dropped. Both sides of that wire were tested only against stubs, so the join
was asserted nowhere below the live e2e tier.
Wire a real subscribers.Subscriber over a real in-process OVN Northbound DB
(ovntest.StartNB), opt-in per test so only tests that assert OVN state pay
the startup cost. StartDaemonLite gains WithRealVPCD to suppress its stubs,
since a stub and the subscriber both answering one request-reply would race.
Scope is the crossing, not NB row shapes — those stay with the reconcile
scenario tests. Everything host-dependent (ovn-controller, OVS, taps, netns,
nftables, packet paths) remains the live tier's claim.
* fix: make the integration tier re-runnable and quiet the ensure probe
Two defects the vpcd/OVN work surfaced.
The tier was green at -count=1 and red package-wide at -count=2. Test
accounts were keyed by t.Name(), which is unique among tests but repeats
across passes in one TestMain, so a second pass inherited the first pass's
JetStream namespace — including an ECR signing key sealed with a master key
StartGateway regenerates per call. Key each account off a counter instead.
TestRunInstances_ClientTokenIdempotency then collided with itself for the
same reason: its dedup store outlives a pass, so its fixed ClientToken made
the second pass's opening launch look like a replay. Suffix the tokens per
invocation.
ensureNamedRowOps' wait-op is built to fail fast when the row it guards
already exists, which is the ordinary idempotent path, but transactOps
reported it as "OVSDB operation failed" at ERROR. Every re-ensure emitted
one, drowning real faults in the log sink. Classify that one result as the
probe outcome it is and log it at Debug.
* test: cover transactOps' failed-result paths
The classifier split one log line into two branches and neither was
exercised: transactOps sat at 31% because EnsureLogicalRouter's cache
lookup absorbs a re-ensure before it ever transacts, so no unit test
reached a failed operation result.
Drive both kinds directly against a real NB — the guard probe finding an
existing row, and two same-named inserts violating the schema's name
index — since only the second is a fault and they now log at different
levels. transactOps goes to 94%; the remainder is the transport-error
return, which needs a broken connection to reach.
99 lines
3.2 KiB
Go
99 lines
3.2 KiB
Go
//go:build integration
|
|
|
|
package integration
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/mulgadc/spinifex/spinifex/network/subscribers"
|
|
"github.com/mulgadc/spinifex/spinifex/network/topology"
|
|
"github.com/nats-io/nats.go"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// startVPCDEvents wires a real vpcd consumer over a real OVN NB DB with no
|
|
// daemon behind it. These tests publish the vpc.* events directly because the
|
|
// property under test is delivery order, which the SDK path cannot produce on
|
|
// demand: through it, CreateVpc necessarily precedes CreateSubnet.
|
|
func startVPCDEvents(t *testing.T) (*VPCDLite, *nats.Conn) {
|
|
t.Helper()
|
|
gw := StartGateway(t)
|
|
return StartVPCDLite(t, gw), gw.NATSConn
|
|
}
|
|
|
|
// publishEvent marshals and fires a fire-and-forget vpc.* topology event, the
|
|
// way handlers/ec2/vpc's publishVPCEvent/publishSubnetEvent do.
|
|
func publishEvent(t *testing.T, nc *nats.Conn, topic string, evt any) {
|
|
t.Helper()
|
|
payload, err := json.Marshal(evt)
|
|
require.NoError(t, err, "marshal %s event", topic)
|
|
require.NoError(t, nc.Publish(topic, payload), "publish %s", topic)
|
|
require.NoError(t, nc.Flush(), "flush %s", topic)
|
|
}
|
|
|
|
// countRouters returns how many logical routers carry name.
|
|
func countRouters(ctx context.Context, vpcd *VPCDLite, name string) (int, error) {
|
|
routers, err := vpcd.OVN.ListLogicalRouters(ctx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
n := 0
|
|
for _, r := range routers {
|
|
if r.Name == name {
|
|
n++
|
|
}
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
// TestVPCD_SubnetBeforeVPCConverges covers the case where vpc.create-subnet
|
|
// is delivered with no preceding vpc.create. The two topics have no ordering
|
|
// guarantee, so on new-tenant bootstrap the subnet can genuinely land first;
|
|
// the subnet handler's defensive pre-ensure is what stops that from being a
|
|
// dropped subnet.
|
|
//
|
|
// The convergence claim is the point: the pre-ensure creates the router
|
|
// without a CIDR, and the real vpc.create arriving afterwards must fill it in
|
|
// rather than being discarded as a duplicate or forking a second router.
|
|
func TestVPCD_SubnetBeforeVPCConverges(t *testing.T) {
|
|
vpcd, nc := startVPCDEvents(t)
|
|
ctx := context.Background()
|
|
|
|
const vpcID, subnetID = "vpc-order-a", "subnet-order-a"
|
|
router := topology.VPCRouter(vpcID)
|
|
|
|
publishEvent(t, nc, subscribers.TopicSubnetCreate, subscribers.SubnetEvent{
|
|
SubnetId: subnetID,
|
|
VpcId: vpcID,
|
|
CidrBlock: "10.50.1.0/24",
|
|
})
|
|
|
|
awaitNB(t, "logical switch for subnet-first delivery", func(ctx context.Context) error {
|
|
_, err := vpcd.OVN.GetLogicalSwitch(ctx, topology.SubnetSwitch(subnetID))
|
|
return err
|
|
})
|
|
|
|
publishEvent(t, nc, subscribers.TopicVPCCreate, subscribers.VPCEvent{
|
|
VpcId: vpcID,
|
|
CidrBlock: "10.50.0.0/16",
|
|
})
|
|
|
|
awaitNB(t, "VPC CIDR backfilled onto pre-ensured router", func(ctx context.Context) error {
|
|
lr, err := vpcd.OVN.GetLogicalRouter(ctx, router)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if got := lr.ExternalIDs["spinifex:cidr"]; got != "10.50.0.0/16" {
|
|
return fmt.Errorf("spinifex:cidr = %q, want 10.50.0.0/16", got)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
n, err := countRouters(ctx, vpcd, router)
|
|
require.NoError(t, err, "list logical routers")
|
|
require.Equal(t, 1, n, "out-of-order delivery forked %s into %d routers", router, n)
|
|
}
|