Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .azure-pipelines/build-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,12 @@ jobs:
clean: true
submodules: true
- script: |
set -xe
sudo apt-get update
sudo apt-get install -y \
libhiredis-dev \
libzmq3-dev \
swig4.0 \
swig \
libdbus-1-dev \
libteam-dev
sudo pip3 install lcov_cobertura
Expand Down
2 changes: 1 addition & 1 deletion teamsyncd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ teamsyncd_SOURCES = teamsyncd.cpp teamsync.cpp

teamsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN)
teamsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_ASAN)
teamsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lhiredis -lswsscommon -lteam
teamsyncd_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lhiredis -lswsscommon -lteam -lteamdctl

if GCOV_ENABLED
teamsyncd_SOURCES += ../gcovpreload/gcovpreload.cpp
Expand Down
44 changes: 39 additions & 5 deletions teamsyncd/teamsync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "warm_restart.h"
#include "teamsync.h"

#include <team.h>
#include <teamdctl.h>
#include <unistd.h>

using namespace std;
Expand Down Expand Up @@ -279,19 +281,51 @@ TeamSync::TeamPortSync::TeamPortSync(const string &lagName, int ifindex,
"Unable to register port change event");
}

struct teamdctl *m_teamdctl = teamdctl_alloc();
if (!m_teamdctl)
{
team_free(m_team);
m_team = NULL;
throw system_error(make_error_code(errc::address_not_available),
"Unable to allocate teamdctl socket");
}

err = teamdctl_connect(m_teamdctl, lagName.c_str(), nullptr, "usock");
if (err)
{
team_free(m_team);
m_team = NULL;
teamdctl_free(m_teamdctl);
throw system_error(make_error_code(errc::connection_refused),
"Unable to connect to teamd");
}

char *response;
err = teamdctl_config_get_raw_direct(m_teamdctl, &response);
if (err)
{
team_free(m_team);
m_team = NULL;
teamdctl_disconnect(m_teamdctl);
teamdctl_free(m_teamdctl);
throw system_error(make_error_code(errc::io_error),
"Unable to get config from teamd (to prove that it is running and alive)");
}

teamdctl_disconnect(m_teamdctl);
teamdctl_free(m_teamdctl);

break;
}
catch (const system_error& e)
{
SWSS_LOG_WARN("Failed to initialize team handler. LAG=%s error=%d:%s, attempt=%d",
lagName.c_str(), e.code().value(), e.what(), count);

if (++count == max_retries)
{
throw;
}
else
{
SWSS_LOG_WARN("Failed to initialize team handler. LAG=%s error=%d:%s, attempt=%d",
lagName.c_str(), e.code().value(), e.what(), count);
}

sleep(1);
}
Expand Down
13 changes: 11 additions & 2 deletions tests/mock_tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ CXXFLAGS = -g -O0

CFLAGS_SAI = -I /usr/include/sai

TESTS = tests tests_intfmgrd tests_teammgrd tests_portsyncd tests_fpmsyncd tests_response_publisher
TESTS = tests tests_intfmgrd tests_teammgrd tests_portsyncd tests_fpmsyncd tests_response_publisher tests_teamsyncd

noinst_PROGRAMS = tests tests_intfmgrd tests_teammgrd tests_portsyncd tests_fpmsyncd tests_response_publisher
noinst_PROGRAMS = tests tests_intfmgrd tests_teammgrd tests_portsyncd tests_fpmsyncd tests_response_publisher tests_teamsyncd

LDADD_SAI = -lsaimeta -lsaimetadata -lsaivs -lsairedis

Expand Down Expand Up @@ -312,3 +312,12 @@ tests_response_publisher_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CF
tests_response_publisher_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(CFLAGS_SAI) $(tests_response_publisher_INCLUDES)
tests_response_publisher_LDADD = $(LDADD_GTEST) $(LDADD_SAI) -lnl-genl-3 -lhiredis -lhiredis \
-lswsscommon -lswsscommon -lgtest -lgtest_main -lzmq -lnl-3 -lnl-route-3 -lpthread

tests_teamsyncd_SOURCES = teamsync_ut.cpp \
$(top_srcdir)/teamsyncd/teamsync.cpp

tests_teamsyncd_INCLUDES = $(tests_INCLUDES) -I$(top_srcdir)/teamsyncd
tests_teamsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(CFLAGS_SAI)
tests_teamsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) $(CFLAGS_SAI) $(tests_teamsyncd_INCLUDES)
tests_teamsyncd_LDADD = $(LDADD_GTEST) $(LDADD_SAI) -lnl-genl-3 \
-lswsscommon -lgtest -lgtest_main -lpthread -lteam -lteamdctl
185 changes: 185 additions & 0 deletions tests/mock_tests/teamsync_ut.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <dlfcn.h>
#include <stdexcept>
#include <team.h>
#include <teamdctl.h>
#include "teamsync.h"

static unsigned int (*callback_sleep)(unsigned int seconds) = NULL;
static int (*callback_team_init)(struct team_handle *th, uint32_t ifindex) = NULL;
static int (*callback_team_change_handler)(struct team_handle *th, struct team_change_handler *handler, void *priv) = NULL;
static int (*callback_teamdctl_connect)(struct teamdctl *tdc, const char *team_name, const char *addr, const char *cli_type) = NULL;
static int (*callback_teamdctl_config_get_raw_direct)(struct teamdctl *tdc, char **response) = NULL;
static void (*callback_teamdctl_disconnect)(struct teamdctl *tdc) = NULL;

