mirror of
https://github.com/berlin-open-wireless-lab/DAWN.git
synced 2025-02-12 08:41:51 +00:00
test_storage: further refactoring, added test functionality, and TESTING.md to describe testing approach
This commit is contained in:
parent
bd35961de8
commit
292ccb01f2
9 changed files with 513 additions and 117 deletions
111
TESTING.md
Normal file
111
TESTING.md
Normal file
|
@ -0,0 +1,111 @@
|
|||
# Testing
|
||||
[NB: The current content is aspirational. Not fully implemented yet.]
|
||||
|
||||
## Overview
|
||||
|
||||
The core purpose of DAWN is the processing of information relating
|
||||
to the set of access points (AP) and clients (STA - meaning stations in 802.11
|
||||
vernacular) that form the wi-fi network under DAWN's management.
|
||||
|
||||
The required data storage and processing capabilites are generally held in the 'storage'
|
||||
part of DAWN's source code tree. The remaining parts are mainly for
|
||||
interfacing with resources of the AP environment rhat provide updated information and allow
|
||||
DAWN to indicate to stations what they should do next following processing of the latest data.
|
||||
Specifically, this means components such as iwinfo, ubus and uci that are commonly found on an
|
||||
AP running OpenWRT variant of Linux.
|
||||
|
||||
## Testing Approach
|
||||
The principal focus of DAWN's test harness is on these storage and processing components. This is achieved by
|
||||
having a build target named test_storage which builds these parts
|
||||
without the environment interaction dependencies. This "test harness" can then be executed on the
|
||||
build host (e.g. a Linux desktop development environment) or on the target AP.
|
||||
|
||||
To configure the imaginary AP (SUT, or "system under test" in testing parlance)
|
||||
a script that mimics many of the messages from ubus and other sources is created to represent
|
||||
the simulated network by describing APs, connected STAs and DAWN's own configuration parameters.
|
||||
The data evaluation algorithms are then executed, and resultant outputs to stations are simulated as
|
||||
text output.
|
||||
|
||||
For example consider a simple network of two AP with 2 stations. The following (simplifed) script is
|
||||
used to configure what one AP will be aware of:
|
||||
|
||||
CONFIG RSSI=10db
|
||||
SELF 01:01:01:01:01:01
|
||||
AP 02:02:02:02:02:02
|
||||
CONNECT 99:99:99:99:99:99 01:01:01:01:01:01 -78dB
|
||||
HEARING 99:99:99:99:99:99 02:02:02:02:02:02 -65dB
|
||||
CONNECT 88:88:88:88:88:88 01:01:01:01:01:01 -65dB
|
||||
HEARING 88:88:88:88:88:88 02:02:02:02:02:02 -65dB
|
||||
KICK CONSUME
|
||||
KICK
|
||||
|
||||
This means our test AP has the BSSID 01:..., and there is another AP in the network with BSSID 02:....
|
||||
Two stations with MAC 99:... and 88:... are in the network, both connected to AP01:... but also
|
||||
able to see AP02:.... The dB values indicate RSSI levels, and will be evalutated to determine if stations
|
||||
are connected to an appropriate AP. We'ed also configured
|
||||
AP01:... to have an RSSI transition threshold of 10dB. When "kicking evaluation" is performed
|
||||
STA99:... can improve its RSSI by over 10dB by switching to AP02:..., so will be instructed to do so,
|
||||
resulting in the test actions:
|
||||
|
||||
REMOVE 99:99:99:99:99:99 01:01:01:01:01:01
|
||||
CONNECT 99:99:99:99:99:99 02:02:02:02:02:02 -65dB
|
||||
|
||||
Note that this is also valid input to the test_harness, and the parameter CONSUME
|
||||
on the KICK action will cause it to be reinjested for consideration when the
|
||||
second KICK action is evaluated.
|
||||
|
||||
## Types of Testing
|
||||
Three main areas of testing are performed by the supplied test scripts:
|
||||
* Data management: Ensuring data is stored correctly and soes not cause buffer overruns, etc
|
||||
* Algorithm functionality: Review the outcomes of evaluation for somple and complex network data
|
||||
* Scalability: Evaluate the ability of DAWN to sacle linearly to hundreds and thousands of AP and STA
|
||||
|
||||
A number of scenarios are defined for each type of testing, along with scripts to execute them.
|
||||
|
||||
### Data Management Scenarios
|
||||
Data management scenarios excercise DAWN's internal data structures by filling and emptying them to ensure no
|
||||
overflow conditions occur, and where appropriate that sorting is applied correctly. They are independent
|
||||
of any functional testing, so each data structure is excercised alone in a way that would never occur in
|
||||
real usage.
|
||||
|
||||
#### Test DM001: AP list
|
||||
Fill, print, empty and print
|
||||
|
||||
#### Test DM002: Client list
|
||||
Fill, print, empty and print
|
||||
|
||||
#### Test DM001: MAC list
|
||||
Fill, print, empty and print
|
||||
|
||||
#### Test DM001: Hearing list
|
||||
Fill, print, empty and print
|
||||
|
||||
### Algorithm Scenarios
|
||||
Algorithm scenarios are used to ensure that DAWN creates the intended outputs to manage which stations
|
||||
connect to APs. They require more intricate crafting of the scripted synthetic data to represent the
|
||||
input to DAWN's evaluation algortithms to blend situation data with decision metrics.
|
||||
|
||||
#### Test AL001: 2+2 Stable
|
||||
Two AP with two stations connected to AP1, and will remain there.
|
||||
|
||||
#### Test AL002: 2+2 Cross
|
||||
Two AP with two stations connected to AP1, both switching to AP2.
|
||||
|
||||
#### Test AL003: 2+1+1 Cross
|
||||
Two AP with one station connected each, and will cross to the other.
|
||||
|
||||
#### Test AL003: Load balance
|
||||
Three AP with 40 stations connected to AP1, all with same metrics. DAWN should balance load to other APs.
|
||||
|
||||
|
||||
### Scalability Scenarios
|
||||
Scalability scenarios explore how well DAWN can function in environments with many APs and clients.
|
||||
Using commodity equipment this might mean tens of APs with a total of a thousand or so connected stations.
|
||||
Subject to use of appropriate hardware (eg small PC rather than SoC platform) there is an aspiration for
|
||||
DAWN to be stable while managing hundreds of APs each with tens of connected stations, allowing networks
|
||||
to support 10,000 or more concurrent stations.
|
||||
|
||||
Scalability requires a number of design aspects to function together:
|
||||
* Data storage scalability: To allow efficient use of memory the amount required should be approximately linear, so simple networks on small devices require small amounts of memory while more complex environments can function on moderately scaled hardware.
|
||||
* Algorithm scalability: Similar to memory usage, ensuring that calculation times are more linear than exponential as numbers of APs and stations grow.
|
||||
* Algorithm efficiency: As well as being scaleable the processing of data must fit within absolute limits to ensure that APs can keep up with the rate of data arriving from the network.
|
|
@ -175,6 +175,8 @@ void print_probe_entry(probe_entry entry);
|
|||
|
||||
int eval_probe_metric(struct probe_entry_s probe_entry);
|
||||
|
||||
void denied_req_array_insert(auth_entry entry);
|
||||
|
||||
auth_entry denied_req_array_delete(auth_entry entry);
|
||||
|
||||
auth_entry insert_to_denied_req_array(auth_entry entry, int inc_counter);
|
||||
|
|
|
@ -43,8 +43,6 @@ int compare_station_count(uint8_t *bssid_addr_own, uint8_t *bssid_addr_to_compar
|
|||
|
||||
int compare_ssid(uint8_t *bssid_addr_own, uint8_t *bssid_addr_to_compare);
|
||||
|
||||
void denied_req_array_insert(auth_entry entry);
|
||||
|
||||
int denied_req_array_go_next(char sort_order[], int i, auth_entry entry,
|
||||
auth_entry next_entry);
|
||||
|
||||
|
|
5
src/test/ap_auto.script
Normal file
5
src/test/ap_auto.script
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Basic test of array entry handling
|
||||
ap_add_auto 10 20
|
||||
ap_show
|
||||
ap_del_auto 10 20
|
||||
ap_show
|
5
src/test/auth_entry_auto.script
Normal file
5
src/test/auth_entry_auto.script
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Basic test of array entry handling
|
||||
auth_entry_add_auto 10 20
|
||||
auth_entry_show
|
||||
auth_entry_del_auto 10 20
|
||||
auth_entry_show
|
5
src/test/client_auto.script
Normal file
5
src/test/client_auto.script
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Basic test of array entry handling
|
||||
client_add_auto 10 20
|
||||
client_show
|
||||
client_del_auto 10 20
|
||||
client_show
|
6
src/test/probe_auto.script
Normal file
6
src/test/probe_auto.script
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Basic test of array entry handling
|
||||
probe_sort bcfs
|
||||
probe_add_auto 10 20
|
||||
probe_show
|
||||
probe_del_auto 10 20
|
||||
probe_show
|
|
@ -1,6 +1,7 @@
|
|||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dawn_iwinfo.h"
|
||||
#include "utils.h"
|
||||
|
@ -9,126 +10,21 @@
|
|||
#include "datastorage.h"
|
||||
#include "uface.h"
|
||||
|
||||
/*** External functions ***/
|
||||
/*** SUT functions we use that are not in header files (like "friend" functions) ***/
|
||||
void ap_array_insert(ap entry);
|
||||
ap ap_array_delete(ap entry);
|
||||
|
||||
/*** Testing structures, etc ***/
|
||||
union __attribute__((__packed__)) mac_mangler
|
||||
union __attribute__((__packed__)) pac_a_mac
|
||||
{
|
||||
struct {
|
||||
uint8_t b[6];
|
||||
uint8_t pos[6];
|
||||
uint8_t packing[2];
|
||||
} u8;
|
||||
uint64_t u64;
|
||||
};
|
||||
|
||||
/*** Test code */
|
||||
int ap_array_helper_auto(int action, int i0, int i1);
|
||||
int ap_array_helper_auto(int action, int i0, int i1)
|
||||
{
|
||||
int m;
|
||||
int step = (i0 > i1) ? -1 : 1;
|
||||
int ret = 0;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
m = i0;
|
||||
int cont = 1;
|
||||
while (cont) {
|
||||
union mac_mangler this_mac;
|
||||
ap ap0;
|
||||
|
||||
this_mac.u64 = m;
|
||||
memcpy(ap0.bssid_addr, this_mac.u8.b, sizeof(ap0.bssid_addr));
|
||||
if (action == 0)
|
||||
ap_array_insert(ap0);
|
||||
else
|
||||
ap_array_delete(ap0);
|
||||
|
||||
if (m == i1)
|
||||
cont = 0;
|
||||
else
|
||||
m += step;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret = 0;
|
||||
int args_ok = 1;
|
||||
int arg_consumed = 0;
|
||||
|
||||
printf("DAWN datastorage.c test harness. Ready for commands...\n");
|
||||
|
||||
int this_arg = 1;
|
||||
argv++;
|
||||
|
||||
while (args_ok)
|
||||
{
|
||||
if (strcmp(*argv, "help") == 0)
|
||||
{
|
||||
arg_consumed = 1;
|
||||
if (this_arg + arg_consumed > argc) goto next_command;
|
||||
|
||||
printf("Help is on its way...\n");
|
||||
}
|
||||
else if (strcmp(*argv, "ap_show") == 0)
|
||||
{
|
||||
arg_consumed = 1;
|
||||
if (this_arg + arg_consumed > argc) goto next_command;
|
||||
|
||||
print_ap_array();
|
||||
}
|
||||
else if (strcmp(*argv, "ap_add_auto") == 0)
|
||||
{
|
||||
arg_consumed = 3;
|
||||
if (this_arg + arg_consumed > argc) goto next_command;
|
||||
|
||||
ap_array_helper_auto(0, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
else if (strcmp(*argv, "ap_del_auto") == 0)
|
||||
{
|
||||
arg_consumed = 3;
|
||||
if (this_arg + arg_consumed > argc) goto next_command;
|
||||
|
||||
ap_array_helper_auto(1, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
arg_consumed = 1;
|
||||
if (this_arg + arg_consumed > argc) goto next_command;
|
||||
|
||||
printf("COMMAND \"%s\": Unknown - skipping!\n", *argv);
|
||||
}
|
||||
|
||||
next_command:
|
||||
this_arg += arg_consumed;
|
||||
if (this_arg > argc)
|
||||
{
|
||||
printf("Commands are mangled at: \"%s\"!\n", *argv);
|
||||
args_ok = 0;
|
||||
}
|
||||
else if (this_arg == argc)
|
||||
args_ok = 0;
|
||||
else
|
||||
argv += arg_consumed;
|
||||
}
|
||||
|
||||
printf("\n\nDAWN datastorage.c test harness - finshed. \n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*** Test Stub Functions - Called by SUT ***/
|
||||
void ubus_send_beacon_report(uint8_t client[], int id)
|
||||
{
|
||||
printf("send_beacon_report() was called...\n");
|
||||
|
@ -140,7 +36,7 @@ int send_set_probe(uint8_t client_addr[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
void wnm_disassoc_imminent(uint32_t id, const uint8_t *client_addr, char* dest_ap, uint32_t duration)
|
||||
void wnm_disassoc_imminent(uint32_t id, const uint8_t* client_addr, char* dest_ap, uint32_t duration)
|
||||
{
|
||||
printf("wnm_disassoc_imminent() was called...\n");
|
||||
}
|
||||
|
@ -150,7 +46,7 @@ void add_client_update_timer(time_t time)
|
|||
printf("add_client_update_timer() was called...\n");
|
||||
}
|
||||
|
||||
void del_client_interface(uint32_t id, const uint8_t *client_addr, uint32_t reason, uint8_t deauth, uint32_t ban_time)
|
||||
void del_client_interface(uint32_t id, const uint8_t* client_addr, uint32_t reason, uint8_t deauth, uint32_t ban_time)
|
||||
{
|
||||
printf("del_client_interface() was called...\n");
|
||||
}
|
||||
|
@ -161,21 +57,389 @@ int ubus_send_probe_via_network(struct probe_entry_s probe_entry)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int get_rssi_iwinfo(uint8_t *client_addr)
|
||||
int get_rssi_iwinfo(uint8_t* client_addr)
|
||||
{
|
||||
printf("get_rssi_iwinfo() was called...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_expected_throughput_iwinfo(uint8_t *client_addr)
|
||||
int get_expected_throughput_iwinfo(uint8_t* client_addr)
|
||||
{
|
||||
printf("get_expected_throughput_iwinfo() was called...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_bandwidth_iwinfo(uint8_t *client_addr, float *rx_rate, float *tx_rate)
|
||||
int get_bandwidth_iwinfo(uint8_t* client_addr, float* rx_rate, float* tx_rate)
|
||||
{
|
||||
printf("get_bandwidth_iwinfo() was called...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** Local Function Prototypes ***/
|
||||
#define HELPER_ACTION_ADD 0x0000
|
||||
#define HELPER_ACTION_DEL 0x1000
|
||||
#define HELPER_ACTION_MASK 0x1000
|
||||
|
||||
#define HELPER_AP 0x0001
|
||||
#define HELPER_CLIENT 0x0002
|
||||
#define HELPER_AUTH_ENTRY 0x0004
|
||||
#define HELPER_PROBE_ARRAY 0x0008
|
||||
|
||||
int array_auto_helper(int action, int i0, int i1);
|
||||
int client_array_auto_helper(int action, int i0, int i1);
|
||||
int auth_entry_array_auto_helper(int action, int i0, int i1);
|
||||
int probe_array_auto_helper(int action, int i0, int i1);
|
||||
|
||||
/*** Test narness code */
|
||||
int array_auto_helper(int action, int i0, int i1)
|
||||
{
|
||||
int m = i0;
|
||||
int step = (i0 > i1) ? -1 : 1;
|
||||
int ret = 0;
|
||||
|
||||
int cont = 1;
|
||||
while (cont) {
|
||||
union pac_a_mac this_mac;
|
||||
|
||||
this_mac.u64 = m;
|
||||
switch (action & ~HELPER_ACTION_MASK)
|
||||
{
|
||||
case HELPER_AP:
|
||||
; // Empty statement to allow label before declaration
|
||||
ap ap0;
|
||||
memcpy(ap0.bssid_addr, &this_mac.u8.pos[0], sizeof(ap0.bssid_addr));
|
||||
|
||||
if ((action & HELPER_ACTION_MASK) == HELPER_ACTION_ADD)
|
||||
ap_array_insert(ap0);
|
||||
else
|
||||
ap_array_delete(ap0);
|
||||
break;
|
||||
case HELPER_CLIENT:
|
||||
; // Empty statement to allow label before declaration
|
||||
client client0;
|
||||
memcpy(client0.bssid_addr, &this_mac.u8.pos[0], sizeof(client0.bssid_addr));
|
||||
memcpy(client0.client_addr, &this_mac.u8.pos[0], sizeof(client0.client_addr));
|
||||
|
||||
if ((action & HELPER_ACTION_MASK) == HELPER_ACTION_ADD)
|
||||
client_array_insert(client0);
|
||||
else
|
||||
client_array_delete(client0);
|
||||
break;
|
||||
case HELPER_PROBE_ARRAY:
|
||||
; // Empty statement to allow label before declaration
|
||||
probe_entry probe0;
|
||||
memcpy(probe0.bssid_addr, &this_mac.u8.pos[0], sizeof(probe0.bssid_addr));
|
||||
memcpy(probe0.client_addr, &this_mac.u8.pos[0], sizeof(probe0.client_addr));
|
||||
|
||||
if ((action & HELPER_ACTION_MASK) == HELPER_ACTION_ADD)
|
||||
probe_array_insert(probe0);
|
||||
else
|
||||
probe_array_delete(probe0);
|
||||
break;
|
||||
case HELPER_AUTH_ENTRY:
|
||||
; // Empty statement to allow label before declaration
|
||||
auth_entry auth_entry0;
|
||||
memcpy(auth_entry0.bssid_addr, &this_mac.u8.pos[0], sizeof(auth_entry0.bssid_addr));
|
||||
memcpy(auth_entry0.client_addr, &this_mac.u8.pos[0], sizeof(auth_entry0.client_addr));
|
||||
|
||||
if ((action & HELPER_ACTION_MASK) == HELPER_ACTION_ADD)
|
||||
denied_req_array_insert(auth_entry0);
|
||||
else
|
||||
denied_req_array_delete(auth_entry0);
|
||||
break;
|
||||
default:
|
||||
printf("HELPER error - which entity?\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (m == i1)
|
||||
cont = 0;
|
||||
else
|
||||
m += step;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int consume_actions(int argc, char* argv[]);
|
||||
|
||||
int consume_actions(int argc, char* argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
int args_required = 0; // Suppress compiler warming by assigning initial value
|
||||
|
||||
int curr_arg = 0;
|
||||
|
||||
while (curr_arg < argc && ret == 0)
|
||||
{
|
||||
if (strcmp(*argv, "probe_sort") == 0)
|
||||
{
|
||||
args_required = 2;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
strcpy(sort_string, argv[1]);
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "ap_show") == 0)
|
||||
{
|
||||
args_required = 1;
|
||||
|
||||
print_ap_array();
|
||||
}
|
||||
else if (strcmp(*argv, "probe_show") == 0)
|
||||
{
|
||||
args_required = 1;
|
||||
|
||||
print_probe_array();
|
||||
}
|
||||
else if (strcmp(*argv, "client_show") == 0)
|
||||
{
|
||||
args_required = 1;
|
||||
|
||||
print_client_array();
|
||||
}
|
||||
else if (strcmp(*argv, "auth_entry_show") == 0)
|
||||
{
|
||||
args_required = 1;
|
||||
|
||||
printf("--------APs------\n");
|
||||
for (int i = 0; i <= denied_req_last; i++) {
|
||||
print_auth_entry(denied_req_array[i]);
|
||||
}
|
||||
printf("------------------\n");
|
||||
}
|
||||
else if (strcmp(*argv, "ap_add_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_AP | HELPER_ACTION_ADD, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "ap_del_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_AP | HELPER_ACTION_DEL, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "probe_add_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_PROBE_ARRAY | HELPER_ACTION_ADD, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "probe_del_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_PROBE_ARRAY | HELPER_ACTION_DEL, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "client_add_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_CLIENT | HELPER_ACTION_ADD, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "client_del_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_CLIENT | HELPER_ACTION_DEL, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "auth_entry_add_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_AUTH_ENTRY | HELPER_ACTION_ADD, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "auth_entry_del_auto") == 0)
|
||||
{
|
||||
args_required = 3;
|
||||
if (curr_arg + args_required <= argc)
|
||||
{
|
||||
ret = array_auto_helper(HELPER_AUTH_ENTRY | HELPER_ACTION_DEL, atoi(*(argv + 1)), atoi(*(argv + 2)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args_required = 1;
|
||||
|
||||
printf("COMMAND \"%s\": Unknown - stopping!\n", *argv);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
curr_arg += args_required;
|
||||
if (curr_arg <= argc)
|
||||
{
|
||||
// Still need to continue consuming args
|
||||
argv += args_required;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There aren't enough args left to give the parameters of the current action
|
||||
printf("Commands are mangled at: \"%s\"!\n", *argv);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int process_script_line(char* line, size_t len);
|
||||
#define MAX_LINE_ARGS 5
|
||||
int process_script_line(char* line, size_t len)
|
||||
{
|
||||
int argc = 0;
|
||||
char* argv[MAX_LINE_ARGS];
|
||||
bool in_white = true;
|
||||
bool force_blank = false;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
//printf("%lu: \"%s\"\n", len, line);
|
||||
while (len > 0 && !ret)
|
||||
{
|
||||
if (isblank(*line) || (*line == '\n') || (*line == '\r') || (*line == '#') || force_blank)
|
||||
{
|
||||
if (*line == '#')
|
||||
{
|
||||
//printf("Blanking 0x%02X...\n", *line);
|
||||
force_blank = true;
|
||||
}
|
||||
|
||||
//printf("Zapping 0x%02X...\n", *line);
|
||||
*line = '\0';
|
||||
in_white = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (in_white)
|
||||
{
|
||||
//printf("Marking 0x%02X...\n", *line);
|
||||
if (argc == MAX_LINE_ARGS)
|
||||
{
|
||||
printf("ERROR: Script line exceeds permitted arg count!\n");
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
argv[argc] = line;
|
||||
argc++;
|
||||
|
||||
in_white = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len--;
|
||||
line++;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = consume_actions(argc, argv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
FILE* fp;
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t read;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
printf("DAWN datastorage.c test harness...\n\n");
|
||||
|
||||
if ((argc == 1) || !strcmp(*(argv + 1), "help") || !strcmp(*(argv + 1), "--help") || !strcmp(*(argv + 1), "-h"))
|
||||
{
|
||||
printf("Usage: %s [commands]\n\n", *argv);
|
||||
printf(" [action [arg...]]... : Read test actions from command line\n");
|
||||
printf(" --script [file]... : Read test script from file(s) (NB: \"-\" is a valid name\n");
|
||||
printf(" indicating STDIN) {-s}\n");
|
||||
printf(" - : Read test script from STDIN (and remaining arguments\n");
|
||||
printf(" as script file names)\n");
|
||||
printf(" --help : This help message {-h, help}\n");
|
||||
printf("NB: Contents of {braces} indicate equivalent command\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Step past command name on args, ie argv[0]
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (!strcmp(*argv, "--script") || !strcmp(*argv, "-s") || !strcmp(*argv, "-"))
|
||||
{
|
||||
if (!strcmp(*argv, "--script") || !strcmp(*argv, "-s"))
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
// Read script from file[s]
|
||||
while (argc > 0 && ret == 0)
|
||||
{
|
||||
if (!strcmp(*argv, "-"))
|
||||
{
|
||||
fp = stdin;
|
||||
printf("Consuming script from STDIN\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fp = fopen(*argv, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("Error opening script file: %s\n", *argv);
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Consuming script file: %s\n", *argv);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
read = getline(&line, &len, fp);
|
||||
while (!ret && read != -1)
|
||||
{
|
||||
printf("Processing: %s\n", line);
|
||||
ret = process_script_line(line, read);
|
||||
if (!ret)
|
||||
read = getline(&line, &len, fp);
|
||||
}
|
||||
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
|
||||
if (line)
|
||||
free(line);
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take direct input on command line
|
||||
ret = consume_actions(argc, argv);
|
||||
}
|
||||
}
|
||||
printf("\nDAWN datastorage.c test harness - finshed. \n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ int hwaddr_aton(const char *txt, uint8_t *addr) {
|
|||
b = hex_to_bin(*txt++);
|
||||
if (b < 0) return -1;
|
||||
*addr++ = (a << 4) | b;
|
||||
// TODO: Should NUL terminator be checked for? Is aa:bb:cc:dd:ee:ff00 valid input?
|
||||
// TODO: Should NUL terminator be checked for? Is aa:bb:cc:dd:ee:ff00 valid input?
|
||||
if (i < (ETH_ALEN - 1) && *txt++ != ':') return -1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue