mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Add a framework for regression tests
This commit is contained in:
parent
e8a991048f
commit
b53980da25
@ -9,6 +9,7 @@ header:
|
||||
- '**/*.S'
|
||||
- '**/*.s'
|
||||
- '**/*.c'
|
||||
- '**/*.h'
|
||||
- '**/*.sh'
|
||||
- '**/Makefile'
|
||||
- '**/Dockerfile.*'
|
||||
@ -58,4 +59,3 @@ header:
|
||||
content: |
|
||||
Licensed under the Apache License, Version 2.0 or the MIT License.
|
||||
Copyright (C) 2023-2024 Ant Group.
|
||||
|
79
regression/apps/network/tcp_err.c
Normal file
79
regression/apps/network/tcp_err.c
Normal file
@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static struct sockaddr_in sk_addr;
|
||||
|
||||
#define C_PORT htons(0x1234)
|
||||
#define S_PORT htons(0x1235)
|
||||
|
||||
FN_SETUP(general)
|
||||
{
|
||||
sk_addr.sin_family = AF_INET;
|
||||
sk_addr.sin_port = htons(8080);
|
||||
CHECK(inet_aton("127.0.0.1", &sk_addr.sin_addr));
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
static int sk_unbound;
|
||||
static int sk_bound;
|
||||
static int sk_listen;
|
||||
static int sk_connected;
|
||||
static int sk_accepted;
|
||||
|
||||
FN_SETUP(unbound)
|
||||
{
|
||||
sk_unbound = CHECK(socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_SETUP(bound)
|
||||
{
|
||||
sk_bound = CHECK(socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0));
|
||||
|
||||
sk_addr.sin_port = C_PORT;
|
||||
CHECK(bind(sk_bound, (struct sockaddr *)&sk_addr, sizeof(sk_addr)));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_SETUP(listen)
|
||||
{
|
||||
sk_listen = CHECK(socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0));
|
||||
|
||||
sk_addr.sin_port = S_PORT;
|
||||
CHECK(bind(sk_listen, (struct sockaddr *)&sk_addr, sizeof(sk_addr)));
|
||||
|
||||
CHECK(listen(sk_listen, 2));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_SETUP(connected)
|
||||
{
|
||||
sk_connected = CHECK(socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0));
|
||||
|
||||
sk_addr.sin_port = S_PORT;
|
||||
CHECK_WITH(connect(sk_connected, (struct sockaddr *)&sk_addr,
|
||||
sizeof(sk_addr)),
|
||||
_ret == 0 || errno == EINPROGRESS);
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_SETUP(accpected)
|
||||
{
|
||||
struct sockaddr addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
do {
|
||||
sk_accepted = CHECK_WITH(accept(sk_listen, &addr, &addrlen),
|
||||
_ret >= 0 || errno == EAGAIN);
|
||||
} while (sk_accepted < 0);
|
||||
}
|
||||
END_SETUP()
|
164
regression/apps/network/test.h
Normal file
164
regression/apps/network/test.h
Normal file
@ -0,0 +1,164 @@
|
||||
/* SPDX-License-Identifier: MPL-2.0 */
|
||||
|
||||
/*
|
||||
* A framework for writing regression tests.
|
||||
*
|
||||
* A regression test typically consists of two parts, the setup part and the
|
||||
* test part. The setup part contains setup functions that set up the context
|
||||
* for the subsequent tests to run. The setup functions cannot fail, and if they
|
||||
* do, execution is aborted because the subsequent tests will not work as
|
||||
* expected either. The test functions, on the other hand, can fail, and if they
|
||||
* do, they are reported as test failures.
|
||||
*
|
||||
* The framework provides basic utilities for writing regression tests:
|
||||
*
|
||||
* - To define a setup function or a test function, FN_SETUP() or FN_TEST() can
|
||||
* be used. These functions are automatically executed in the order of their
|
||||
* definiton. Note that the order of execution is _not_ related to whether a
|
||||
* function is a setup function or a test function.
|
||||
*
|
||||
* - Within a setup function, CHECK() can be used to write a setup expression
|
||||
* that must succeed. If the expression fails, a fatal error will be reported
|
||||
* and the execution will be aborted.
|
||||
*
|
||||
* - Within a test function, TEST_SUCC() can be used to write a test expression
|
||||
* that should succeed. If the expression fails, a test failure will be reported
|
||||
* but the execution will continue.
|
||||
*
|
||||
* - The number of successful and failed tests is tracked. When a test function
|
||||
* finishes, a summary sentence is printed describing the number of test
|
||||
* failures. The program will exit with a non-zero code if and only if there is
|
||||
* at least one test failure.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/** Starts the definition of a setup function. */
|
||||
#define FN_SETUP(name) \
|
||||
void setup_##name(void) __attribute__((constructor(__LINE__ + 200))); \
|
||||
\
|
||||
void setup_##name(void) \
|
||||
{
|
||||
/** Ends the definition of a setup function. */
|
||||
#define END_SETUP() }
|
||||
|
||||
#define __CHECK(func, cond) \
|
||||
errno = 0; \
|
||||
long _ret = (func); \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, \
|
||||
"fatal error: %s: `" #cond "` is false after `" #func \
|
||||
"` [got %s]\n", \
|
||||
__func__, strerror(errno)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a fucntion call and checks its return value is positive.
|
||||
*
|
||||
* The execution will be aborted if the check fails.
|
||||
*/
|
||||
#define CHECK(func) \
|
||||
({ \
|
||||
__CHECK(func, _ret >= 0); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
/**
|
||||
* Makes a function call and checks its result with the specified condition.
|
||||
*
|
||||
* The execution will be aborted if the check fails.
|
||||
*
|
||||
* The return value of the function can be accessed with a local variable named
|
||||
* _ret.
|
||||
*/
|
||||
#define CHECK_WITH(func, cond) \
|
||||
({ \
|
||||
__CHECK(func, cond); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
static int __total_failures;
|
||||
|
||||
/** Starts the definition of a test function. */
|
||||
#define FN_TEST(name) \
|
||||
void test_##name(void) __attribute__((constructor(__LINE__ + 200))); \
|
||||
\
|
||||
void test_##name(void) \
|
||||
{ \
|
||||
int __tests_passed = 0, __tests_failed = 0;
|
||||
|
||||
/** Ends the definition of a test function. */
|
||||
#define END_TEST() \
|
||||
fprintf(stderr, "%s summary: %d tests passed, %d tests failed\n", \
|
||||
__func__, __tests_passed, __tests_failed); \
|
||||
__total_failures += __tests_failed; \
|
||||
}
|
||||
|
||||
#define __TEST(func, err, cond) \
|
||||
errno = 0; \
|
||||
long _ret = (func); \
|
||||
if (errno != (err)) { \
|
||||
__tests_failed++; \
|
||||
fprintf(stderr, \
|
||||
"%s: `" #func "` failed [got %s, but expected %s]\n", \
|
||||
__func__, strerror(errno), strerror(err)); \
|
||||
} else if (!(cond)) { \
|
||||
__tests_failed++; \
|
||||
fprintf(stderr, \
|
||||
"%s: `" #func "` failed [got %s, but `" #cond \
|
||||
"` is false]\n", \
|
||||
__func__, strerror(errno)); \
|
||||
} else { \
|
||||
__tests_passed++; \
|
||||
fprintf(stderr, "%s: `" #func "` passed [got %s]\n", __func__, \
|
||||
strerror(errno)); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a function call and checks its result.
|
||||
*
|
||||
* A test failure will be reported if the function does not set the specified
|
||||
* errno or the specified condition does not meet.
|
||||
*
|
||||
* The return value of the function can be accessed with a local variable named
|
||||
* _ret.
|
||||
*/
|
||||
#define TEST(func, err, cond) \
|
||||
({ \
|
||||
__TEST(func, err, cond); \
|
||||
_ret; \
|
||||
})
|
||||
/**
|
||||
* Makes a function call and checks whether it succeeds.
|
||||
*
|
||||
* A test failure will be reported if the function sets a non-zero errno.
|
||||
*/
|
||||
#define TEST_SUCC(func) TEST(func, 0, 1)
|
||||
|
||||
/**
|
||||
* Makes a function call and checks whether it fails in the specified way.
|
||||
*
|
||||
* A test failure will be reported if the function does not set the specified
|
||||
* errno.
|
||||
*/
|
||||
#define TEST_ERRNO(func, err) TEST(func, err, 1)
|
||||
|
||||
/**
|
||||
* Makes a function call and checks whether it produces expected results.
|
||||
*
|
||||
* A test failure will be reported if the function sets a non-zero errno or the
|
||||
* specified condition does not meet.
|
||||
*
|
||||
* The return value of the function can be accessed with a local variable named
|
||||
* _ret.
|
||||
*/
|
||||
#define TEST_RES(func, cond) TEST(func, 0, cond)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return __total_failures ? 1 : 0;
|
||||
}
|
52
regression/apps/network/udp_err.c
Normal file
52
regression/apps/network/udp_err.c
Normal file
@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
static struct sockaddr_in sk_addr;
|
||||
|
||||
#define C_PORT htons(0x1234)
|
||||
|
||||
FN_SETUP(general)
|
||||
{
|
||||
sk_addr.sin_family = AF_INET;
|
||||
sk_addr.sin_port = htons(8080);
|
||||
CHECK(inet_aton("127.0.0.1", &sk_addr.sin_addr));
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
static int sk_unbound;
|
||||
static int sk_bound;
|
||||
static int sk_connected;
|
||||
|
||||
FN_SETUP(unbound)
|
||||
{
|
||||
sk_unbound = CHECK(socket(PF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_SETUP(bound)
|
||||
{
|
||||
sk_bound = CHECK(socket(PF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0));
|
||||
|
||||
sk_addr.sin_port = C_PORT;
|
||||
CHECK(bind(sk_bound, (struct sockaddr *)&sk_addr, sizeof(sk_addr)));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_SETUP(connected)
|
||||
{
|
||||
sk_connected = CHECK(socket(PF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0));
|
||||
|
||||
sk_addr.sin_port = C_PORT;
|
||||
CHECK(connect(sk_connected, (struct sockaddr *)&sk_addr,
|
||||
sizeof(sk_addr)));
|
||||
}
|
||||
END_SETUP()
|
@ -21,5 +21,7 @@ echo "Start network test......"
|
||||
# ./send_buf_full
|
||||
./http_server &
|
||||
./http_client
|
||||
./tcp_err
|
||||
./udp_err
|
||||
|
||||
echo "All network test passed"
|
||||
|
Loading…
x
Reference in New Issue
Block a user