Rick.Brown

API Testing for IoT

Blog Post created by Rick.Brown Employee on Jul 3, 2016

APIs are central to the Internet of Things (IoT). DevTest is an extremely capable API testing tool. Many corporate organisations are already implementing IoT devices, such as set-top boxes (STBs), smart meters, point-of-sale devices, etc, and even more are developing software to run in an IoT infrastructure, like banking apps.

 

Over the past couple of days, I've been looking at my home network with regard to IoT. I didn't think I had much call for management, but I find that my home LAN includes:

2 SKY+HD STBs

3 Roku LT players

3 Nest smoke alarms

Panasonic wifi speakers

     Sound bar, subwoofer & 2 satellite speakers for the lounge TV

     2 speakers in the basement allocated to L and R channels for immersive music

     1 speaker in both of the 1st floor bedrooms

BG Hive hub

     Zigbee master thermostat

     Zigbee boiler & water tank controller

LAN servers

     WD myBookWorld, originally for iTKO backups, but now running a version of Debian Linux

     Amahi home server for DNS, DHCP, network shares, etc

     Proxmox virtualised server platform

          Plex software for networked video

          Logitech Squeeze Server software for networked audio

          My wife's business website server at http://www.ena-marine.co.uk

          Nessus for LAN security

          etc

1 Panasonic wifi landline phone

1 Panasonic smart TV

1 Samsung wifi blu-ray player

1 Epson wifi printer

1 BT Home Hub 5 wifi router

1 Thomson wifi access point (powerline ethernet to wifi router)

1 Nintendo Wii

1 Android tablet

5 Android phones

1 iPhone

1 Windows laptop

2 Mac laptops

1 nettop PC to explore low-power media player software

 

All of this stuff needs monitoring, so I'm wondering whether CA UIM would be useful, or if I would do better completing my evaluation of openHAB which seems to be designed for IoT monitoring, but everything has also been tested and continues to need testing, and I know that the software release cycle for my smoke alarms is different to that of my speakers, because they auto-upgrade at different times.

 

