2024-02-02 23:29:38 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package discovery
import (
"errors"
2024-02-09 22:41:40 +00:00
"fmt"
2024-02-02 23:29:38 +00:00
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/anypb"
"github.com/hashicorp/consul/agent/config"
mockpbresource "github.com/hashicorp/consul/grpcmocks/proto-public/pbresource"
"github.com/hashicorp/consul/internal/resource"
pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1"
"github.com/hashicorp/consul/proto-public/pbresource"
"github.com/hashicorp/consul/sdk/testutil"
)
2024-02-06 16:12:04 +00:00
var (
unknownErr = errors . New ( "I don't feel so good" )
)
2024-02-02 23:29:38 +00:00
// Test_FetchService tests the FetchService method in scenarios where the RPC
// call succeeds and fails.
func Test_FetchWorkload ( t * testing . T ) {
rc := & config . RuntimeConfig {
DNSOnlyPassing : false ,
}
tests := [ ] struct {
name string
queryPayload * QueryPayload
context Context
configureMockClient func ( mockClient * mockpbresource . ResourceServiceClient_Expecter )
expectedResult * Result
expectedErr error
} {
{
name : "FetchWorkload returns result" ,
queryPayload : & QueryPayload {
Name : "foo-1234" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
2024-02-09 22:41:40 +00:00
result := getTestWorkloadResponse ( t , "foo-1234" , "" , "" )
2024-02-02 23:29:38 +00:00
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : & Result {
2024-02-03 03:23:52 +00:00
Node : & Location { Name : "foo-1234" , Address : "1.2.3.4" } ,
Type : ResultTypeWorkload ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-02 23:29:38 +00:00
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
} ,
expectedErr : nil ,
} ,
{
name : "FetchWorkload for non-existent workload" ,
queryPayload : & QueryPayload {
Name : "foo-1234" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
2024-02-09 22:41:40 +00:00
input := getTestWorkloadResponse ( t , "foo-1234" , "" , "" )
2024-02-02 23:29:38 +00:00
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( nil , status . Error ( codes . NotFound , "not found" ) ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , input . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : nil ,
expectedErr : ErrNotFound ,
} ,
{
name : "FetchWorkload encounters a resource client error" ,
queryPayload : & QueryPayload {
Name : "foo-1234" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
2024-02-09 22:41:40 +00:00
input := getTestWorkloadResponse ( t , "foo-1234" , "" , "" )
2024-02-02 23:29:38 +00:00
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( nil , unknownErr ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , input . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : nil ,
expectedErr : unknownErr ,
} ,
{
name : "FetchWorkload with a matching port" ,
queryPayload : & QueryPayload {
Name : "foo-1234" ,
PortName : "api" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
2024-02-09 22:41:40 +00:00
result := getTestWorkloadResponse ( t , "foo-1234" , "" , "" )
2024-02-02 23:29:38 +00:00
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : & Result {
2024-02-09 22:41:40 +00:00
Node : & Location { Name : "foo-1234" , Address : "1.2.3.4" } ,
Type : ResultTypeWorkload ,
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
} ,
2024-02-02 23:29:38 +00:00
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
} ,
expectedErr : nil ,
} ,
{
name : "FetchWorkload with a matching port" ,
queryPayload : & QueryPayload {
Name : "foo-1234" ,
PortName : "not-api" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
2024-02-09 22:41:40 +00:00
result := getTestWorkloadResponse ( t , "foo-1234" , "" , "" )
2024-02-02 23:29:38 +00:00
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : nil ,
expectedErr : ErrNotFound ,
} ,
{
name : "FetchWorkload returns result for non-default tenancy" ,
queryPayload : & QueryPayload {
Name : "foo-1234" ,
Tenancy : QueryTenancy {
Namespace : "test-namespace" ,
Partition : "test-partition" ,
} ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
2024-02-09 22:41:40 +00:00
result := getTestWorkloadResponse ( t , "foo-1234" , "test-namespace" , "test-partition" )
2024-02-02 23:29:38 +00:00
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetTenancy ( ) . GetNamespace ( ) , req . Id . Tenancy . Namespace )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetTenancy ( ) . GetPartition ( ) , req . Id . Tenancy . Partition )
} )
} ,
expectedResult : & Result {
2024-02-03 03:23:52 +00:00
Node : & Location { Name : "foo-1234" , Address : "1.2.3.4" } ,
Type : ResultTypeWorkload ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-02 23:29:38 +00:00
Tenancy : ResultTenancy {
Namespace : "test-namespace" ,
Partition : "test-partition" ,
} ,
} ,
expectedErr : nil ,
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
logger := testutil . Logger ( t )
client := mockpbresource . NewResourceServiceClient ( t )
mockClient := client . EXPECT ( )
tc . configureMockClient ( mockClient )
df := NewV2DataFetcher ( rc , client , logger )
result , err := df . FetchWorkload ( tc . context , tc . queryPayload )
require . True ( t , errors . Is ( err , tc . expectedErr ) )
require . Equal ( t , tc . expectedResult , result )
} )
}
}
2024-02-06 16:12:04 +00:00
// Test_V2FetchEndpoints the FetchService method in scenarios where the RPC
// call succeeds and fails.
func Test_V2FetchEndpoints ( t * testing . T ) {
tests := [ ] struct {
name string
queryPayload * QueryPayload
context Context
configureMockClient func ( mockClient * mockpbresource . ResourceServiceClient_Expecter )
rc * config . RuntimeConfig
expectedResult [ ] * Result
expectedErr error
verifyShuffle bool
} {
{
name : "FetchEndpoints returns result" ,
queryPayload : & QueryPayload {
Name : "consul" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
2024-02-09 22:41:40 +00:00
endpoints := [ ] * pbcatalog . Endpoint {
2024-02-06 16:12:04 +00:00
makeEndpoint ( "consul-1" , "1.2.3.4" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
}
2024-02-09 22:41:40 +00:00
serviceEndpoints := getTestEndpointsResponse ( t , "" , "" , endpoints ... )
2024-02-06 16:12:04 +00:00
mockClient . Read ( mock . Anything , mock . Anything ) .
2024-02-09 22:41:40 +00:00
Return ( serviceEndpoints , nil ) .
2024-02-06 16:12:04 +00:00
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
2024-02-09 22:41:40 +00:00
require . Equal ( t , serviceEndpoints . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
2024-02-06 16:12:04 +00:00
} )
} ,
expectedResult : [ ] * Result {
{
Node : & Location { Name : "consul-1" , Address : "1.2.3.4" } ,
Type : ResultTypeWorkload ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-06 16:12:04 +00:00
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
2024-02-09 16:26:02 +00:00
DNS : DNSConfig {
Weight : 1 ,
} ,
2024-02-06 16:12:04 +00:00
} ,
} ,
} ,
{
name : "FetchEndpoints returns empty result with no endpoints" ,
queryPayload : & QueryPayload {
Name : "consul" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
result := getTestEndpointsResponse ( t , "" , "" )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : [ ] * Result { } ,
} ,
{
name : "FetchEndpoints returns a name error when the ServiceEndpoint does not exist" ,
queryPayload : & QueryPayload {
Name : "consul" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
result := getTestEndpointsResponse ( t , "" , "" )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( nil , status . Error ( codes . NotFound , "not found" ) ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedErr : ErrNotFound ,
} ,
{
name : "FetchEndpoints encounters a resource client error" ,
queryPayload : & QueryPayload {
Name : "consul" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
result := getTestEndpointsResponse ( t , "" , "" )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( nil , unknownErr ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedErr : unknownErr ,
} ,
{
name : "FetchEndpoints always filters out critical endpoints; DNS weights applied correctly" ,
queryPayload : & QueryPayload {
Name : "consul" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
results := [ ] * pbcatalog . Endpoint {
makeEndpoint ( "consul-1" , "1.2.3.4" , pbcatalog . Health_HEALTH_PASSING , 2 , 3 ) ,
makeEndpoint ( "consul-2" , "2.3.4.5" , pbcatalog . Health_HEALTH_WARNING , 2 , 3 ) ,
makeEndpoint ( "consul-3" , "3.4.5.6" , pbcatalog . Health_HEALTH_CRITICAL , 2 , 3 ) ,
}
result := getTestEndpointsResponse ( t , "" , "" , results ... )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : [ ] * Result {
{
Node : & Location { Name : "consul-1" , Address : "1.2.3.4" } ,
Type : ResultTypeWorkload ,
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
2024-02-09 16:26:02 +00:00
DNS : DNSConfig {
Weight : 2 ,
} ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-06 16:12:04 +00:00
} ,
{
Node : & Location { Name : "consul-2" , Address : "2.3.4.5" } ,
Type : ResultTypeWorkload ,
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
2024-02-09 16:26:02 +00:00
DNS : DNSConfig {
Weight : 3 ,
} ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-06 16:12:04 +00:00
} ,
} ,
} ,
{
name : "FetchEndpoints filters out warning endpoints when DNSOnlyPassing is true" ,
queryPayload : & QueryPayload {
Name : "consul" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
results := [ ] * pbcatalog . Endpoint {
makeEndpoint ( "consul-1" , "1.2.3.4" , pbcatalog . Health_HEALTH_PASSING , 2 , 3 ) ,
makeEndpoint ( "consul-2" , "2.3.4.5" , pbcatalog . Health_HEALTH_WARNING , 2 , 3 ) ,
makeEndpoint ( "consul-3" , "3.4.5.6" , pbcatalog . Health_HEALTH_CRITICAL , 2 , 3 ) ,
}
result := getTestEndpointsResponse ( t , "" , "" , results ... )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
rc : & config . RuntimeConfig {
DNSOnlyPassing : true ,
} ,
expectedResult : [ ] * Result {
{
Node : & Location { Name : "consul-1" , Address : "1.2.3.4" } ,
Type : ResultTypeWorkload ,
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
2024-02-09 16:26:02 +00:00
DNS : DNSConfig {
Weight : 2 ,
} ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-06 16:12:04 +00:00
} ,
} ,
} ,
{
name : "FetchEndpoints shuffles the results" ,
queryPayload : & QueryPayload {
Name : "consul" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
results := [ ] * pbcatalog . Endpoint {
// use a set of 10 elements, the odds of getting the same result are 1 in 3628800
makeEndpoint ( "consul-1" , "10.0.0.1" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-2" , "10.0.0.2" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-3" , "10.0.0.3" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-4" , "10.0.0.4" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-5" , "10.0.0.5" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-6" , "10.0.0.6" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-7" , "10.0.0.7" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-8" , "10.0.0.8" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-9" , "10.0.0.9" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-10" , "10.0.0.10" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
}
result := getTestEndpointsResponse ( t , "" , "" , results ... )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
2024-02-09 22:41:40 +00:00
expectedResult : func ( ) [ ] * Result {
results := make ( [ ] * Result , 0 , 10 )
for i := 0 ; i < 10 ; i ++ {
name := fmt . Sprintf ( "consul-%d" , i + 1 )
address := fmt . Sprintf ( "10.0.0.%d" , i + 1 )
result := & Result {
Node : & Location { Name : name , Address : address } ,
Type : ResultTypeWorkload ,
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
DNS : DNSConfig {
Weight : 1 ,
} ,
}
results = append ( results , result )
}
return results
} ( ) ,
2024-02-06 16:12:04 +00:00
verifyShuffle : true ,
} ,
{
name : "FetchEndpoints returns only the specified limit" ,
queryPayload : & QueryPayload {
Name : "consul" ,
Limit : 1 ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
results := [ ] * pbcatalog . Endpoint {
// intentionally all the same to make this easier to verify
makeEndpoint ( "consul-1" , "10.0.0.1" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-1" , "10.0.0.1" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
makeEndpoint ( "consul-1" , "10.0.0.1" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
}
result := getTestEndpointsResponse ( t , "" , "" , results ... )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : [ ] * Result {
{
Node : & Location { Name : "consul-1" , Address : "10.0.0.1" } ,
Type : ResultTypeWorkload ,
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
2024-02-09 16:26:02 +00:00
DNS : DNSConfig {
Weight : 1 ,
} ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-06 16:12:04 +00:00
} ,
} ,
} ,
{
name : "FetchEndpoints returns results with non-default tenancy" ,
queryPayload : & QueryPayload {
Name : "consul" ,
Tenancy : QueryTenancy {
Namespace : "test-namespace" ,
Partition : "test-partition" ,
} ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
results := [ ] * pbcatalog . Endpoint {
// intentionally all the same to make this easier to verify
makeEndpoint ( "consul-1" , "10.0.0.1" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
}
result := getTestEndpointsResponse ( t , "test-namespace" , "test-partition" , results ... )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( result , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetTenancy ( ) . GetNamespace ( ) , req . Id . Tenancy . Namespace )
require . Equal ( t , result . GetResource ( ) . GetId ( ) . GetTenancy ( ) . GetPartition ( ) , req . Id . Tenancy . Partition )
} )
} ,
expectedResult : [ ] * Result {
{
Node : & Location { Name : "consul-1" , Address : "10.0.0.1" } ,
Type : ResultTypeWorkload ,
Tenancy : ResultTenancy {
Namespace : "test-namespace" ,
Partition : "test-partition" ,
} ,
2024-02-09 16:26:02 +00:00
DNS : DNSConfig {
Weight : 1 ,
} ,
2024-02-09 22:41:40 +00:00
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
{
Name : "mesh" ,
Number : 21000 ,
} ,
} ,
2024-02-06 16:12:04 +00:00
} ,
} ,
} ,
2024-02-09 22:41:40 +00:00
{
name : "FetchEndpoints returns only a specific port if is one requested" ,
queryPayload : & QueryPayload {
Name : "consul" ,
PortName : "api" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
endpoints := [ ] * pbcatalog . Endpoint {
makeEndpoint ( "consul-1" , "10.0.0.1" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
}
serviceEndpoints := getTestEndpointsResponse ( t , "" , "" , endpoints ... )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( serviceEndpoints , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , serviceEndpoints . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedResult : [ ] * Result {
{
Node : & Location { Name : "consul-1" , Address : "10.0.0.1" } ,
Type : ResultTypeWorkload ,
Ports : [ ] Port {
{
Name : "api" ,
Number : 5678 ,
} ,
// No mesh port this time
} ,
Tenancy : ResultTenancy {
Namespace : resource . DefaultNamespaceName ,
Partition : resource . DefaultPartitionName ,
} ,
DNS : DNSConfig {
Weight : 1 ,
} ,
} ,
} ,
} ,
{
name : "FetchEndpoints returns a name error when a service doesn't implement the requested port" ,
queryPayload : & QueryPayload {
Name : "consul" ,
PortName : "banana" ,
} ,
context : Context {
Token : "test-token" ,
} ,
configureMockClient : func ( mockClient * mockpbresource . ResourceServiceClient_Expecter ) {
endpoints := [ ] * pbcatalog . Endpoint {
makeEndpoint ( "consul-1" , "10.0.0.1" , pbcatalog . Health_HEALTH_PASSING , 0 , 0 ) ,
}
serviceEndpoints := getTestEndpointsResponse ( t , "" , "" , endpoints ... )
mockClient . Read ( mock . Anything , mock . Anything ) .
Return ( serviceEndpoints , nil ) .
Once ( ) .
Run ( func ( args mock . Arguments ) {
req := args . Get ( 1 ) . ( * pbresource . ReadRequest )
require . Equal ( t , serviceEndpoints . GetResource ( ) . GetId ( ) . GetName ( ) , req . Id . Name )
} )
} ,
expectedErr : ErrNotFound ,
} ,
2024-02-06 16:12:04 +00:00
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
logger := testutil . Logger ( t )
client := mockpbresource . NewResourceServiceClient ( t )
mockClient := client . EXPECT ( )
tc . configureMockClient ( mockClient )
if tc . rc == nil {
tc . rc = & config . RuntimeConfig {
DNSOnlyPassing : false ,
}
}
df := NewV2DataFetcher ( tc . rc , client , logger )
result , err := df . FetchEndpoints ( tc . context , tc . queryPayload , LookupTypeService )
require . True ( t , errors . Is ( err , tc . expectedErr ) )
if tc . verifyShuffle {
require . NotEqualf ( t , tc . expectedResult , result , "expected result to be shuffled. There is a small probability that it shuffled back to the original order. In that case, you may want to play the lottery." )
}
require . ElementsMatchf ( t , tc . expectedResult , result , "elements of results should match" )
} )
}
}
2024-02-09 22:41:40 +00:00
func getTestWorkloadResponse ( t * testing . T , name string , nsOverride string , partitionOverride string ) * pbresource . ReadResponse {
2024-02-02 23:29:38 +00:00
workload := & pbcatalog . Workload {
Addresses : [ ] * pbcatalog . WorkloadAddress {
{
Host : "1.2.3.4" ,
2024-02-09 22:41:40 +00:00
Ports : [ ] string { "api" , "mesh" } ,
2024-02-02 23:29:38 +00:00
} ,
} ,
Ports : map [ string ] * pbcatalog . WorkloadPort {
"api" : {
Port : 5678 ,
} ,
2024-02-09 22:41:40 +00:00
"mesh" : {
Port : 21000 ,
} ,
2024-02-02 23:29:38 +00:00
} ,
Identity : "test-identity" ,
}
data , err := anypb . New ( workload )
require . NoError ( t , err )
resp := & pbresource . ReadResponse {
Resource : & pbresource . Resource {
Id : & pbresource . ID {
2024-02-09 22:41:40 +00:00
Name : name ,
2024-02-02 23:29:38 +00:00
Type : pbcatalog . WorkloadType ,
2024-02-06 16:12:04 +00:00
Tenancy : resource . DefaultNamespacedTenancy ( ) ,
} ,
Data : data ,
} ,
}
if nsOverride != "" {
resp . Resource . Id . Tenancy . Namespace = nsOverride
}
if partitionOverride != "" {
resp . Resource . Id . Tenancy . Partition = partitionOverride
}
return resp
}
func makeEndpoint ( name string , address string , health pbcatalog . Health , weightPassing , weightWarning uint32 ) * pbcatalog . Endpoint {
endpoint := & pbcatalog . Endpoint {
Addresses : [ ] * pbcatalog . WorkloadAddress {
{
2024-02-09 22:41:40 +00:00
Host : address ,
Ports : [ ] string { "api" } ,
} ,
} ,
Ports : map [ string ] * pbcatalog . WorkloadPort {
"api" : {
Port : 5678 ,
} ,
"mesh" : {
Port : 21000 ,
2024-02-06 16:12:04 +00:00
} ,
} ,
HealthStatus : health ,
TargetRef : & pbresource . ID {
Name : name ,
} ,
}
if weightPassing > 0 || weightWarning > 0 {
endpoint . Dns = & pbcatalog . DNSPolicy {
Weights : & pbcatalog . Weights {
Passing : weightPassing ,
Warning : weightWarning ,
} ,
}
}
return endpoint
}
func getTestEndpointsResponse ( t * testing . T , nsOverride string , partitionOverride string , endpoints ... * pbcatalog . Endpoint ) * pbresource . ReadResponse {
serviceEndpoints := & pbcatalog . ServiceEndpoints {
Endpoints : endpoints ,
}
data , err := anypb . New ( serviceEndpoints )
require . NoError ( t , err )
resp := & pbresource . ReadResponse {
Resource : & pbresource . Resource {
Id : & pbresource . ID {
Name : "consul" ,
Type : pbcatalog . ServiceType ,
Tenancy : resource . DefaultNamespacedTenancy ( ) ,
2024-02-02 23:29:38 +00:00
} ,
Data : data ,
} ,
}
if nsOverride != "" {
resp . Resource . Id . Tenancy . Namespace = nsOverride
}
if partitionOverride != "" {
resp . Resource . Id . Tenancy . Partition = partitionOverride
}
return resp
}