Skip to content

Commit

Permalink
Add unittest infrastructure (#5) (#31)
Browse files Browse the repository at this point in the history
This is cherry-pick from PR #5
Signed-off-by: kellyyeh [email protected]

Why I did it
Add unittest infrastructure

How I did it
Modified Makefile and added test directory

How to verify it
Run make
  • Loading branch information
kellyyeh authored Feb 1, 2023
1 parent 21bff54 commit d4a51f6
Show file tree
Hide file tree
Showing 16 changed files with 841 additions and 75 deletions.
13 changes: 11 additions & 2 deletions .azure-pipelines/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ jobs:
libnl-3-dev \
libnl-route-3-dev \
libnl-genl-3-dev \
libnl-nf-3-dev
libnl-nf-3-dev \
redis-server
sudo sed -ri 's/^# unixsocket/unixsocket/' /etc/redis/redis.conf
sudo sed -ri 's/^unixsocketperm .../unixsocketperm 777/' /etc/redis/redis.conf
sudo sed -ri 's/redis-server.sock/redis.sock/' /etc/redis/redis.conf
sudo service redis-server start
displayName: "Install dependencies"
- checkout: self
Expand Down Expand Up @@ -73,9 +78,13 @@ jobs:
- publish: $(Build.ArtifactStagingDirectory)
artifact: sonic-dhcp-relay.${{ parameters.arch }}
displayName: "Archive dhcp-relay debian packages"
- task: PublishTestResults@2
inputs:
testResultsFiles: build-test/dhcp6relay-test-test-result.xml
- ${{ if and(eq(parameters.arch, 'amd64'), parameters.codeCoverage) }}:
- task: PublishCodeCoverageResults@1
inputs:
summaryFileLocation: dhcprelay-test-result.xml
summaryFileLocation: build-test/dhcp6relay-test-code-coverage.xml
pathToSources: $(Build.SourcesDirectory)
reportDirectory: $(Build.SourcesDirectory)/build-test
codeCoverageTool: 'Cobertura'
56 changes: 43 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,36 +1,66 @@
RM := rm -rf
DHCP6RELAY_TARGET := dhcp6relay
BUILD_DIR := build
BUILD_TEST_DIR := build-test
DHCP6RELAY_TARGET := $(BUILD_DIR)/dhcp6relay
DHCP6RELAY_TEST_TARGET := $(BUILD_TEST_DIR)/dhcp6relay-test
CP := cp
MKDIR := mkdir
MV := mv
FIND := find
GCOVR := gcovr
override LDLIBS += -levent -lhiredis -lswsscommon -pthread -lboost_thread -lboost_system
override CPPFLAGS += -Wall -std=c++17 -fPIE -I/usr/include/swss
override CPPFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)"
CPPFLAGS_TEST := --coverage -fprofile-arcs -ftest-coverage -fprofile-generate -fsanitize=address
LDLIBS_TEST := --coverage -lgtest -pthread -lstdc++fs -fsanitize=address
PWD := $(shell pwd)

all: $(DHCP6RELAY_TARGET)
all: $(DHCP6RELAY_TARGET) $(DHCP6RELAY_TEST_TARGET)

-include src/subdir.mk
-include test/subdir.mk

# Use different build directories based on whether it's a regular build or a
# test build. This is because in the test build, code coverage is enabled,
# which means the object files that get built will be different
OBJS = $(SRCS:%.cpp=$(BUILD_DIR)/%.o)
TEST_OBJS = $(TEST_SRCS:%.cpp=$(BUILD_TEST_DIR)/%.o)

ifneq ($(MAKECMDGOALS),clean)
-include $(OBJS:%.o=%.d)
-include $(TEST_OBJS:%.o=%.d)
endif

-include src/subdir.mk
$(BUILD_DIR)/%.o: %.cpp
@mkdir -p $(@D)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<

$(DHCP6RELAY_TARGET): $(OBJS)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

install:
$(MKDIR) -p $(DESTDIR)/usr/sbin
$(MV) $(DHCP6RELAY_TARGET) $(DESTDIR)/usr/sbin
$(BUILD_TEST_DIR)/%.o: %.cpp
@mkdir -p $(@D)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(CPPFLAGS_TEST) -c -o $@ $<

deinstall:
$(RM) $(DESTDIR)/usr/sbin/$(DHCP6RELAY_TARGET)
$(RM) -rf $(DESTDIR)/usr/sbin
$(DHCP6RELAY_TEST_TARGET): $(TEST_OBJS)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LDLIBS_TEST) -o $@