static unsigned int cb_sleep(unsigned int seconds)
{
return 0;
}

unsigned int sleep(unsigned int seconds)
{
if (callback_sleep)
{
return callback_sleep(seconds);
}
unsigned int (*realfunc)(unsigned int) =
(unsigned int (*)(unsigned int))(dlsym (RTLD_NEXT, "sleep"));
return realfunc(seconds);
}


static int cb_team_init(struct team_handle *th, uint32_t ifindex)
{
return 0;
}

int team_init(struct team_handle *th, uint32_t ifindex)
{
if (callback_team_init)
{
return callback_team_init(th, ifindex);
}
int (*realfunc)(struct team_handle *, uint32_t) =
(int (*)(struct team_handle *, uint32_t))(dlsym (RTLD_NEXT, "team_init"));
return realfunc(th, ifindex);
}

static int cb_team_change_handler(struct team_handle *th, struct team_change_handler *handler, void *priv)
{
return 0;
}

int team_change_handler(struct team_handle *th, struct team_change_handler *handler, void *priv)
{
if (callback_team_change_handler)
{
return callback_team_change_handler(th, handler, priv);
}
int (*realfunc)(struct team_handle *, struct team_change_handler*, void*) =
(int (*)(struct team_handle *, struct team_change_handler*, void*))(dlsym (RTLD_NEXT, "team_change_handler"));
return realfunc(th, handler, priv);
}

static int cb_teamdctl_connect(struct teamdctl *tdc, const char *team_name, const char *addr, const char *cli_type)
{
return 0;
}

int teamdctl_connect(struct teamdctl *tdc, const char *team_name, const char *addr, const char *cli_type)
{
if (callback_teamdctl_connect)
{
return callback_teamdctl_connect(tdc, team_name, addr, cli_type);
}
int (*realfunc)(struct teamdctl *, const char *, const char *, const char *) =
(int (*)(struct teamdctl *, const char *, const char *, const char *))(dlsym (RTLD_NEXT, "teamdctl_connect"));
return realfunc(tdc, team_name, addr, cli_type);
}

static int cb_teamdctl_config_get_raw_direct_force_error(struct teamdctl *tdc, char **response)
{
// Forced error
return 1;
}

static int cb_teamdctl_config_get_raw_direct_success(struct teamdctl *tdc, char **response)
{
return 0;
}

int teamdctl_config_get_raw_direct(struct teamdctl *tdc, char **response)
{
if (callback_teamdctl_config_get_raw_direct)
{
return callback_teamdctl_config_get_raw_direct(tdc, response);
}
int (*realfunc)(struct teamdctl *, char **) =
(int (*)(struct teamdctl *, char **))(dlsym (RTLD_NEXT, "teamdctl_config_get_raw_direct"));
return realfunc(tdc, response);
}

static void cb_teamdctl_disconnect(struct teamdctl *tdc)
{
}

void teamdctl_disconnect(struct teamdctl *tdc)
{
if (callback_teamdctl_disconnect)
{
callback_teamdctl_disconnect(tdc);
return;
}
int (*realfunc)(struct teamdctl *) =
(int (*)(struct teamdctl *))(dlsym (RTLD_NEXT, "teamdctl_disconnect"));
realfunc(tdc);
}

namespace teamportsync_test
{
struct TeamPortSyncTest : public ::testing::Test
{
virtual void SetUp() override
{
callback_sleep = cb_sleep;
callback_team_init = NULL;
callback_team_change_handler = NULL;
callback_teamdctl_connect = NULL;
callback_teamdctl_config_get_raw_direct = cb_teamdctl_config_get_raw_direct_force_error;
callback_teamdctl_disconnect = cb_teamdctl_disconnect;
}

virtual void TearDown() override
{
callback_sleep = NULL;
callback_team_init = NULL;
callback_team_change_handler = NULL;
callback_teamdctl_connect = NULL;
callback_teamdctl_config_get_raw_direct = NULL;
callback_teamdctl_disconnect = NULL;
}
};

TEST_F(TeamPortSyncTest, TestInvalidIfIndex)
{
try {
swss::TeamSync::TeamPortSync("testLag", 0, NULL);
FAIL();
} catch (std::runtime_error &exception) {
EXPECT_THAT(exception.what(), testing::HasSubstr("Unable to initialize team socket"));
}
}

TEST_F(TeamPortSyncTest, NoLagPresent)
{
try {
swss::TeamSync::TeamPortSync("testLag", 4, NULL);
FAIL();
} catch (std::runtime_error &exception) {
EXPECT_THAT(exception.what(), testing::HasSubstr("Unable to initialize team socket"));
}
}

TEST_F(TeamPortSyncTest, TeamdctlNoConfig)
{
callback_team_init = cb_team_init;
callback_team_change_handler = cb_team_change_handler;
callback_teamdctl_connect = cb_teamdctl_connect;
try {
swss::TeamSync::TeamPortSync("testLag", 4, NULL);
FAIL();
} catch (std::runtime_error &exception) {
EXPECT_THAT(exception.what(), testing::HasSubstr("Unable to get config from teamd"));
}
}

TEST_F(TeamPortSyncTest, AllSuccess)
{
callback_team_init = cb_team_init;
callback_team_change_handler = cb_team_change_handler;
callback_teamdctl_connect = cb_teamdctl_connect;
callback_teamdctl_config_get_raw_direct = cb_teamdctl_config_get_raw_direct_success;
swss::TeamSync::TeamPortSync("testLag", 4, NULL);
}
}
Loading