Skip to content

Commit a045c1c

Browse files
mdns: Example tests integration
1 parent bbb4b7e commit a045c1c

File tree

3 files changed

+132
-78
lines changed

3 files changed

+132
-78
lines changed

.github/workflows/target-test.yml

Lines changed: 88 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
container: espressif/idf:${{ matrix.idf_ver }}
2424
steps:
2525
- name: Checkout esp-protocols
26-
uses: actions/checkout@v3
26+
uses: actions/checkout@master
2727
with:
2828
path: esp-protocols
2929
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
@@ -39,7 +39,8 @@ jobs:
3939
strategy:
4040
matrix:
4141
idf_ver: ["latest"]
42-
idf_target: ["esp32", "esp32s2", "esp32c3"]
42+
idf_target: ["esp32", "esp32s2", "esp32c3"]
43+
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
4344

4445
runs-on: ubuntu-20.04
4546
container: espressif/idf:${{ matrix.idf_ver }}
@@ -48,36 +49,41 @@ jobs:
4849
uses: actions/checkout@v3
4950
with:
5051
submodules: recursive
51-
path: esp-protocols
52-
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
52+
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.config }}
5353
env:
5454
IDF_TARGET: ${{ matrix.idf_target }}
5555
shell: bash
56+
working-directory: components/mdns/examples/
5657
run: |
5758
. ${IDF_PATH}/export.sh
58-
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/examples/
59-
idf.py set-target ${{ matrix.idf_target }}
60-
echo "Building for default configuration"
61-
idf.py build
62-
rm sdkconfig
63-
echo "Building for sdkconfig.ci.eth_def"
64-
cat sdkconfig.ci.eth_def >> sdkconfig.defaults
65-
idf.py build
66-
rm sdkconfig sdkconfig.defaults
67-
echo "Building for sdkconfig.ci.eth_custom_netif"
68-
cat sdkconfig.ci.eth_custom_netif >> sdkconfig.defaults
69-
idf.py build
70-
rm sdkconfig sdkconfig.defaults
71-
echo "Building for sdkconfig.ci.eth_socket"
72-
cat sdkconfig.ci.eth_socket >> sdkconfig.defaults
73-
idf.py build
74-
rm sdkconfig sdkconfig.defaults
75-
echo "Building for sdkconfig.ci.eth_no_ipv6"
76-
cat sdkconfig.ci.eth_no_ipv6 >> sdkconfig.defaults
77-
idf.py build
78-
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_apps/
59+
rm -rf sdkconfig sdkconfig.defaults build build_${{ matrix.config }}
60+
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
7961
idf.py set-target ${{ matrix.idf_target }}
8062
idf.py build
63+
mv build build_${{ matrix.config }}
64+
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.config }}
65+
working-directory: components/mdns/examples
66+
env:
67+
IDF_TARGET: ${{ matrix.idf_target }}
68+
shell: bash
69+
run: |
70+
. ${IDF_PATH}/export.sh
71+
cd build_${{ matrix.config }}
72+
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
73+
cd ../
74+
cat build_${{ matrix.config }}/config/sdkconfig.json
75+
- uses: actions/upload-artifact@v2
76+
with:
77+
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
78+
path: |
79+
components/mdns/examples/build_${{ matrix.config }}/bootloader/bootloader.bin
80+
components/mdns/examples/build_${{ matrix.config }}/partition_table/partition-table.bin
81+
components/mdns/examples/build_${{ matrix.config }}/*.bin
82+
components/mdns/examples/build_${{ matrix.config }}/*.elf
83+
components/mdns/examples/build_${{ matrix.config }}/flasher_args.json
84+
components/mdns/examples/build_${{ matrix.config }}/config/sdkconfig.h
85+
components/mdns/examples/build_${{ matrix.config }}/config/sdkconfig.json
86+
if-no-files-found: error
8187

8288
build_asio:
8389
strategy:
@@ -109,7 +115,6 @@ jobs:
109115
matrix:
110116
idf_ver: ["latest"]
111117
idf_target: ["esp32"]
112-
113118
runs-on: ubuntu-20.04
114119
container: espressif/idf:${{ matrix.idf_ver }}
115120
steps:
@@ -137,7 +142,14 @@ jobs:
137142
- uses: actions/upload-artifact@v2
138143
with:
139144
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
140-
path: components/esp_websocket_client/examples/build/
145+
path: |
146+
components/esp_websocket_client/examples/build/bootloader/bootloader.bin
147+
components/esp_websocket_client/examples/build/partition_table/partition-table.bin
148+
components/esp_websocket_client/examples/build/*.bin
149+
components/esp_websocket_client/examples/build/*.elf
150+
components/esp_websocket_client/examples/build/flasher_args.json
151+
components/esp_websocket_client/examples/build/config/sdkconfig.h
152+
components/esp_websocket_client/examples/build/config/sdkconfig.json
141153
if-no-files-found: error
142154

143155
run-target:
@@ -151,6 +163,8 @@ jobs:
151163
runs-on:
152164
- self-hosted
153165
- ESP32-ETHERNET-KIT
166+
# Skip running on forks since it won't have access to secrets
167+
if: github.repository == 'espressif/esp-protocols'
154168
container:
155169
image: python:3.7-buster
156170
options: --privileged # Privileged mode has access to serial ports
@@ -161,6 +175,8 @@ jobs:
161175
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
162176
path: components/esp_websocket_client/examples/build/
163177
- name: Install Python packages
178+
env:
179+
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
164180
run: |
165181
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/components/esp_websocket_client/examples/requirements.txt
166182
- name: Download Example Test to target
@@ -169,9 +185,52 @@ jobs:
169185
working-directory: components/esp_websocket_client/examples
170186
run: |
171187
cp sdkconfig.ci sdkconfig.defaults
172-
pytest --log-cli-level DEBUG --junit-xml=./test_app_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
188+
pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
173189
- uses: actions/upload-artifact@v2
174190
if: always()
175191
with:
176192
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
177-
path: examples/*.xml
193+
path: components/esp_websocket_client/examples/*.xml
194+
195+
run-target-mdns:
196+
strategy:
197+
matrix:
198+
idf_ver: ["latest"]
199+
idf_target: ["esp32"]
200+
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
201+
name: Run mDNS Example Test on target
202+
needs: build_mdns
203+
runs-on:
204+
- self-hosted
205+
- ESP32-ETHERNET-KIT
206+
# Skip running on forks since it won't have access to secrets
207+
if: github.repository == 'espressif/esp-protocols'
208+
steps:
209+
- name: Clear repository
210+
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
211+
- uses: actions/checkout@v3
212+
- uses: actions/download-artifact@v2
213+
with:
214+
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
215+
path: components/mdns/examples/build_${{ matrix.config }}
216+
- name: Install Python packages
217+
env:
218+
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
219+
run: |
220+
sudo apt-get install -y dnsutils
221+
- name: Download Example Test to target ${{ matrix.config }}
222+
run: |
223+
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/mdns/examples/build_${{ matrix.config }}/flash_image.bin
224+
- name: Run Example Test on target ${{ matrix.config }}
225+
working-directory: components/mdns/examples
226+
run: |
227+
rm -rf build
228+
mv build_${{ matrix.config }} build
229+
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
230+
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
231+
rm -rf build sdkconfig.defaults
232+
- uses: actions/upload-artifact@v2
233+
if: always()
234+
with:
235+
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
236+
path: components/mdns/examples/*.xml

components/mdns/examples/pytest.ini

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[pytest]
2+
# only the files with prefix `pytest_` would be recognized as pytest test scripts.
3+
python_files = pytest_*.py
4+
5+
addopts =
6+
-s
7+
--embedded-services esp,idf
8+
-W ignore::_pytest.warning_types.PytestExperimentalApiWarning
9+
--tb short
10+
11+
# ignore DeprecationWarning
12+
filterwarnings =
13+
ignore:Call to deprecated create function (.*)\(\):DeprecationWarning
14+
15+
# log related
16+
log_cli = True
17+
log_cli_level = INFO
18+
log_cli_format = %(asctime)s %(levelname)s %(message)s
19+
log_cli_date_format = %Y-%m-%d %H:%M:%S
20+
21+
log_file = test.log
22+
log_file_level = INFO
23+
log_file_format = %(asctime)s %(levelname)s %(message)s
24+
log_file_date_format = %Y-%m-%d %H:%M:%S

components/mdns/examples/mdns_example_test.py renamed to components/mdns/examples/pytest_mdns.py

Lines changed: 20 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
import struct
66
import subprocess
77
import time
8+
import pytest
89
from threading import Event, Thread
910

1011
import dpkt
1112
import dpkt.dns
12-
import ttfw_idf
13-
from tiny_test_fw import DUT
14-
from tiny_test_fw.Utility import console_log
13+
from pytest_embedded import Dut
14+
import subprocess
1515

1616

1717
def get_dns_query_for_esp(esp_host):
1818
dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
1919
dns.qd[0].name = esp_host + u'.local'
20-
console_log('Created query for esp host: {} '.format(dns.__repr__()))
20+
print('Created query for esp host: {} '.format(dns.__repr__()))
2121
return dns.pack()
2222

2323

@@ -31,7 +31,7 @@ def get_dns_answer_to_mdns(tester_host):
3131
arr.name = tester_host
3232
arr.ip = socket.inet_aton('127.0.0.1')
3333
dns.an.append(arr)
34-
console_log('Created answer to mdns query: {} '.format(dns.__repr__()))
34+
print('Created answer to mdns query: {} '.format(dns.__repr__()))
3535
return dns.pack()
3636

3737

@@ -80,87 +80,58 @@ def mdns_server(esp_host, events):
8080
dns = dpkt.dns.DNS(data)
8181
if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A:
8282
if dns.qd[0].name == TESTER_NAME:
83-
console_log('Received query: {} '.format(dns.__repr__()))
83+
print('Received query: {} '.format(dns.__repr__()))
8484
sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP, UDP_PORT))
8585
elif dns.qd[0].name == TESTER_NAME_LWIP:
86-
console_log('Received query: {} '.format(dns.__repr__()))
86+
print('Received query: {} '.format(dns.__repr__()))
8787
sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr)
8888
if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A:
89-
console_log('Received answer from {}'.format(dns.an[0].name))
89+
print('Received answer from {}'.format(dns.an[0].name))
9090
if dns.an[0].name == esp_host + u'.local':
91-
console_log('Received answer to esp32-mdns query: {}'.format(dns.__repr__()))
91+
print('Received answer to esp32-mdns query: {}'.format(dns.__repr__()))
9292
events['esp_answered'].set()
9393
if dns.an[0].name == esp_host + u'-delegated.local':
94-
console_log('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__()))
94+
print('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__()))
9595
events['esp_delegated_answered'].set()
9696
except socket.timeout:
9797
break
9898
except dpkt.UnpackError:
9999
continue
100100

101101

102-
def test_examples_protocol_mdns(env, config):
102+
def test_examples_protocol_mdns(dut):
103103
"""
104104
steps: |
105105
1. obtain IP address + init mdns example
106106
2. get the dut host name (and IP address)
107107
3. check the mdns name is accessible
108108
4. check DUT output if mdns advertized host is resolved
109109
"""
110-
dut1 = env.get_dut('mdns-test', 'examples/protocols/mdns', dut_class=ttfw_idf.ESP32DUT, app_config_name=config)
111-
# check and log bin size
112-
binary_file = os.path.join(dut1.app.binary_path, 'mdns_test.bin')
113-
bin_size = os.path.getsize(binary_file)
114-
ttfw_idf.log_performance('mdns-test_bin_size', '{}KB'.format(bin_size // 1024))
115-
# 1. start mdns application
116-
dut1.start_app()
117-
# 2. get the dut host name (and IP address)
118-
specific_host = dut1.expect(re.compile(r'mdns hostname set to: \[([^\]]+)\]'), timeout=30)[0]
110+
111+
specific_host = dut.expect(re.compile(b'mdns hostname set to: \[(.*?)\]')).group(1).decode()
119112

120113
mdns_server_events = {'stop': Event(), 'esp_answered': Event(), 'esp_delegated_answered': Event()}
121114
mdns_responder = Thread(target=mdns_server, args=(str(specific_host), mdns_server_events))
115+
ip_address = dut.expect(re.compile(b'IPv4 address:([a-zA-Z0-9]*).*')).group(1).decode()
116+
print('Connected to AP with IP: {}'.format(ip_address))
122117
try:
123-
ip_address = dut1.expect(re.compile(r' eth ip: ([^,]+),'), timeout=30)[0]
124-
console_log('Connected to AP with IP: {}'.format(ip_address))
125-
except DUT.ExpectTimeout:
126-
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
127-
try:
128-
# 3. check the mdns name is accessible
118+
# 3. check the mdns name is accessible.
129119
mdns_responder.start()
130120
if not mdns_server_events['esp_answered'].wait(timeout=30):
131121
raise ValueError('Test has failed: did not receive mdns answer within timeout')
132122
if not mdns_server_events['esp_delegated_answered'].wait(timeout=30):
133123
raise ValueError('Test has failed: did not receive mdns answer for delegated host within timeout')
134124
# 4. check DUT output if mdns advertized host is resolved
135-
dut1.expect(re.compile(r'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30)
136-
dut1.expect(re.compile(r'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
137-
dut1.expect(re.compile(r'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
125+
dut.expect(re.compile(b'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30)
126+
dut.expect(re.compile(b'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
127+
dut.expect(re.compile(b'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
138128
# 5. check the DUT answers to `dig` command
139129
dig_output = subprocess.check_output(['dig', '+short', '-p', '5353', '@224.0.0.251',
140130
'{}.local'.format(specific_host)])
141-
console_log('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output))
131+
print('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output))
142132
if not ip_address.encode('utf-8') in dig_output:
143133
raise ValueError('Test has failed: Incorrectly resolved DUT hostname using dig'
144134
"Output should've contained DUT's IP address:{}".format(ip_address))
145135
finally:
146136
mdns_server_events['stop'].set()
147137
mdns_responder.join()
148-
149-
150-
@ttfw_idf.idf_example_test(env_tag='Example_EthKitV1')
151-
def test_examples_protocol_mdns_default(env, _):
152-
test_examples_protocol_mdns(env, 'eth_def')
153-
154-
155-
@ttfw_idf.idf_example_test(env_tag='Example_EthKitV1')
156-
def test_examples_protocol_mdns_socket(env, _):
157-
test_examples_protocol_mdns(env, 'eth_socket')
158-
159-
160-
@ttfw_idf.idf_example_test(env_tag='Example_EthKitV1')
161-
def test_examples_protocol_mdns_custom_netif(env, _):
162-
test_examples_protocol_mdns(env, 'eth_custom_netif')
163-
164-
165-
if __name__ == '__main__':
166-
test_examples_protocol_mdns_default()

0 commit comments

Comments
 (0)