clean:
-$(RM) $(EXECUTABLES) $(OBJS:%.o=%.d) $(OBJS) $(DHCP6RELAY_TARGET)
-@echo ' '
test: $(DHCP6RELAY_TEST_TARGET)
sudo ASAN_OPTIONS=detect_leaks=0 ./$(DHCP6RELAY_TEST_TARGET) --gtest_output=xml:$(DHCP6RELAY_TEST_TARGET)-test-result.xml || true
$(GCOVR) -r ./ --html --html-details -o $(DHCP6RELAY_TEST_TARGET)-code-coverage.html
$(GCOVR) -r ./ --xml-pretty -o $(DHCP6RELAY_TEST_TARGET)-code-coverage.xml

install: $(DHCP6RELAY_TARGET)
install -D $(DHCP6RELAY_TARGET) $(DESTDIR)/usr/sbin/$(notdir $(DHCP6RELAY_TARGET))

.PHONY: all clean dependents
uninstall:
$(RM) $(DESTDIR)/usr/sbin/$(notdir $(DHCP6RELAY_TARGET))

clean:
-$(RM) $(BUILD_DIR) $(BUILD_TEST_DIR) *.html *.xml
$(FIND) . -name *.gcda -exec rm -f {} \;
$(FIND) . -name *.gcno -exec rm -f {} \;
$(FIND) . -name *.gcov -exec rm -f {} \;
-@echo ' '

.PHONY: all clean test install uninstall
22 changes: 12 additions & 10 deletions src/configInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ constexpr auto DEFAULT_TIMEOUT_MSEC = 1000;

bool pollSwssNotifcation = true;
std::shared_ptr<boost::thread> mSwssThreadPtr;

std::shared_ptr<swss::DBConnector> configDbPtr = std::make_shared<swss::DBConnector> ("CONFIG_DB", 0);
swss::SubscriberStateTable ipHelpersTable(configDbPtr.get(), "DHCP_RELAY");
swss::Select swssSelect;

/**
Expand All @@ -22,9 +19,14 @@ swss::Select swssSelect;
void initialize_swss(std::vector<relay_config> *vlans)
{
try {
std::shared_ptr<swss::DBConnector> configDbPtr = std::make_shared<swss::DBConnector> ("CONFIG_DB", 0);
swss::SubscriberStateTable ipHelpersTable(configDbPtr.get(), "DHCP_RELAY");
swssSelect.addSelectable(&ipHelpersTable);
get_dhcp(vlans);
mSwssThreadPtr = std::make_shared<boost::thread> (&handleSwssNotification, vlans);
get_dhcp(vlans, &ipHelpersTable);
struct swssNotification test;
test.vlans = vlans;
test.ipHelpersTable = &ipHelpersTable;
mSwssThreadPtr = std::make_shared<boost::thread> (&handleSwssNotification, test);
}
catch (const std::bad_alloc &e) {
syslog(LOG_ERR, "Failed allocate memory. Exception details: %s", e.what());
Expand Down Expand Up @@ -52,15 +54,15 @@ void deinitialize_swss()
*
* @return none
*/
void get_dhcp(std::vector<relay_config> *vlans) {
void get_dhcp(std::vector<relay_config> *vlans, swss::SubscriberStateTable *ipHelpersTable) {
swss::Selectable *selectable;
int ret = swssSelect.select(&selectable, DEFAULT_TIMEOUT_MSEC);
if (ret == swss::Select::ERROR) {
syslog(LOG_WARNING, "Select: returned ERROR");
} else if (ret == swss::Select::TIMEOUT) {
}
if (selectable == static_cast<swss::Selectable *> (&ipHelpersTable)) {
handleRelayNotification(ipHelpersTable, vlans);
if (selectable == static_cast<swss::Selectable *> (ipHelpersTable)) {
handleRelayNotification(*ipHelpersTable, vlans);
}
}
/**
Expand All @@ -72,10 +74,10 @@ void get_dhcp(std::vector<relay_config> *vlans) {
*
* @return none
*/
void handleSwssNotification(std::vector<relay_config> *vlans)
void handleSwssNotification(swssNotification test)
{
while (pollSwssNotifcation) {
get_dhcp(vlans);
get_dhcp(test.vlans, test.ipHelpersTable);
}
}

Expand Down
14 changes: 10 additions & 4 deletions src/configInterface.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#pragma once

#include <boost/thread.hpp>
#include "subscriberstatetable.h"
#include "select.h"
#include "relay.h"

struct swssNotification {
std::vector<relay_config> *vlans;
swss::SubscriberStateTable *ipHelpersTable;
};
/**
* @code void initialize_swss()
*
Expand All @@ -28,18 +34,18 @@ void deinitialize_swss();
*
* @return none
*/
void get_dhcp(std::vector<relay_config> *vlans);
void get_dhcp(std::vector<relay_config> *vlans, swss::SubscriberStateTable *ipHelpersTable);

/**
* @code void handleSwssNotification(std::vector<relay_config> *vlans)
* @code void swssNotification test
*
* @brief main thread for handling SWSS notification
*
* @param vlans list of vlans/argument config that contains strings of server and option
* @param test swssNotification that includes list of vlans/argument config that contains strings of server and option
*
* @return none
*/
void handleSwssNotification(std::vector<relay_config> *vlans);
void handleSwssNotification(swssNotification test);

/**
* @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector<relay_config> *vlans)
Expand Down
40 changes: 15 additions & 25 deletions src/relay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ struct event *ev_sigterm;
static std::string vlan_member = "VLAN_MEMBER|";

static std::string counter_table = "DHCPv6_COUNTER_TABLE|";
struct database redis_db;

/* DHCPv6 filter */
/* sudo tcpdump -dd "inbound and ip6 dst ff02::1:2 && udp dst port 547" */
Expand Down Expand Up @@ -221,24 +220,9 @@ const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_
return option;
}

/**
* @code void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type);
*
* @brief send udp packet
*
* @param *buffer message buffer
* @param sockaddr_in6 target target socket
* @param n length of message
* @param relay_config *config pointer to relay_config
* @param uint8_t msg_type message type of dhcpv6 option of relayed message
*
* @return dhcpv6_option end of dhcpv6 message option
*/
void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type) {
void process_sent_msg(relay_config *config, uint8_t msg_type) {
std::string counterVlan = counter_table;
if(sendto(sock, buffer, n, 0, (const struct sockaddr *)&target, sizeof(target)) == -1)
syslog(LOG_ERR, "sendto: Failed to send to target address\n");
else if (counterMap.find(msg_type) != counterMap.end()) {
if (counterMap.find(msg_type) != counterMap.end()) {
counters[msg_type]++;
update_counter(config->state_db, counterVlan.append(config->interface), msg_type);
} else {
Expand Down Expand Up @@ -497,7 +481,9 @@ void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_h
current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option);

for(auto server: config->servers_sock) {
send_udp(sock, buffer, server, current_buffer_position - buffer, config, new_message.msg_type);
if(send_udp(sock, buffer, server, current_buffer_position - buffer)) {
process_sent_msg(config, new_message.msg_type);
}
}
}

Expand Down Expand Up @@ -537,7 +523,9 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *
current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option);

for(auto server: config->servers_sock) {
send_udp(sock, buffer, server, current_buffer_position - buffer, config, new_message.msg_type);
if(send_udp(sock, buffer, server, current_buffer_position - buffer)) {
process_sent_msg(config, new_message.msg_type);
}
}
}

