473 lines
10 KiB
Go
473 lines
10 KiB
Go
/*
|
|
Copyright 2021 The Dapr Authors
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package mdns
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
nr "github.com/dapr/components-contrib/nameresolution"
|
|
"github.com/dapr/kit/logger"
|
|
)
|
|
|
|
func TestInit(t *testing.T) {
|
|
tests := []struct {
|
|
missingProp string
|
|
props map[string]string
|
|
}{
|
|
{
|
|
"name",
|
|
map[string]string{
|
|
nr.MDNSInstanceAddress: "127.0.0.1",
|
|
nr.MDNSInstancePort: "30003",
|
|
},
|
|
},
|
|
{
|
|
"address",
|
|
map[string]string{
|
|
nr.MDNSInstanceName: "testAppID",
|
|
nr.MDNSInstancePort: "30003",
|
|
},
|
|
},
|
|
{
|
|
"port",
|
|
map[string]string{
|
|
nr.MDNSInstanceName: "testAppID",
|
|
nr.MDNSInstanceAddress: "127.0.0.1",
|
|
},
|
|
},
|
|
{
|
|
"port",
|
|
map[string]string{
|
|
nr.MDNSInstanceName: "testAppID",
|
|
nr.MDNSInstanceAddress: "127.0.0.1",
|
|
nr.MDNSInstancePort: "abcd",
|
|
},
|
|
},
|
|
}
|
|
|
|
// arrange
|
|
resolver := NewResolver(logger.NewLogger("test"))
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.missingProp+" is missing", func(t *testing.T) {
|
|
// act
|
|
err := resolver.Init(nr.Metadata{Properties: tt.props})
|
|
|
|
// assert
|
|
assert.Error(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResolver(t *testing.T) {
|
|
// arrange
|
|
resolver := NewResolver(logger.NewLogger("test"))
|
|
md := nr.Metadata{Properties: map[string]string{
|
|
nr.MDNSInstanceName: "testAppID",
|
|
nr.MDNSInstanceAddress: "127.0.0.1",
|
|
nr.MDNSInstancePort: "1234",
|
|
}}
|
|
|
|
// act
|
|
err := resolver.Init(md)
|
|
require.NoError(t, err)
|
|
|
|
request := nr.ResolveRequest{ID: "testAppID"}
|
|
pt, err := resolver.ResolveID(request)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "127.0.0.1:1234", pt)
|
|
}
|
|
|
|
func TestResolverMultipleInstances(t *testing.T) {
|
|
// arrange...
|
|
resolver := NewResolver(logger.NewLogger("test"))
|
|
|
|
// register instance A
|
|
instanceAID := "A"
|
|
instanceAName := "testAppID"
|
|
instanceAAddress := "127.0.0.1"
|
|
instanceAPort := "1234"
|
|
instanceAPQDN := fmt.Sprintf("%s:%s", instanceAAddress, instanceAPort)
|
|
|
|
instanceA := nr.Metadata{Properties: map[string]string{
|
|
nr.MDNSInstanceName: instanceAName,
|
|
nr.MDNSInstanceAddress: instanceAAddress,
|
|
nr.MDNSInstancePort: instanceAPort,
|
|
nr.MDNSInstanceID: instanceAID,
|
|
}}
|
|
err1 := resolver.Init(instanceA)
|
|
require.NoError(t, err1)
|
|
|
|
// register instance B
|
|
instanceBID := "B"
|
|
instanceBName := "testAppID"
|
|
instanceBAddress := "127.0.0.1"
|
|
instanceBPort := "5678"
|
|
instanceBPQDN := fmt.Sprintf("%s:%s", instanceBAddress, instanceBPort)
|
|
|
|
instanceB := nr.Metadata{Properties: map[string]string{
|
|
nr.MDNSInstanceName: instanceBName,
|
|
nr.MDNSInstanceAddress: instanceBAddress,
|
|
nr.MDNSInstancePort: instanceBPort,
|
|
nr.MDNSInstanceID: instanceBID,
|
|
}}
|
|
err2 := resolver.Init(instanceB)
|
|
require.NoError(t, err2)
|
|
|
|
// act...
|
|
request := nr.ResolveRequest{ID: "testAppID"}
|
|
|
|
// first resolution will return the first responder's address and trigger a cache refresh.
|
|
addr1, err := resolver.ResolveID(request)
|
|
require.NoError(t, err)
|
|
require.Contains(t, []string{instanceAPQDN, instanceBPQDN}, addr1)
|
|
|
|
// delay long enough for the background address cache to populate.
|
|
time.Sleep(1 * time.Second)
|
|
|
|
// assert that when we resolve the test app id n times, we see only
|
|
// instance A and instance B and we see them each atleast m times.
|
|
instanceACount := 0
|
|
instanceBCount := 0
|
|
for i := 0; i < 100; i++ {
|
|
addr, err := resolver.ResolveID(request)
|
|
require.NoError(t, err)
|
|
require.Contains(t, []string{instanceAPQDN, instanceBPQDN}, addr)
|
|
if addr == instanceAPQDN {
|
|
instanceACount++
|
|
} else if addr == instanceBPQDN {
|
|
instanceBCount++
|
|
}
|
|
}
|
|
// 45 allows some variation in distribution.
|
|
require.Greater(t, instanceACount, 45)
|
|
require.Greater(t, instanceBCount, 45)
|
|
}
|
|
|
|
func TestAddressListExpire(t *testing.T) {
|
|
// arrange
|
|
base := time.Now()
|
|
expired := base.Add(-60 * time.Second)
|
|
notExpired := base.Add(60 * time.Second)
|
|
addressList := &addressList{
|
|
addresses: []address{
|
|
{
|
|
ip: "expired0",
|
|
expiresAt: expired,
|
|
},
|
|
{
|
|
ip: "expired1",
|
|
expiresAt: expired,
|
|
},
|
|
{
|
|
ip: "notExpired0",
|
|
expiresAt: notExpired,
|
|
},
|
|
},
|
|
}
|
|
|
|
// act
|
|
addressList.expire()
|
|
|
|
// assert
|
|
require.Len(t, addressList.addresses, 1)
|
|
}
|
|
|
|
func TestAddressListAddNewAddress(t *testing.T) {
|
|
// arrange
|
|
expiry := time.Now().Add(60 * time.Second)
|
|
addressList := &addressList{
|
|
addresses: []address{
|
|
{
|
|
ip: "addr0",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr1",
|
|
expiresAt: expiry,
|
|
},
|
|
},
|
|
}
|
|
|
|
// act
|
|
addressList.add("addr2")
|
|
|
|
// assert
|
|
require.Len(t, addressList.addresses, 3)
|
|
require.Equal(t, "addr2", addressList.addresses[2].ip)
|
|
}
|
|
|
|
func TestAddressListAddExisitingAddress(t *testing.T) {
|
|
// arrange
|
|
expiry := time.Now().Add(10 * time.Second)
|
|
addressList := &addressList{
|
|
addresses: []address{
|
|
{
|
|
ip: "addr0",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr1",
|
|
expiresAt: expiry,
|
|
},
|
|
},
|
|
}
|
|
|
|
// act
|
|
addressList.add("addr1")
|
|
deltaSec := int(addressList.addresses[1].expiresAt.Sub(expiry).Seconds())
|
|
|
|
// assert
|
|
require.Len(t, addressList.addresses, 2)
|
|
require.Greater(t, deltaSec, 0) // Ensures expiry has been extended for existing address.
|
|
}
|
|
|
|
func TestAddressListNext(t *testing.T) {
|
|
// arrange
|
|
expiry := time.Now().Add(10 * time.Second)
|
|
addressList := &addressList{
|
|
addresses: []address{
|
|
{
|
|
ip: "addr0",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr1",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr2",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr3",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr4",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr5",
|
|
expiresAt: expiry,
|
|
},
|
|
},
|
|
}
|
|
|
|
// act & assert
|
|
require.Equal(t, "addr0", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
require.Equal(t, "addr2", *addressList.next())
|
|
require.Equal(t, "addr3", *addressList.next())
|
|
require.Equal(t, "addr4", *addressList.next())
|
|
require.Equal(t, "addr5", *addressList.next())
|
|
require.Equal(t, "addr0", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
}
|
|
|
|
func TestAddressListNextMaxCounter(t *testing.T) {
|
|
// arrange
|
|
expiry := time.Now().Add(10 * time.Second)
|
|
addressList := &addressList{
|
|
addresses: []address{
|
|
{
|
|
ip: "addr0",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr1",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr2",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr3",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr4",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr5",
|
|
expiresAt: expiry,
|
|
},
|
|
},
|
|
}
|
|
|
|
// act & assert
|
|
require.Equal(t, "addr0", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
require.Equal(t, "addr2", *addressList.next())
|
|
require.Equal(t, "addr3", *addressList.next())
|
|
addressList.counter = maxInt
|
|
require.Equal(t, "addr0", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
require.Equal(t, "addr2", *addressList.next())
|
|
}
|
|
|
|
func TestAddressListNextNoAddress(t *testing.T) {
|
|
// arrange
|
|
addressList := &addressList{
|
|
addresses: []address{},
|
|
}
|
|
|
|
// act & assert
|
|
require.Nil(t, addressList.next())
|
|
}
|
|
|
|
func TestAddressListNextWithAdd(t *testing.T) {
|
|
// arrange
|
|
expiry := time.Now().Add(10 * time.Second)
|
|
addressList := &addressList{
|
|
addresses: []address{
|
|
{
|
|
ip: "addr0",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr1",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr2",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr3",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr4",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr5",
|
|
expiresAt: expiry,
|
|
},
|
|
},
|
|
}
|
|
|
|
// act & assert
|
|
require.Equal(t, "addr0", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
require.Equal(t, "addr2", *addressList.next())
|
|
require.Equal(t, "addr3", *addressList.next())
|
|
addressList.add("addr6")
|
|
require.Equal(t, "addr4", *addressList.next())
|
|
require.Equal(t, "addr5", *addressList.next())
|
|
require.Equal(t, "addr6", *addressList.next())
|
|
require.Equal(t, "addr0", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
}
|
|
|
|
func TestAddressListNextWithExpiration(t *testing.T) {
|
|
// arrange
|
|
expiry := time.Now().Add(10 * time.Second)
|
|
expired := time.Now().Add(-60 * time.Second)
|
|
addressList := &addressList{
|
|
addresses: []address{
|
|
{
|
|
ip: "addr0",
|
|
expiresAt: expired,
|
|
},
|
|
{
|
|
ip: "addr1",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr2",
|
|
expiresAt: expired,
|
|
},
|
|
{
|
|
ip: "addr3",
|
|
expiresAt: expiry,
|
|
},
|
|
{
|
|
ip: "addr4",
|
|
expiresAt: expired,
|
|
},
|
|
{
|
|
ip: "addr5",
|
|
expiresAt: expiry,
|
|
},
|
|
},
|
|
}
|
|
|
|
// act & assert
|
|
require.Equal(t, "addr0", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
require.Equal(t, "addr2", *addressList.next())
|
|
require.Equal(t, "addr3", *addressList.next())
|
|
addressList.expire()
|
|
require.Equal(t, "addr3", *addressList.next())
|
|
require.Equal(t, "addr5", *addressList.next())
|
|
require.Equal(t, "addr1", *addressList.next())
|
|
require.Equal(t, "addr3", *addressList.next())
|
|
}
|
|
|
|
func TestUnion(t *testing.T) {
|
|
// arrange
|
|
testCases := []struct {
|
|
first []string
|
|
second []string
|
|
expected []string
|
|
}{
|
|
{
|
|
first: []string{"a", "b", "c"},
|
|
second: []string{"a", "c", "d", "e"},
|
|
expected: []string{"a", "b", "c", "d", "e"},
|
|
},
|
|
{
|
|
first: []string{"a", "b", "c"},
|
|
second: []string{"d", "e", "f", "g"},
|
|
expected: []string{"a", "b", "c", "d", "e", "f", "g"},
|
|
},
|
|
{
|
|
first: []string{"a", "b"},
|
|
second: []string{"a", "b"},
|
|
expected: []string{"a", "b"},
|
|
},
|
|
{
|
|
first: []string{"a", "b"},
|
|
second: []string{"b", "a"},
|
|
expected: []string{"a", "b"},
|
|
},
|
|
}
|
|
for _, tt := range testCases {
|
|
// act
|
|
union := union(tt.first, tt.second)
|
|
|
|
// assert
|
|
var matches int
|
|
for _, i1 := range tt.expected {
|
|
for _, i2 := range union {
|
|
if i1 == i2 {
|
|
matches++
|
|
}
|
|
}
|
|
}
|
|
require.Equal(t, len(tt.expected), matches)
|
|
}
|
|
}
|