Skip to content

Commit 2cbb096

Browse files
committed
robot functional tests added
Todo: add more test
1 parent fe5aa4f commit 2cbb096

File tree

5 files changed

+143
-1
lines changed

5 files changed

+143
-1
lines changed

.github/workflows/cmake.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ jobs:
2121
run: sudo apt-get update
2222

2323
- name: Setup Dependencies
24-
run: sudo apt-get install cmake libc-ares-dev libcurl4-openssl-dev libev-dev build-essential clang-tidy-12 ${{ matrix.compiler }}
24+
run: sudo apt-get install cmake libc-ares-dev libcurl4-openssl-dev libev-dev build-essential clang-tidy-12 ${{ matrix.compiler }} dnsutils python3-pip
25+
26+
- name: Setup Robot Framework
27+
run: sudo pip3 install robotframework
2528

2629
- name: Set clang-tidy
2730
run: sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-12 100
@@ -36,3 +39,12 @@ jobs:
3639
CC: ${{ matrix.compiler }}
3740
# Build your program with the given configuration
3841
run: make -C ${{github.workspace}}/
42+
43+
- name: Test
44+
run: make -C ${{github.workspace}}/ test ARGS="--verbose"
45+
46+
- uses: actions/upload-artifact@v2
47+
if: ${{ success() || failure() }}
48+
with:
49+
name: robot-logs-${{ matrix.compiler }}
50+
path: ${{github.workspace}}/tests/robot/*.html

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ install_manifest.txt
1313
.ninja_log
1414
build.ninja
1515
rules.ninja
16+
log.html
17+
output.xml
18+
report.html

CMakeLists.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
project(HttpsDnsProxy C)
22
cmake_minimum_required(VERSION 3.7)
33

4+
# FUNCTIONS
5+
46
# source: https://stackoverflow.com/a/27990434
57
function(define_file_basename_for_sources targetname)
68
get_target_property(source_files "${targetname}" SOURCES)
@@ -12,6 +14,8 @@ function(define_file_basename_for_sources targetname)
1214
endforeach()
1315
endfunction()
1416

17+
# CONFIG
18+
1519
set(CMAKE_BUILD_TYPE "Debug")
1620
#set(CMAKE_BUILD_TYPE "Release")
1721

@@ -24,6 +28,8 @@ if ((CMAKE_C_COMPILER_ID MATCHES GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREA
2428
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-gnu-zero-variadic-macro-arguments -Wno-gnu-folding-constant")
2529
endif()
2630

31+
# VERSION
32+
2733
find_package(Git)
2834
if(Git_FOUND)
2935
execute_process(
@@ -42,13 +48,17 @@ else()
4248
message(WARNING "Could not find git command! Version is set to: ${GIT_VERSION}")
4349
endif()
4450

51+
# LIBRARY DEPENDENCIES
52+
4553
find_path(LIBCARES_INCLUDE_DIR ares.h)
4654
find_path(LIBCURL_INCLUDE_DIR curl/curl.h)
4755
find_path(LIBEV_INCLUDE_DIR ev.h)
4856
include_directories(
4957
${LIBCARES_INCLUDE_DIR} ${LIBCURL_INCLUDE_DIR}
5058
${LIBEV_INCLUDE_DIR} src)
5159

60+
# CLANG TIDY
61+
5262
find_program(
5363
CLANG_TIDY_EXE
5464
NAMES "clang-tidy"
@@ -61,6 +71,8 @@ else()
6171
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-fix" "-checks=*,-clang-analyzer-alpha.*,-misc-unused-parameters,-cert-err34-c,-google-readability-todo,-hicpp-signed-bitwise,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-gnu-folding-constant,-gnu-zero-variadic-macro-arguments,-readability-function-cognitive-complexity,-concurrency-mt-unsafe")
6272
endif()
6373

74+
# BUILD
75+
6476
# The main binary
6577
set(TARGET_NAME "https_dns_proxy")
6678
aux_source_directory(src SRC_LIST)
@@ -82,6 +94,8 @@ if(CLANG_TIDY_EXE)
8294
)
8395
endif()
8496

97+
# INSTALL
98+
8599
install(TARGETS ${TARGET_NAME} DESTINATION bin)
86100

87101
set(SERVICE_EXTRA_OPTIONS "")
@@ -100,3 +114,20 @@ configure_file(${TARGET_NAME}.service.in ${TARGET_NAME}.service)
100114

101115
install(FILES ${TARGET_NAME}.service
102116
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/systemd/system/)
117+
118+
# TESTING
119+
120+
find_program(
121+
PYTHON3_EXE
122+
NAMES "python3"
123+
DOC "Path to python3 executable"
124+
)
125+
if(NOT PYTHON3_EXE)
126+
message(STATUS "python3 not found, robot testing not possible")
127+
else()
128+
message(STATUS "python3 found: ${PYTHON3_EXE}")
129+
130+
enable_testing()
131+
add_test(NAME robot COMMAND ${PYTHON3_EXE} -m robot.run functional_tests.robot
132+
WORKING_DIRECTORY tests/robot)
133+
endif()

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,17 @@ Usage: ./https_dns_proxy [-a <listen_addr>] [-p <listen_port>]
183183
-h Print help and exit.
184184
```
185185

186+
## Testing
187+
188+
Functional tests can be executed using [Robot Framework](https://robotframework.org/).
189+
190+
dig command is expected to be available.
191+
192+
```
193+
pip3 install robotframework
194+
python3 -m robot.run tests/robot/functional_tests.robot
195+
```
196+
186197
## TODO
187198

188199
* Add some tests.

tests/robot/functional_tests.robot

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
*** Settings ***
2+
Documentation Simple functional tests for https_dns_proxy
3+
Library OperatingSystem
4+
Library Process
5+
Library Collections
6+
7+
8+
*** Variables ***
9+
${BINARY_PATH} ${CURDIR}/../../https_dns_proxy
10+
${PORT} 55353
11+
12+
13+
*** Settings ***
14+
Test Setup Start Proxy
15+
Test Teardown Stop Proxy
16+
17+
18+
*** Keywords ***
19+
Start Proxy
20+
[Arguments] @{args}
21+
@{default_args} = Create List -v -v -v -4 -p ${PORT}
22+
@{proces_args} = Combine Lists ${default_args} ${args}
23+
${proxy} = Start Process ${BINARY_PATH} @{proces_args}
24+
# ... stdout=${TEMPDIR}/https_dns_proxy_robot_test_stdout.txt
25+
... stderr=STDOUT alias=proxy
26+
Set Test Variable ${proxy}
27+
Set Test Variable &{expected_logs} loop destroyed=1 # last log line
28+
Set Test Variable @{error_logs} [F] # any fatal error
29+
Sleep 0.5
30+
31+
Stop Proxy
32+
Send Signal To Process SIGINT ${proxy}
33+
${result} = Wait For Process ${proxy} timeout=15 secs
34+
Log ${result.stdout}
35+
FOR ${log} ${times} IN &{expected_logs}
36+
Should Contain X Times ${result.stdout} ${log} ${times}
37+
END
38+
FOR ${log} IN @{error_logs}
39+
Run Keyword And Expect Error not found
40+
... Should Contain ${result.stdout} ${log} msg=not found values=False
41+
END
42+
Should Be Equal As Integers ${result.rc} 0
43+
44+
45+
Start Dig
46+
[Arguments] ${domain}=google.com
47+
${handle} = Start Process dig +timeout\=2 +retry\=0 @127.0.0.1 -p ${PORT} ${domain}
48+
... stderr=STDOUT alias=dig
49+
[Return] ${handle}
50+
51+
Stop Dig
52+
[Arguments] ${handle}
53+
${result} = Wait For Process ${handle} timeout=10 secs
54+
Log ${result.stdout}
55+
Should Be Equal As Integers ${result.rc} 0
56+
Should Contain ${result.stdout} ANSWER SECTION
57+
58+
Run Dig
59+
[Arguments] ${domain}=google.com
60+
${handle} = Start Dig ${domain}
61+
Stop Dig ${handle}
62+
63+
64+
*** Test Cases ***
65+
Simple smoke test
66+
Run Dig
67+
68+
Handle Unbound Server Does Not Support HTTP/1.1
69+
[Setup] NONE
70+
Start Proxy -x -r https://doh.mullvad.net/dns-query # resolver uses Unbound
71+
Run Keyword And Expect Error 9 != 0 # timeout exit code
72+
... Run Dig
73+
74+
Reuse HTTP/2 Connection
75+
[Documentation] After first successful request, further requests should not open new connections
76+
Run Dig # opens first connection
77+
${dig_handles} = Create List
78+
FOR ${domain} IN facebook.com microsoft.com youtube.com maps.google.com wikipedia.org amazon.com
79+
${handle} = Start Dig ${domain}
80+
Append To List ${dig_handles} ${handle}
81+
END
82+
FOR ${handle} IN @{dig_handles}
83+
Stop Dig ${handle}
84+
END
85+
Set To Dictionary ${expected_logs} curl opened socket=1 # curl must not open more sockets then 1

0 commit comments

Comments
 (0)