Expand Down Expand Up @@ -589,7 +577,9 @@ void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *
target_addr.sin6_port = htons(CLIENT_PORT);
target_addr.sin6_scope_id = if_nametoindex(config->interface.c_str());

send_udp(sock, buffer, target_addr, current_buffer_position - buffer, config, type);
if(send_udp(sock, buffer, target_addr, current_buffer_position - buffer)) {
process_sent_msg(config, type);
}
}

/**
Expand Down Expand Up @@ -728,9 +718,9 @@ void callback_dual_tor(evutil_socket_t fd, short event, void *arg) {
return;
std::string state;
std::string intf(interfaceName);
redis_db.muxTable->hget(intf, "state", state);
config->mux_table->hget(intf, "state", state);

if (state != "standby" && redis_db.config_db->exists(key.append(intf))) {
if (state != "standby" && config->config_db->exists(key.append(intf))) {
char* ptr = (char *)message_buffer;
const uint8_t *current_position = (uint8_t *)ptr;
const uint8_t *tmp = NULL;
Expand Down Expand Up @@ -970,8 +960,6 @@ void loop_relay(std::vector<relay_config> *vlans) {
std::shared_ptr<swss::Table> mStateDbMuxTablePtr = std::make_shared<swss::Table> (
state_db.get(), "HW_MUX_CABLE_TABLE"
);
redis_db.config_db = config_db;
redis_db.muxTable = mStateDbMuxTablePtr;

int filter = 0;
filter = sock_open(&ether_relay_fprog);
Expand All @@ -981,6 +969,8 @@ void loop_relay(std::vector<relay_config> *vlans) {
relay_config *config = &vlan;
int local_sock = 0;
int server_sock = 0;
config->config_db = config_db;
config->mux_table = mStateDbMuxTablePtr;
config->state_db = state_db;
config->mux_key = vlan_member + config->interface + "|";

Expand Down
Loading

0 comments on commit d4a51f6

Please sign in to comment.