dragonfly/client/daemon/networktopology/network_topology_test.go

546 lines
18 KiB
Go

/*
* Copyright 2023 The Dragonfly 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 networktopology
import (
"context"
"errors"
"io"
"net"
"reflect"
"testing"
"time"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
v1 "d7y.io/api/v2/pkg/apis/common/v1"
schedulerv1 "d7y.io/api/v2/pkg/apis/scheduler/v1"
schedulerv1mocks "d7y.io/api/v2/pkg/apis/scheduler/v1/mocks"
"d7y.io/dragonfly/v2/client/config"
"d7y.io/dragonfly/v2/pkg/idgen"
"d7y.io/dragonfly/v2/pkg/rpc/scheduler/client/mocks"
schedulerclientmocks "d7y.io/dragonfly/v2/pkg/rpc/scheduler/client/mocks"
)
var (
mockDaemonConfig = &config.DaemonOption{
Host: config.HostOption{
Location: mockHostLocation,
IDC: mockHostIDC,
Hostname: idgen.HostIDV2("127.0.0.1", "bar"),
AdvertiseIP: net.IPv4(127, 0, 0, 1),
},
NetworkTopology: config.NetworkTopologyOption{
Enable: true,
Probe: config.ProbeOption{
Interval: 200 * time.Millisecond,
},
},
}
mockPort = 8000
mockDownloadPort = 8001
mockHostLocation = "bar"
mockHostIDC = "baz"
mockHost = &v1.Host{
Id: "foo",
Ip: "127.0.0.1",
Hostname: idgen.HostIDV2("127.0.0.1", "foo"),
Port: int32(mockPort),
DownloadPort: int32(mockDownloadPort),
Location: mockHostLocation,
Idc: mockHostIDC,
}
mockSeedHost = &v1.Host{
Id: "bar",
Ip: "127.0.0.1",
Hostname: idgen.HostIDV2("127.0.0.1", "bar"),
Port: int32(mockPort),
DownloadPort: int32(mockDownloadPort),
Location: mockHostLocation,
Idc: mockHostIDC,
}
)
func Test_NewNetworkTopology(t *testing.T) {
tests := []struct {
name string
expect func(t *testing.T, n NetworkTopology, err error)
}{
{
name: "new network topology",
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.Equal(reflect.TypeOf(n).Elem().Name(), "networkTopology")
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
ctl := gomock.NewController(t)
defer ctl.Finish()
schedulerClient := schedulerclientmocks.NewMockV1(ctl)
n, err := NewNetworkTopology(mockDaemonConfig, mockSeedHost.Id, int32(mockPort), int32(mockDownloadPort), schedulerClient)
tc.expect(t, n, err)
})
}
}
func TestNetworkTopology_Serve(t *testing.T) {
tests := []struct {
name string
sleep func()
mock func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder)
expect func(t *testing.T, n NetworkTopology, err error)
}{
{
name: "synchronize probes",
sleep: func() {
time.Sleep(300 * time.Millisecond)
},
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(&schedulerv1.SyncProbesResponse{
Hosts: []*v1.Host{mockHost},
}, nil).Times(1),
ms.Send(gomock.Any()).Return(nil).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
go n.Serve()
},
},
{
name: "synchronize probes error",
sleep: func() {
time.Sleep(300 * time.Millisecond)
},
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(nil, errors.New("synchronize probes error")).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
go n.Serve()
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
ctl := gomock.NewController(t)
defer ctl.Finish()
schedulerClient := schedulerclientmocks.NewMockV1(ctl)
stream := schedulerv1mocks.NewMockScheduler_SyncProbesClient(ctl)
tc.mock(schedulerClient.EXPECT(), stream, stream.EXPECT())
n, err := NewNetworkTopology(mockDaemonConfig, mockSeedHost.Id, int32(mockPort), int32(mockDownloadPort), schedulerClient)
tc.expect(t, n, err)
tc.sleep()
n.Stop()
})
}
}
func TestNetworkTopology_syncProbes(t *testing.T) {
tests := []struct {
name string
mock func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder)
expect func(t *testing.T, n NetworkTopology, err error)
}{
{
name: "synchronize probes and send ProbeFinishedRequest",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(&schedulerv1.SyncProbesResponse{
Hosts: []*v1.Host{mockHost},
}, nil).Times(1),
ms.Send(gomock.Any()).Return(nil).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.NoError(n.(*networkTopology).syncProbes())
},
},
{
name: "synchronize fail probes and send ProbeFailedRequest",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(&schedulerv1.SyncProbesResponse{
Hosts: []*v1.Host{
{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
},
}, nil).Times(1),
ms.Send(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeFailedRequest{
ProbeFailedRequest: &schedulerv1.ProbeFailedRequest{
Probes: []*schedulerv1.FailedProbe{
{
Host: &v1.Host{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
Description: "receive packet failed",
},
},
},
},
}).Return(nil).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.NoError(n.(*networkTopology).syncProbes())
},
},
{
name: "synchronize probes and fail probes, send ProbeFinishedRequest and ProbeFailedRequest",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(&schedulerv1.SyncProbesResponse{
Hosts: []*v1.Host{
mockHost,
{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
},
}, nil).Times(1),
ms.Send(gomock.Any()).Return(nil).Times(1),
ms.Send(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeFailedRequest{
ProbeFailedRequest: &schedulerv1.ProbeFailedRequest{
Probes: []*schedulerv1.FailedProbe{
{
Host: &v1.Host{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
Description: "receive packet failed",
},
},
},
},
}).Return(nil).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.NoError(n.(*networkTopology).syncProbes())
},
},
{
name: "syncProbe error",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(nil, errors.New("syncProbe error")).Times(1)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.EqualError(n.(*networkTopology).syncProbes(), "syncProbe error")
},
},
{
name: "receive error",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(nil, errors.New("receive error")).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.EqualError(n.(*networkTopology).syncProbes(), "receive error")
},
},
{
name: "receive EOF",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(nil, io.EOF).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.NoError(n.(*networkTopology).syncProbes())
},
},
{
name: "send ProbeFinishedRequest error",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(&schedulerv1.SyncProbesResponse{
Hosts: []*v1.Host{mockHost},
}, nil).Times(1),
ms.Send(gomock.Any()).Return(errors.New("send ProbeFinishedRequest error")).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.EqualError(n.(*networkTopology).syncProbes(), "send ProbeFinishedRequest error")
},
},
{
name: "send ProbeFailedRequest error",
mock: func(mv *mocks.MockV1MockRecorder, stream *schedulerv1mocks.MockScheduler_SyncProbesClient,
ms *schedulerv1mocks.MockScheduler_SyncProbesClientMockRecorder) {
gomock.InOrder(
mv.SyncProbes(gomock.Eq(context.Background()), gomock.Eq(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeStartedRequest{
ProbeStartedRequest: &schedulerv1.ProbeStartedRequest{},
}})).Return(stream, nil).Times(1),
ms.Recv().Return(&schedulerv1.SyncProbesResponse{
Hosts: []*v1.Host{
{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
},
}, nil).Times(1),
ms.Send(&schedulerv1.SyncProbesRequest{
Host: mockSeedHost,
Request: &schedulerv1.SyncProbesRequest_ProbeFailedRequest{
ProbeFailedRequest: &schedulerv1.ProbeFailedRequest{
Probes: []*schedulerv1.FailedProbe{
{
Host: &v1.Host{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
Description: "receive packet failed",
},
},
},
},
}).Return(errors.New("send ProbeFailedRequest error")).Times(1),
)
},
expect: func(t *testing.T, n NetworkTopology, err error) {
assert := assert.New(t)
assert.NoError(err)
assert.EqualError(n.(*networkTopology).syncProbes(), "send ProbeFailedRequest error")
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
ctl := gomock.NewController(t)
defer ctl.Finish()
schedulerClient := schedulerclientmocks.NewMockV1(ctl)
stream := schedulerv1mocks.NewMockScheduler_SyncProbesClient(ctl)
tc.mock(schedulerClient.EXPECT(), stream, stream.EXPECT())
n, err := NewNetworkTopology(mockDaemonConfig, mockSeedHost.Id, int32(mockPort), int32(mockDownloadPort), schedulerClient)
tc.expect(t, n, err)
n.Stop()
})
}
}
func TestNetworkTopology_pingHosts(t *testing.T) {
tests := []struct {
name string
destHosts []*v1.Host
expect func(t *testing.T, n NetworkTopology, err error, destHosts []*v1.Host)
}{
{
name: "ping hosts and collect probes",
destHosts: []*v1.Host{mockHost},
expect: func(t *testing.T, n NetworkTopology, err error, destHosts []*v1.Host) {
assert := assert.New(t)
assert.NoError(err)
probes, failProbes := n.(*networkTopology).pingHosts(destHosts)
assert.Equal(len(probes), 1)
assert.Equal(len(failProbes), 0)
},
},
{
name: "ping hosts and collect fail probes",
destHosts: []*v1.Host{
{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
},
expect: func(t *testing.T, n NetworkTopology, err error, destHosts []*v1.Host) {
assert := assert.New(t)
assert.NoError(err)
probes, failProbes := n.(*networkTopology).pingHosts(destHosts)
assert.Equal(len(probes), 0)
assert.Equal(len(failProbes), 1)
},
},
{
name: "ping hosts, collect probes and fail probes",
destHosts: []*v1.Host{
mockHost,
{
Id: idgen.HostIDV2("172.0.0.1", "foo"),
Ip: "172.0.0.1",
Hostname: "foo",
Port: 8003,
DownloadPort: 8001,
Location: "location",
Idc: "idc",
},
},
expect: func(t *testing.T, n NetworkTopology, err error, destHosts []*v1.Host) {
assert := assert.New(t)
assert.NoError(err)
probes, failProbes := n.(*networkTopology).pingHosts(destHosts)
assert.Equal(len(probes), 1)
assert.Equal(len(failProbes), 1)
},
},
{
name: "dest hosts is empty",
destHosts: []*v1.Host{},
expect: func(t *testing.T, n NetworkTopology, err error, destHosts []*v1.Host) {
assert := assert.New(t)
assert.NoError(err)
probes, failProbes := n.(*networkTopology).pingHosts(destHosts)
assert.Equal(len(probes), 0)
assert.Equal(len(failProbes), 0)
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
ctl := gomock.NewController(t)
defer ctl.Finish()
schedulerClient := schedulerclientmocks.NewMockV1(ctl)
n, err := NewNetworkTopology(mockDaemonConfig, mockSeedHost.Id, int32(mockPort), int32(mockDownloadPort), schedulerClient)
tc.expect(t, n, err, tc.destHosts)
})
}
}