// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package proxycfg import ( "fmt" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul/discoverychain" "github.com/mitchellh/go-testing-interface" "github.com/hashicorp/consul/agent/configentry" "github.com/hashicorp/consul/agent/structs" ) func TestConfigSnapshotAPIGateway( t testing.T, variation string, nsFn func(ns *structs.NodeService), configFn func(entry *structs.APIGatewayConfigEntry, boundEntry *structs.BoundAPIGatewayConfigEntry), routes []structs.BoundRoute, certificates []structs.InlineCertificateConfigEntry, extraUpdates []UpdateEvent, additionalEntries ...structs.ConfigEntry, ) *ConfigSnapshot { roots, placeholderLeaf := TestCerts(t) entry := &structs.APIGatewayConfigEntry{ Kind: structs.APIGateway, Name: "api-gateway", } boundEntry := &structs.BoundAPIGatewayConfigEntry{ Kind: structs.BoundAPIGateway, Name: "api-gateway", } if configFn != nil { configFn(entry, boundEntry) } baseEvents := []UpdateEvent{ { CorrelationID: rootsWatchID, Result: roots, }, { CorrelationID: leafWatchID, Result: placeholderLeaf, }, { CorrelationID: gatewayConfigWatchID, Result: &structs.ConfigEntryResponse{ Entry: entry, }, }, { CorrelationID: gatewayConfigWatchID, Result: &structs.ConfigEntryResponse{ Entry: boundEntry, }, }, } for _, route := range routes { // Add the watch event for the route. watch := UpdateEvent{ CorrelationID: routeConfigWatchID, Result: &structs.ConfigEntryResponse{ Entry: route, }, } baseEvents = append(baseEvents, watch) // Add the watch event for the discovery chain. entries := []structs.ConfigEntry{ &structs.ProxyConfigEntry{ Kind: structs.ProxyDefaults, Name: structs.ProxyConfigGlobal, Config: map[string]interface{}{ "protocol": route.GetProtocol(), }, }, &structs.ServiceResolverConfigEntry{ Kind: structs.ServiceResolver, Name: "api-gateway", }, } set := configentry.NewDiscoveryChainSet() set.AddEntries(entries...) // Add a discovery chain watch event for each service. for _, serviceName := range route.GetServiceNames() { discoChain := UpdateEvent{ CorrelationID: fmt.Sprintf("discovery-chain:%s", UpstreamIDString("", "", serviceName.Name, &serviceName.EnterpriseMeta, "")), Result: &structs.DiscoveryChainResponse{ Chain: discoverychain.TestCompileConfigEntries(t, serviceName.Name, "default", "default", "dc1", connect.TestClusterID+".consul", nil, set), }, } baseEvents = append(baseEvents, discoChain) } } for _, certificate := range certificates { inlineCertificate := certificate baseEvents = append(baseEvents, UpdateEvent{ CorrelationID: inlineCertificateConfigWatchID, Result: &structs.ConfigEntryResponse{ Entry: &inlineCertificate, }, }) } upstreams := structs.TestUpstreams(t, false) baseEvents = testSpliceEvents(baseEvents, setupTestVariationConfigEntriesAndSnapshot( t, variation, false, upstreams, additionalEntries..., )) return testConfigSnapshotFixture(t, &structs.NodeService{ Kind: structs.ServiceKindAPIGateway, Service: "api-gateway", Address: "1.2.3.4", Meta: nil, TaggedAddresses: nil, }, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates)) } // TestConfigSnapshotAPIGateway_NilConfigEntry is used to test when // the update event for the config entry returns nil // since this always happens on the first watch if it doesn't exist. func TestConfigSnapshotAPIGateway_NilConfigEntry( t testing.T, ) *ConfigSnapshot { roots, _ := TestCerts(t) baseEvents := []UpdateEvent{ { CorrelationID: rootsWatchID, Result: roots, }, { CorrelationID: gatewayConfigWatchID, Result: &structs.ConfigEntryResponse{ Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist. }, }, { CorrelationID: gatewayConfigWatchID, Result: &structs.ConfigEntryResponse{ Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist. }, }, } return testConfigSnapshotFixture(t, &structs.NodeService{ Kind: structs.ServiceKindAPIGateway, Service: "api-gateway", Address: "1.2.3.4", Meta: nil, TaggedAddresses: nil, }, nil, nil, testSpliceEvents(baseEvents, nil)) }