mdns_example_test.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import re
  2. import os
  3. import sys
  4. import socket
  5. import time
  6. import struct
  7. import dpkt
  8. import dpkt.dns
  9. from threading import Thread, Event
  10. # this is a test case write with tiny-test-fw.
  11. # to run test cases outside tiny-test-fw,
  12. # we need to set environment variable `TEST_FW_PATH`,
  13. # then get and insert `TEST_FW_PATH` to sys path before import FW module
  14. try:
  15. import IDF
  16. from IDF.IDFDUT import ESP32DUT
  17. except ImportError:
  18. test_fw_path = os.getenv("TEST_FW_PATH")
  19. if test_fw_path and test_fw_path not in sys.path:
  20. sys.path.insert(0, test_fw_path)
  21. import IDF
  22. import DUT
  23. # g_run_server = True
  24. # g_done = False
  25. stop_mdns_server = Event()
  26. esp_answered = Event()
  27. def get_dns_query_for_esp(esp_host):
  28. dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
  29. dns.qd[0].name = esp_host + u'.local'
  30. print("Created query for esp host: {} ".format(dns.__repr__()))
  31. return dns.pack()
  32. def get_dns_answer_to_mdns(tester_host):
  33. dns = dpkt.dns.DNS(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
  34. dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA
  35. dns.rcode = dpkt.dns.DNS_RCODE_NOERR
  36. arr = dpkt.dns.DNS.RR()
  37. arr.cls = dpkt.dns.DNS_IN
  38. arr.type = dpkt.dns.DNS_A
  39. arr.name = tester_host
  40. arr.ip = socket.inet_aton('127.0.0.1')
  41. dns. an.append(arr)
  42. print("Created answer to mdns query: {} ".format(dns.__repr__()))
  43. return dns.pack()
  44. def get_dns_answer_to_mdns_lwip(tester_host, id):
  45. dns = dpkt.dns.DNS(b"\x5e\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x0a\x64\x61\x76\x69\x64"
  46. b"\x2d\x63\x6f\x6d\x70\x05\x6c\x6f\x63\x61\x6c\x00\x00\x01\x00\x01\xc0\x0c"
  47. b"\x00\x01\x00\x01\x00\x00\x00\x0a\x00\x04\xc0\xa8\x0a\x6c")
  48. dns.qd[0].name = tester_host
  49. dns.an[0].name = tester_host
  50. dns.an[0].ip = socket.inet_aton('127.0.0.1')
  51. dns.an[0].rdata = socket.inet_aton('127.0.0.1')
  52. dns.id = id
  53. print("Created answer to mdns (lwip) query: {} ".format(dns.__repr__()))
  54. return dns.pack()
  55. def mdns_server(esp_host):
  56. global esp_answered
  57. UDP_IP = "0.0.0.0"
  58. UDP_PORT = 5353
  59. MCAST_GRP = '224.0.0.251'
  60. TESTER_NAME = u'tinytester.local'
  61. TESTER_NAME_LWIP = u'tinytester-lwip.local'
  62. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  63. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  64. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  65. sock.bind((UDP_IP,UDP_PORT))
  66. mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
  67. sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
  68. sock.settimeout(30)
  69. while not stop_mdns_server.is_set():
  70. try:
  71. if not esp_answered.is_set():
  72. sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT))
  73. time.sleep(0.2)
  74. data, addr = sock.recvfrom(1024)
  75. dns = dpkt.dns.DNS(data)
  76. if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A:
  77. if dns.qd[0].name == TESTER_NAME:
  78. print("Received query: {} ".format(dns.__repr__()))
  79. sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP,UDP_PORT))
  80. elif dns.qd[0].name == TESTER_NAME_LWIP:
  81. print("Received query: {} ".format(dns.__repr__()))
  82. sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr)
  83. if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A:
  84. if dns.an[0].name == esp_host + u'.local':
  85. print("Received answer to esp32-mdns query: {}".format(dns.__repr__()))
  86. esp_answered.set()
  87. except socket.timeout:
  88. break
  89. except dpkt.UnpackError:
  90. continue
  91. @IDF.idf_example_test(env_tag="Example_WIFI")
  92. def test_examples_protocol_mdns(env, extra_data):
  93. global stop_mdns_server
  94. """
  95. steps: |
  96. 1. join AP + init mdns example
  97. 2. get the dut host name (and IP address)
  98. 3. check the mdns name is accessible
  99. 4. check DUT output if mdns advertized host is resolved
  100. """
  101. dut1 = env.get_dut("mdns-test", "examples/protocols/mdns", dut_class=ESP32DUT)
  102. # check and log bin size
  103. binary_file = os.path.join(dut1.app.binary_path, "mdns-test.bin")
  104. bin_size = os.path.getsize(binary_file)
  105. IDF.log_performance("mdns-test_bin_size", "{}KB".format(bin_size // 1024))
  106. IDF.check_performance("mdns-test_bin_size", bin_size // 1024)
  107. # 1. start mdns application
  108. dut1.start_app()
  109. # 2. get the dut host name (and IP address)
  110. specific_host = dut1.expect(re.compile(r"mdns hostname set to: \[([^\]]+)\]"), timeout=30)
  111. specific_host = str(specific_host[0])
  112. thread1 = Thread(target=mdns_server, args=(specific_host,))
  113. thread1.start()
  114. try:
  115. dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
  116. except DUT.ExpectTimeout:
  117. stop_mdns_server.set()
  118. thread1.join()
  119. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
  120. # 3. check the mdns name is accessible
  121. if not esp_answered.wait(timeout=30):
  122. raise ValueError('Test has failed: did not receive mdns answer within timeout')
  123. # 4. check DUT output if mdns advertized host is resolved
  124. try:
  125. dut1.expect(re.compile(r"mdns-test: Query A: tinytester.local resolved to: 127.0.0.1"), timeout=30)
  126. dut1.expect(re.compile(r"mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1"), timeout=30)
  127. dut1.expect(re.compile(r"mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1"), timeout=30)
  128. finally:
  129. stop_mdns_server.set()
  130. thread1.join()
  131. if __name__ == '__main__':
  132. test_examples_protocol_mdns()