Skip to content
Snippets Groups Projects
Commit 95007528 authored by Shubham's avatar Shubham Committed by Rahul Thakur
Browse files

Test, coverage and documentation fixes

 - all test scenarios added for functional testing
 - wrong method for qos object
 - strncpy fixed and ports uci file needed for testing
 - compilation fix for functional test
 - Added dummy test stats for test platform
 - removed reload from documentation
 - unnecessary test removal
parent 03df56c6
Branches
No related tags found
1 merge request!9Test, coverage and documentation fixes
Pipeline #11658 passed
......@@ -30,21 +30,6 @@ run_api_test:
- api-test-memory-report.xml
- timestamp.log
run_unit_test:
stage: unit_test
image: iopsys/code-analysis-dev
allow_failure: false
script:
- "./gitlab-ci/install-dependencies.sh"
- "./gitlab-ci/setup.sh"
- "./gitlab-ci/unit-test.sh"
artifacts:
when: always
paths:
- unit-test-coverage.xml
- timestamp.log
run_functional_test:
stage: functional_test
image: iopsys/code-analysis-dev
......
......@@ -6,7 +6,7 @@ QOSMNGR_LIB=libqosmngr.so
GCOV=gcov
SRC_DIR = src
CODECOVERAGE_SRC = $(addprefix $(SRC_DIR), qosmngr.c )
CODECOVERAGE_SRC = $(addprefix $(SRC_DIR)/, qosmngr.c )
PROG = $(PROJECT_TOPLEVEL)/qosmngr
SHARED_LIB = $(PROJECT_TOPLEVEL)/libqosmngr.so
OBJS = $(addprefix $(SRC_DIR)/, main.o qosmngr.o )
......@@ -45,9 +45,6 @@ coverage: LDFLAGS += --coverage
coverage: test $(PROG)
$(foreach testprog, $(CODECOVERAGE_SRC), $(GCOV) $(testprog);)
unit-test: test
$(MAKE) -C test/cmocka unit-test
functional-test: test
$(MAKE) -C test/cmocka functional-test
......
......@@ -13,7 +13,6 @@ http://example.com/root.json
| List of Methods |
| --------------------------- |
| [queue_stats](#queue_stats) | Method | qos (this schema) |
| [reload](#reload) | Method | qos (this schema) |
| `*` | any | Additional | Yes | this schema _allows_ additional properties |
## queue_stats
......@@ -44,7 +43,7 @@ http://example.com/root.json
| Property | Type | Required |
| -------- | ------- | ------------ |
| `ifname` | string | **Required** |
| `ifname` | string | Optional |
| `qid` | integer | Optional |
#### ifname
......@@ -252,79 +251,3 @@ All items must be of the type: `object` with following properties:
}
```
## reload
`reload`
- type: `Method`
### reload Type
`object` with following properties:
| Property | Type | Required |
| -------- | ------ | -------- |
| `input` | object | Optional |
| `output` | object | Optional |
#### input
`input`
- is optional
- type: `object`
##### input Type
`object` with following properties:
| Property | Type | Required |
| --------- | ------ | ------------ |
| `section` | string | **Required** |
#### section
`section`
- is **required**
- type: `string`
##### section Type
`string`
- minimum length: 1 characters
- maximum length: 16 characters
### Ubus CLI Example
```
ubus call qos reload {"section":"aliquip repr"}
```
### JSONRPC Example
```json
{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "qos", "reload", { "section": "aliquip repr" }] }
```
#### output
`output`
- is optional
- type: `object`
##### output Type
`object` with following properties:
| Property | Type | Required |
| -------- | ---- | -------- |
| None | None | None |
### Output Example
```json
{}
```
......@@ -10,7 +10,9 @@ sleep 3
supervisorctl status all
# run API validation
echo "Validating ubus api with ubs-api-validator"
ubus-api-validator -d ./test/api/json/ > ./api-result.log
echo "Please check test result under pipeline test tab."
supervisorctl stop all
supervisorctl status
......
#!/bin/bash
echo "preparation script"
echo "Functional Test"
pwd
make coverage -C ./
supervisorctl status all
supervisorctl update
sleep 3
......
......@@ -9,14 +9,13 @@ cd /opt/dev
rm -fr easy-soc-libs
git clone https://dev.iopsys.eu/iopsys/easy-soc-libs.git
cd easy-soc-libs
git checkout wip/libqos/subject-to-rebase
cd libeasy
make CFLAGS+="-I/usr/include/libnl3"
mkdir -p /usr/include/easy
cp easy.h event.h utils.h /usr/include/easy
cp easy.h event.h utils.h if_utils.h debug.h /usr/include/easy
cp -a libeasy*.so* /usr/lib
cd ../libqos
make PLATFORM=TEST
make PLATFORM=TEST
cp qos.h /usr/include
cp -a libqos.so* /usr/lib
sudo ldconfig
#!/bin/bash
echo "preparation script"
pwd
make unit-test -C ./
#report part
#GitLab-CI output
gcovr -r .
# Artefact
gcovr -r . --xml -o ./unit-test-coverage.xml
date +%s > timestamp.log
\ No newline at end of file
......@@ -13,29 +13,6 @@
"title": "qos",
"object": "qos",
"properties": {
"reload": {
"type": "object",
"properties": {
"input": {
"type": "object",
"required": [
"section"
],
"properties": {
"section": {
"type": "string",
"minLength": 1,
"maxLength": 16
}
}
},
"output": {
"type": "object",
"required": [],
"properties": {}
}
}
},
"queue_stats": {
"type": "object",
"properties": {
......
......@@ -36,6 +36,8 @@
#define MIN_INDEX 48
#define MAX_INDEX 57
int test_flag = 0;
static int init_flag = 1;
static struct qos_stats **q_stat = {0};
......@@ -288,7 +290,7 @@ static int get_stats_for_all_intf(struct blob_buf *b, struct qos_stats *stats, v
struct uci_section *uci_sec = uci_to_section(uci_elmnt);
if (uci_sec) {
struct uci_option *uci_opn = uci_lookup_option(uci_ctx, uci_sec, "ifname");
strcpy(ifname, uci_opn->v.string);
strncpy(ifname, uci_opn->v.string, sizeof(ifname) - 1);
ret = get_stats_by_ifname(b, stats, dd, ifname, QOS_QUEUE_ANY);
if (ret != 0) {
syslog(LOG_ERR, "get_stats_by_ifname : ret %d\n", ret);
......
{
"object": "qos",
"methods": [
{
"method": "get_status",
"args": {
"ifname": "test"
},
"rc": 0
},
{
"method": "get_status",
"args": {
"ifname": "test",
"qid": 0
},
"rc": 0
}
]
"object": "qos",
"methods": [
{
"method": "queue_stats",
"rc": 0
},
{
"method": "queue_stats",
"args": {
"ifname": "eth0"
},
"rc": 0
},
{
"method": "queue_stats",
"args": {
"ifname": "eth0",
"qid": 0
},
"rc": 0
}
]
}
......@@ -3,9 +3,8 @@ include ../../common.mk
QOSMNGR_LIB_DIR = $(PROJECT_TOPLEVEL)
CMOCKA_LIB = -lcmocka
LIBS = $(QOSMNGR_LDFLAGS) $(CMOCKA_LIB) -lpthread $(COMMON_LDFLAGS) -ljson-validator -ljson-schema-validator -ljson-editor
CFLAGS = -g -Wall -O0 -fprofile-arcs -ftest-coverage -fPIC -I$(INCLUDE_DIR)
CFLAGS = -g -Wall -O0 -fPIC -I$(INCLUDE_DIR)
LDFLAGS = $(LIBS) -Wl,-rpath=$(QOSMNGR_LIB_DIR) -I$(QOSMNGR_LIB_DIR) --coverage
UNIT_TESTS = unit_test_qos
FUNCTIONAL_TESTS = functional_test_qos
VALGRIND = valgrind --leak-check=full --show-reachable=no \
......@@ -15,19 +14,13 @@ VALGRIND = valgrind --leak-check=full --show-reachable=no \
%.o: %.c
$(CC) $(CFLAGS) $(FPIC) -c -o $@ $<
unit_test_qos: unit_test_qos.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
functional_test_qos: functional_test_qos.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
unit-test: $(UNIT_TESTS)
$(foreach testprog, $(UNIT_TESTS), sudo $(VALGRIND) ./$(testprog);)
functional-test: $(FUNCTIONAL_TESTS)
$(foreach testprog, $(FUNCTIONAL_TESTS), sudo $(VALGRIND) ./$(testprog);)
.PHONY: clean
clean:
rm $(UNIT_TESTS) $(FUNCTIONAL_TESTS) *.o *.gcno *.gcda -fv
rm $(FUNCTIONAL_TESTS) *.o *.gcno *.gcda -fv
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <errno.h>
#include <cmocka.h>
#include <libubus.h>
......@@ -10,48 +16,226 @@
#include <json-validator.h>
#include <json-c/json.h>
#include <json-editor.h>
#include <json-c/json_tokener.h>
#include <easy/easy.h>
#include <qos.h>
#include "qosmngr.h"
struct test_ctx {
FILE *fp;
};
#define UBUS_OUTPUT_FILE "/tmp/qosmngr_ubus_output.txt"
int qosmngr_event_main(const char *evmap_file);
struct json_object *json_output = NULL;
/**
* group_setup function to setup the test modules
* @param state input parameter pointer to a pointer to test state
*/
static int group_setup(void **state)
{
struct test_ctx *ctx = calloc(1, sizeof(struct test_ctx));
if (!ctx)
return -1;
// Start ubusd if it is not running
system("pidof ubusd || ubusd &");
remove("/tmp/test.log");
// Restart qosmngr
system("kill $(pidof qosmngr) 2>/dev/null; ../../qosmngr &");
*state = ctx;
return 0;
}
/**
* group_teardown function to cleanup the test modules
* @param state input parameter pointer to a pointer to test state
*/
static int group_teardown(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
// Stop qosmngr
system("kill $(pidof qosmngr) 2>/dev/null");
// Delete test logs
unlink(UBUS_OUTPUT_FILE);
return 0;
}
free(ctx);
remove("/tmp/test.log");
/**
* teardown function to cleanup the test modules
* @param state input parameter pointer to a pointer to test state
*/
static int teardown(void **state)
{
if (json_output) {
json_object_put(json_output); // Free the output JSON object
json_output = NULL;
}
/* TODO: fix event poll file */
//if (ctx->fp)
//fclose(ctx->fp);
return 0;
}
/**
* validate_queues function to validate all queues received under queues
* @param queues input parameter pointer to json_object containg all queues to
* be validated
*/
static void validate_queues(struct json_object *queues)
{
int i;
int len;
struct json_object *queue;
assert_non_null(queues);
len = json_object_array_length(queues);
// Assert on length as well, should be greater than 0
assert_true(len >= 0);
for (i = 0; i < len; i++) {
queue = json_object_array_get_idx(queues, i);
json_object_object_foreach(queue, key, val) {
int val_type = json_object_get_type(val);
switch(val_type) {
case json_type_int:
assert_true(json_object_get_int(val) >= 0);
break;
case json_type_string:
assert_true(!strncmp(json_object_get_string(val),
"eth", strlen("eth")));
break;
}
}
}
}
/**
* validate_stats function to validate json_object received under json_obj
* @param json_obj input parameter pointer to json_object containg ubus output
*/
static void validate_stats(struct json_object *json_obj)
{
assert_non_null(json_obj);
json_object_object_foreach(json_obj, key, val) {
int val_type = json_object_get_type(val);
if (val_type == json_type_array) {
switch (val_type) {
case json_type_array:
validate_queues(val);
break;
}
}
}
}
/**
* get_ubus_call_output function to fill global json output variable with ubus call output
* @param ubus_cmd input parameter pointer to char string containg ubus call
* @param negative_case input parameter of type bool to identify negative scenarios
*/
static void get_ubus_call_output(const char *ubus_cmd, bool negative_case)
{
char cmd[256];
int fd = -1;
char *str = NULL;
// Put the output of ubus call into a string
snprintf(cmd, sizeof(cmd), "%s > %s", ubus_cmd, UBUS_OUTPUT_FILE);
int rc = system(cmd);
assert_return_code(rc, errno);
fd = open(UBUS_OUTPUT_FILE, O_RDONLY);
assert_return_code(fd, errno);
struct stat st;
rc = fstat(fd, &st);
if(negative_case) {
assert_false(rc == 0 && st.st_size > 0);
return;
} else
assert_true(rc == 0 && st.st_size > 0);
str = calloc(1, (size_t)st.st_size + 1);
assert_non_null(str);
ssize_t read_len = read(fd, str, (size_t)st.st_size);
assert_int_equal((int)read_len, (int)st.st_size);
// Parse the string to a json_object
//printf("JSON_OBJECT GET : %s\n", str);
json_output = json_tokener_parse(str);
if (fd >= 0)
close(fd);
if (str)
free(str);
}
/**
* test_qos_stats_no_param function to test qos_stats without any parameter
* @param state input parameter pointer to a pointer to test state
*/
static void test_qos_stats_no_param(void **state)
{
get_ubus_call_output("ubus call qos queue_stats", false);
validate_stats(json_output);
}
/**
* test_qos_stats_one_param function to test qos_stats with just ifname
* @param state input parameter pointer to a pointer to test state
*/
static void test_qos_stats_one_param(void **state)
{
get_ubus_call_output("ubus call qos queue_stats '{\"ifname\":\"eth0\"}'", false);
validate_stats(json_output);
}
/**
* test_qos_stats_all_param function to test qos_stats with all valid params
* @param state input parameter pointer to a pointer to test state
*/
static void test_qos_stats_all_param(void **state)
{
get_ubus_call_output("ubus call qos queue_stats '{\"ifname\":\"eth0\", \"qid\":0}'", false);
validate_stats(json_output);
}
/**
* test_qos_stats_missing_param_ifname function to test missing parameter i.e., ifname
* @param state input parameter pointer to a pointer to test state
*/
static void test_qos_stats_missing_param_ifname(void **state)
{
get_ubus_call_output("ubus call qos queue_stats '{\"qid\":0}'", true);
}
/**
* test_qos_stats_invalid_param_port function to test invalid parameter as port
* @param state input parameter pointer to a pointer to test state
*/
static void test_qos_stats_invalid_param_port(void **state)
{
get_ubus_call_output("ubus call qos queue_stats '{\"port\":\"eth0\"}'", true);
}
/**
* test_qos_stats_invalid_param_pid function to test invalid parameter as pid
* @param state input parameter pointer to a pointer to test state
*/
static void test_qos_stats_invalid_param_pid(void **state)
{
get_ubus_call_output("ubus call qos queue_stats '{\"ifname\":\"eth0\", \"pid\":0}'", true);
}
int main(void)
{
const struct CMUnitTest tests[] = { };
const struct CMUnitTest tests[] = {
cmocka_unit_test_teardown(test_qos_stats_no_param, teardown),
cmocka_unit_test_teardown(test_qos_stats_one_param, teardown),
cmocka_unit_test_teardown(test_qos_stats_all_param, teardown),
// -ve scenarios
cmocka_unit_test_teardown(test_qos_stats_missing_param_ifname, teardown),
cmocka_unit_test_teardown(test_qos_stats_invalid_param_port, teardown),
cmocka_unit_test_teardown(test_qos_stats_invalid_param_pid, teardown),
};
return cmocka_run_group_tests(tests, group_setup, group_teardown);
}
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <libubus.h>
#include <libubox/blobmsg_json.h>
#include <libubox/blobmsg.h>
#include <json-validator.h>
#include <json-c/json.h>
#include <json-editor.h>
#include <json-c/json_tokener.h>
#include <easy/easy.h>
#include <qos.h>
#include <qosmngr.h>
struct test_ctx {
struct blob_buf bb;
struct ubus_object qos;
FILE *fp;
};
/* declare qosmngr functions */
int qosmngr_event_main(const char *evmap_file);
/* overload ubus_send_reply to prevent segfault*/
int ubus_send_reply(struct ubus_context *ctx, struct ubus_request_data *req,
struct blob_attr *msg)
{
return 0;
}
char *multi_tok(char *input, char *delimiter)
{
static char *string;
char *end, *temp;
if (input)
string = input;
if (!string)
return string;
end = strstr(string, delimiter);
if (!end) {
char *temp = string;
string = NULL;
return temp;
}
temp = string;
*end = '\0';
string = end + strlen(delimiter);
return temp;
}
/* TODO: how to fix events without fopen and fclose every poll? */
struct json_object *poll_test_log(FILE *fp, const char *prefix)
{
char line[256] = {0};
char msg[256] = {0};
struct json_object *obj = NULL;
fp = fopen("/tmp/test.log", "r");
if (!fp) {
return NULL;
}
while (fgets(line, 256, fp)) {
char *ptr, *s;
char appended[32];
snprintf(appended, sizeof(appended), "%s:", prefix);
ptr = strstr(line, appended);
if (!ptr)
continue;
s = multi_tok(ptr, appended);
s = multi_tok(NULL, appended);
strncpy(msg, s, sizeof(msg));
}
if (strlen(msg))
obj = json_tokener_parse(msg);
fclose(fp);
return obj;
}
static int group_setup(void **state)
{
struct test_ctx *ctx = calloc(1, sizeof(struct test_ctx));
if (!ctx)
return -1;
remove("/tmp/test.log");
ctx->qos.name = "qos";
memset(&ctx->bb, 0, sizeof(struct blob_buf));
*state = ctx;
return 0;
}
static int group_teardown(void **state)
{
struct test_ctx *ctx = (struct test_ctx *) *state;
blob_buf_free(&ctx->bb);
free(ctx);
remove("/tmp/test.log");
/* TODO: fix event poll file */
//if (ctx->fp)
//fclose(ctx->fp);
return 0;
}
int main(void)
{
const struct CMUnitTest tests[] = {
};
return cmocka_run_group_tests(tests, group_setup, group_teardown);
}
config ethport 'LAN1'
option enabled '1'
option name 'LAN1'
option ifname 'eth1'
option speed '1000'
option duplex 'full'
option autoneg '1'
option eee '0'
option pause '0'
config ethport 'WAN'
option enabled '1'
option name 'WAN'
option ifname 'eth0'
option speed '1000'
option duplex 'full'
option autoneg '1'
option eee '0'
option pause '1'
option uplink '1'
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment