Skip to content

Commit 8f9242f

Browse files
committed
Add netsocket tests
1 parent 43aa6a2 commit 8f9242f

File tree

16 files changed

+2699
-0
lines changed

16 files changed

+2699
-0
lines changed

TESTS/netsocket/connectivity/main.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "mbed.h"
2+
#include "greentea-client/test_env.h"
3+
#include "unity.h"
4+
#include "utest.h"
5+
#include MBED_CONF_APP_HEADER_FILE
6+
7+
using namespace utest::v1;
8+
9+
// Bringing the network up and down
10+
template <int COUNT>
11+
void test_bring_up_down() {
12+
NetworkInterface* net = MBED_CONF_APP_OBJECT_CONSTRUCTION;
13+
14+
for (int i = 0; i < COUNT; i++) {
15+
int err = MBED_CONF_APP_CONNECT_STATEMENT;
16+
TEST_ASSERT_EQUAL(0, err);
17+
18+
printf("MBED: IP Address %s\r\n", net->get_ip_address());
19+
TEST_ASSERT(net->get_ip_address());
20+
21+
UDPSocket udp;
22+
err = udp.open(net);
23+
TEST_ASSERT_EQUAL(0, err);
24+
err = udp.close();
25+
TEST_ASSERT_EQUAL(0, err);
26+
27+
TCPSocket tcp;
28+
err = tcp.open(net);
29+
TEST_ASSERT_EQUAL(0, err);
30+
err = tcp.close();
31+
TEST_ASSERT_EQUAL(0, err);
32+
33+
err = net->disconnect();
34+
TEST_ASSERT_EQUAL(0, err);
35+
}
36+
}
37+
38+
39+
// Test setup
40+
utest::v1::status_t test_setup(const size_t number_of_cases) {
41+
GREENTEA_SETUP(120, "default_auto");
42+
return verbose_test_setup_handler(number_of_cases);
43+
}
44+
45+
Case cases[] = {
46+
Case("Bringing the network up and down", test_bring_up_down<1>),
47+
Case("Bringing the network up and down twice", test_bring_up_down<2>),
48+
};
49+
50+
Specification specification(test_setup, cases);
51+
52+
int main() {
53+
return !Harness::run(specification);
54+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include "mbed.h"
2+
#include "greentea-client/test_env.h"
3+
#include "unity.h"
4+
#include "utest.h"
5+
#include MBED_CONF_APP_HEADER_FILE
6+
7+
using namespace utest::v1;
8+
9+
// Hostname for testing against
10+
// Must have A and AAAA records
11+
#ifndef MBED_DNS_TEST_HOST
12+
#define MBED_DNS_TEST_HOST "connector.mbed.com"
13+
#endif
14+
15+
16+
// Address info from stack
17+
const char *ip_literal;
18+
nsapi_version_t ip_pref;
19+
const char *ip_pref_repr;
20+
21+
// Network setup
22+
NetworkInterface *net;
23+
24+
void net_bringup() {
25+
net = MBED_CONF_APP_OBJECT_CONSTRUCTION;
26+
int err = MBED_CONF_APP_CONNECT_STATEMENT;
27+
TEST_ASSERT_EQUAL(0, err);
28+
printf("MBED: Connected to network\n");
29+
printf("MBED: IP Address: %s\n", net->get_ip_address());
30+
31+
ip_literal = net->get_ip_address();
32+
ip_pref = SocketAddress(ip_literal).get_ip_version();
33+
ip_pref_repr = (ip_pref == NSAPI_IPv4) ? "ipv4" :
34+
(ip_pref == NSAPI_IPv6) ? "ipv6" : "unspec";
35+
}
36+
37+
38+
// DNS tests
39+
void test_dns_query() {
40+
SocketAddress addr;
41+
int err = net->gethostbyname(MBED_DNS_TEST_HOST, &addr);
42+
printf("DNS: query \"%s\" => \"%s\"\n",
43+
MBED_DNS_TEST_HOST, addr.get_ip_address());
44+
45+
TEST_ASSERT_EQUAL(0, err);
46+
TEST_ASSERT((bool)addr);
47+
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
48+
}
49+
50+
void test_dns_query_pref() {
51+
SocketAddress addr;
52+
int err = net->gethostbyname(MBED_DNS_TEST_HOST, &addr, ip_pref);
53+
printf("DNS: query %s \"%s\" => \"%s\"\n",
54+
ip_pref_repr, MBED_DNS_TEST_HOST, addr.get_ip_address());
55+
56+
TEST_ASSERT_EQUAL(0, err);
57+
TEST_ASSERT((bool)addr);
58+
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
59+
TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version());
60+
}
61+
62+
void test_dns_literal() {
63+
SocketAddress addr;
64+
int err = net->gethostbyname(ip_literal, &addr);
65+
printf("DNS: literal \"%s\" => \"%s\"\n",
66+
ip_literal, addr.get_ip_address());
67+
68+
TEST_ASSERT_EQUAL(0, err);
69+
TEST_ASSERT((bool)addr);
70+
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
71+
TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0);
72+
}
73+
74+
void test_dns_literal_pref() {
75+
SocketAddress addr;
76+
int err = net->gethostbyname(ip_literal, &addr, ip_pref);
77+
printf("DNS: literal %s \"%s\" => \"%s\"\n",
78+
ip_pref_repr, ip_literal, addr.get_ip_address());
79+
80+
TEST_ASSERT_EQUAL(0, err);
81+
TEST_ASSERT((bool)addr);
82+
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
83+
TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version());
84+
TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0);
85+
}
86+
87+
88+
// Test setup
89+
utest::v1::status_t test_setup(const size_t number_of_cases) {
90+
GREENTEA_SETUP(120, "default_auto");
91+
net_bringup();
92+
return verbose_test_setup_handler(number_of_cases);
93+
}
94+
95+
Case cases[] = {
96+
Case("DNS query", test_dns_query),
97+
Case("DNS preference query", test_dns_query_pref),
98+
Case("DNS literal", test_dns_literal),
99+
Case("DNS preference literal", test_dns_literal_pref),
100+
};
101+
102+
Specification specification(test_setup, cases);
103+
104+
int main() {
105+
return !Harness::run(specification);
106+
}
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Copyright 2015 ARM Limited, All rights reserved
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import sys
16+
import select
17+
import socket
18+
import logging
19+
from threading import Thread
20+
from sys import stdout
21+
from SocketServer import BaseRequestHandler, TCPServer
22+
from mbed_host_tests import BaseHostTest, event_callback
23+
24+
25+
class TCPEchoClientHandler(BaseRequestHandler):
26+
def handle(self):
27+
"""
28+
Handles a connection. Test starts by client(i.e. mbed) connecting to server.
29+
This connection handler receives data and echoes back to the client util
30+
{{end}} is received. Then it sits on recv() for client to terminate the
31+
connection.
32+
33+
Note: reason for not echoing data back after receiving {{end}} is that send
34+
fails raising a SocketError as client closes connection.
35+
"""
36+
while self.server.isrunning():
37+
try:
38+
data = self.recv()
39+
if not data: break
40+
except Exception as e:
41+
break
42+
43+
try:
44+
# echo data back to the client
45+
self.send(data)
46+
except Exception as e:
47+
break
48+
49+
def recv(self):
50+
"""
51+
Try to receive until server is shutdown
52+
"""
53+
while self.server.isrunning():
54+
rl, wl, xl = select.select([self.request], [], [], 1)
55+
if len(rl):
56+
return self.request.recv(1024)
57+
58+
def send(self, data):
59+
"""
60+
Try to send until server is shutdown
61+
"""
62+
while self.server.isrunning():
63+
rl, wl, xl = select.select([], [self.request], [], 1)
64+
if len(wl):
65+
self.request.sendall(data)
66+
break
67+
68+
69+
class TCPServerWrapper(TCPServer):
70+
"""
71+
Wrapper over TCP server to implement server initiated shutdown.
72+
Adds a flag:= running that a request handler can check and come out of
73+
recv loop when shutdown is called.
74+
"""
75+
76+
def __init__(self, addr, request_handler):
77+
# hmm, TCPServer is not sub-classed from object!
78+
if issubclass(TCPServer, object):
79+
super(TCPServerWrapper, self).__init__(addr, request_handler)
80+
else:
81+
TCPServer.__init__(self, addr, request_handler)
82+
self.running = False
83+
84+
def serve_forever(self):
85+
self.running = True
86+
if issubclass(TCPServer, object):
87+
super(TCPServerWrapper, self).serve_forever()
88+
else:
89+
TCPServer.serve_forever(self)
90+
91+
def shutdown(self):
92+
self.running = False
93+
if issubclass(TCPServer, object):
94+
super(TCPServerWrapper, self).shutdown()
95+
else:
96+
TCPServer.shutdown(self)
97+
98+
def isrunning(self):
99+
return self.running
100+
101+
102+
class TCPEchoClientTest(BaseHostTest):
103+
104+
def __init__(self):
105+
"""
106+
Initialise test parameters.
107+
108+
:return:
109+
"""
110+
BaseHostTest.__init__(self)
111+
self.SERVER_IP = None # Will be determined after knowing the target IP
112+
self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port
113+
self.server = None
114+
self.server_thread = None
115+
self.target_ip = None
116+
117+
@staticmethod
118+
def find_interface_to_target_addr(target_ip):
119+
"""
120+
Finds IP address of the interface through which it is connected to the target.
121+
122+
:return:
123+
"""
124+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
125+
try:
126+
s.connect((target_ip, 0)) # Target IP, any port
127+
except socket.error:
128+
s.connect((target_ip, 8000)) # Target IP, 'random' port
129+
ip = s.getsockname()[0]
130+
s.close()
131+
return ip
132+
133+
def setup_tcp_server(self):
134+
"""
135+
sets up a TCP server for target to connect and send test data.
136+
137+
:return:
138+
"""
139+
# !NOTE: There should mechanism to assert in the host test
140+
if self.SERVER_IP is None:
141+
self.log("setup_tcp_server() called before determining server IP!")
142+
self.notify_complete(False)
143+
144+
# Returning none will suppress host test from printing success code
145+
self.server = TCPServerWrapper((self.SERVER_IP, self.SERVER_PORT), TCPEchoClientHandler)
146+
ip, port = self.server.server_address
147+
self.SERVER_PORT = port
148+
self.server.allow_reuse_address = True
149+
self.log("HOST: Listening for TCP connections: " + self.SERVER_IP + ":" + str(self.SERVER_PORT))
150+
self.server_thread = Thread(target=TCPEchoClientTest.server_thread_func, args=(self,))
151+
self.server_thread.start()
152+
153+
@staticmethod
154+
def server_thread_func(this):
155+
"""
156+
Thread function to run TCP server forever.
157+
158+
:param this:
159+
:return:
160+
"""
161+
this.server.serve_forever()
162+
163+
@event_callback("target_ip")
164+
def _callback_target_ip(self, key, value, timestamp):
165+
"""
166+
Callback to handle reception of target's IP address.
167+
168+
:param key:
169+
:param value:
170+
:param timestamp:
171+
:return:
172+
"""
173+
self.target_ip = value
174+
self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip)
175+
self.setup_tcp_server()
176+
177+
@event_callback("host_ip")
178+
def _callback_host_ip(self, key, value, timestamp):
179+
"""
180+
Callback for request for host IP Addr
181+
182+
"""
183+
self.send_kv("host_ip", self.SERVER_IP)
184+
185+
@event_callback("host_port")
186+
def _callback_host_port(self, key, value, timestamp):
187+
"""
188+
Callback for request for host port
189+
"""
190+
self.send_kv("host_port", self.SERVER_PORT)
191+
192+
def teardown(self):
193+
if self.server:
194+
self.server.shutdown()
195+
self.server_thread.join()

0 commit comments

Comments
 (0)