Someone must be testing all the APIs contained in each of the devices. Every device is a server, and every one of them communicates over the LAN, some upstream to b2c servers, some downstream to clients on my LAN. For example, my personal mobile phone includes the Panasonic Smart Phone app to take landline calls, the Plex client to watch my classic Doctor Who collection, the Nest app to alert me when I'm burning dinner again (for details, visit http://cookerydisasters.blogspot.co.uk), the Hive app to turn the heating on because Summer still hasn't arrived (it's JULY already!), and many others.

 

So, as I said, every device is a server. Servers need APIs. What, where and how could an API work for my speakers, for example? Well, I noticed that, when I start the Panasonic music player app on my phone, it forces me to wait for a few seconds before it shows all my speakers. There must be some discovery happening on my network, and network discovery is something that I should be able to accomplish in DevTest, in preparation for querying and updating via standard APIs.

 

LAN discovery is generally accomplished by querying using "Simple Service Discovery Protocol" (ssdp), enhanced by Universal Plug'n'Play (uPnP), using multicast HTTP (HTTP over UDP, not over TCP). UDP is a strange protocol. There's no point in properly performance testing UDP, because servers advertise when they are initially connected and then repeat the advertisement at their expire time. Clients send a discovery query with a timeout, and the functional specification for ssdp says that every server must respond with a message for every service it provides before the timeout period is reached. Network load is directly proportional to the number of services advertised on the LAN multiplied by the number of client requests over time, but because there is no direct connection between clients and servers, there is no way to test dropped messages or to assert on errors. Therefore, it's simply a measure of network traffic, and doesn't need a testing tool.

 

So, what about functional testing? Specifically, how would a query be performed that will provide a response that can be used as a part of a business process? It might be best to show a client discovery request and a response.

 

Request:

M-SEARCH * HTTP/1.1

Host: 239.255.255.250:1900

MX: 5

Man: "ssdp:discover"

ST: ssdp:all

 

Note the blank line at the end of the request.

 

Sample response:

INFO  - NOTIFY * HTTP/1.1

INFO  - Host: 239.255.255.250:1900

INFO  - Cache-Control: max-age=1800

INFO  - Location: http://192.168.1.165:2870/dmr.xml

INFO  - NT: urn:schemas-upnp-org:service:RenderingControl:1

INFO  - NTS: ssdp:alive

INFO  - Server: NFLC/2.3 UPnP/1.0 DLNADOC/1.50

INFO  - USN: uuid:12345678-1234-1234-1234-123456789abc::urn:schemas-upnp-org:service:RenderingControl:1

 

This response provides us some useful information. Interesting things for this specific response might be:

It contains a URL, which we can then use to query the server

It is a RenderingControl, so it's something to do with media

It is DLNA, so it conforms to the Digital Living Network Alliance operability guidelines for media appliances

 

Navigating to the URL provided gives this response:

<root>

     <specVersion>

          <major>1</major>

          <minor>0</minor>

     </specVersion>

     <device>

          <dlna:X_DLNADOC>DMR-1.50</dlna:X_DLNADOC>

          <dlna:X_DLNACAP/>

          <deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>

          <friendlyName>KitchenR</friendlyName>

          <manufacturer>Qualcomm AllPlay</manufacturer>

          <manufacturerURL>http://www.qualcomm.com</manufacturerURL>

          <modelDescription>AllPlay capable network audio module.</modelDescription>

          <modelName>SamAudio</modelName>

          <modelNumber>CUS227 1.0</modelNumber>

     further details snipped

 

So we can see that this is one of my Panasonic speakers; specifically, the one allocated to the right stereo channel in the Kitchen.

 

Ok, so that is an example of the data format, now start doing it in DevTest! So far, I have been looking at this in my spare time this weekend around the sport, and there has been a LOT of sport on TV: Euro2016 football, ODI cricket, Wimbledon, Tour de France, F1 GP, etc, so I have implemented a simple ssdp test step in bean shell, adapted from something I found on the Internet

 

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.DatagramPacket;

import java.net.InetAddress;

import java.net.MulticastSocket;

import java.net.SocketTimeoutException;

 

/**

* UPNP/SSDP client to demonstrate the usage of UDP multicast sockets.

*

* @throws IOException

*/

public void multicast() throws IOException {

    int numberOfResponses = 0;

    try {

        InetAddress multicastAddress = InetAddress.getByName("239.255.255.250");

        // multicast address for SSDP

        final int port = 1900; // standard port for SSDP

        MulticastSocket socket = new MulticastSocket(port);

        socket.setReuseAddress(true);

        socket.setSoTimeout(15000);

        socket.joinGroup(multicastAddress);

 

        // send discover

        byte[] txbuf = DISCOVER_MESSAGE.getBytes("UTF-8");

        DatagramPacket hi = new DatagramPacket(txbuf, txbuf.length,

                multicastAddress, port);

        socket.send(hi);

        _logger.debug("SSDP discover sent");

 

        do {

            byte[] rxbuf = new byte[8192];

            DatagramPacket packet = new DatagramPacket(rxbuf, rxbuf.length);

            socket.receive(packet);

            dumpPacket(packet);

            numberOfResponses++;

        } while (true); // should leave loop by SocketTimeoutException

    } catch (SocketTimeoutException e) {

        _logger.debug("Multicast timed out after {} responses", numberOfResponses);

    }

}

 

private void dumpPacket(DatagramPacket packet) throws IOException {

    InetAddress addr = packet.getAddress();

    _logger.debug("Response from: {}", addr);

    ByteArrayInputStream in = new ByteArrayInputStream(packet.getData(), 0, packet.getLength());

    copyStream(in, System.out);

}

 

private void copyStream(InputStream in, OutputStream out) throws IOException {

    BufferedInputStream bin = new BufferedInputStream(in);

    BufferedOutputStream bout = new BufferedOutputStream(out);

    int c = bin.read();

    while (c != -1) {

        out.write((char) c);

        c = bin.read();

    }

    bout.flush();

}

 

private final static String DISCOVER_MESSAGE

        = "M-SEARCH * HTTP/1.1\r\n"

        + "HOST: 239.255.255.250:1900\r\n"

        + "MAN: \"ssdp:discover\"\r\n"

        + "MX: 5\r\n"

        + "ST: ssdp:all\r\n"

        + "\r\n";

 

multicast();

 

Run this step and it'll spend a good few seconds being unresponsive, but it'll eventually complete with a large amount of logging, showing all (well, perhaps not all - it depends on how well your servers respond to discovery messages) your ssdp & upnp servers on your network.

Outcomes