Files
MeshCore/test/fixtures/companion_ap_ownership.cpp
T

192 lines
9.0 KiB
C++

#include <cassert>
#include <cstdint>
#include <cstring>
#include <string>
#include "helpers/WiFiReconnectPolicy.h"
#include "helpers/WiFiNetworkPowerPolicy.h"
#define WIFI_DEBUG_PRINTLN(...) ((void)0)
using wifi_mode_t=int;using esp_err_t=int;
constexpr int ESP_OK=0,ESP_FAIL=-1,ESP_ERR_WIFI_NOT_INIT=-2;
constexpr int WIFI_OFF=0,WIFI_STA=1,WIFI_AP=2,WIFI_AP_STA=3,WIFI_MODE_NULL=0,WIFI_MODE_AP=2;
constexpr int WL_CONNECTED=3,WL_DISCONNECTED=0,WIFI_SETUP_FALLBACK_MS=120000;
constexpr const char* COMPANION_WIFI_SETUP_AP="mesh-test";
int sdk_mode=WIFI_STA,query_error=0,mode_writes=0,disconnects=0;
int joins=0,channel_checks=0,reconnect_writes=0,credential_loads=0;
int power_writes=0,socket_starts=0,console_starts=0;
uint32_t now=300001;
uint32_t millis(){return now;}
int esp_wifi_get_mode(wifi_mode_t* mode){if(query_error)return query_error;*mode=sdk_mode;return ESP_OK;}
struct WiFiClass{
int state=WL_DISCONNECTED;
bool mode(int value){++mode_writes;sdk_mode=value;return true;}
int status(){return state;}
void setAutoReconnect(bool){++reconnect_writes;}
void disconnect(bool=false,bool=false){++disconnects;state=WL_DISCONNECTED;}
}WiFi;
namespace mesh{namespace wifi{
@STATION_GUARD@
void setStationAutoReconnect(bool){++reconnect_writes;}
bool enforceStationChannel(){++channel_checks;return true;}
void applyProtocolMask(int){}
void beginStation(const char*,const char*){++joins;}
}}
namespace mesh{namespace wireless{
constexpr int WiFi=1;
struct Control{bool blocked(int){return false;}};
Control& control(){static Control instance;return instance;}
}}
constexpr int WIFI_IF_STA=0;
struct Board{
bool ota=true,inhibit_sleep=false;
bool isOTAUpdateRunning(){return ota;}
void setInhibitSleep(bool enabled){inhibit_sleep=enabled;}
}board;
struct Mesh{
bool setup=false,recovery=false,active=false;
bool isWebConfigSetupActive(){return setup;}
bool isWebConfigWiFiRecoveryActive(){return recovery;}
bool isWebConfigActiveOrStopping(){return active;}
bool startWebConfig(bool,char*){return false;}
void stopWebConfig(){setup=false;}
}the_mesh;
struct WebConfigServer{static bool loadEnabled(bool){return false;}};
struct Portal{
bool active=false;bool isActive(){return active;}
template<class T>bool begin(const char*,T,void*){return false;}
void configureRecovery(const char*,const char*,uint32_t,uint32_t){}
}portal;
Portal& wifiSetupPortal(){return portal;}
void saveCompanionWiFi(){}
char configured_wifi_ssid[8]="mesh",configured_wifi_password[8]="secret";
bool companion_wifi_has_credentials=true,companion_wifi_requested=true,companion_wifi_active=true;
bool companion_wifi_interface_registered=true;
bool companion_wifi_services_stopped=true;
bool companion_wifi_background_stopped=false,companion_wifi_espnow_restore_pending=true;
bool companion_wifi_webconfig_start_pending=false;
bool companion_wifi_credential_reload_pending=true;
unsigned long companion_wifi_credential_reload_at=1;
bool wifi_setup_recovery_mode=false,wifi_setup_attempted=true;
unsigned long last_wifi_setup_attempt=1;
WiFiReconnectPolicy::Tracker wifi_reconnect_tracker;
void loadCompanionWiFiCredentials(){++credential_loads;}
void resetCompanionWiFiRecoveryState(){wifi_reconnect_tracker=WiFiReconnectPolicy::Tracker();}
void applyCompanionWiFiPowerSave(){++power_writes;}
constexpr int TCP_PORT=1234;
struct Interface{
bool begin(int){++socket_starts;return true;}
void enable(){}
bool isListening()const{return socket_starts>0;}
}wifi_interface;
void ota_console_start(){++console_starts;}
@POWER_GUARDS@
#ifdef WITH_WEBCONFIG
@AUTO_WEBCONFIG@
#endif
@RELOAD@
@START_WIFI@
void serviceStation(){
@STATION_LOOP@
}
void assert_untouched(){
assert(sdk_mode&WIFI_AP);assert(mode_writes==0&&disconnects==0&&joins==0);
assert(channel_checks==0&&reconnect_writes==0);
}
int main(int argc,char** argv){
assert(argc==2);const std::string scenario=argv[1];
wifi_reconnect_tracker.noteDisconnected(1);wifi_reconnect_tracker.noteAttempt(1);
if(scenario=="retry"){
for(int mode:{WIFI_AP,WIFI_AP_STA}){
sdk_mode=mode;serviceStation();assert_untouched();
assert(wifi_reconnect_tracker.retryDue(now));
}
query_error=ESP_FAIL;serviceStation();assert_untouched();query_error=0;
sdk_mode=WIFI_STA;board.ota=false;serviceStation();
assert(sdk_mode==WIFI_STA&&mode_writes==1&&disconnects==1&&joins==1);
assert(!wifi_reconnect_tracker.retryDue(now));
}else if(scenario=="reload"){
for(int mode:{WIFI_AP,WIFI_AP_STA}){
sdk_mode=mode;serviceCompanionWiFiCredentialReload();assert_untouched();
assert(companion_wifi_credential_reload_pending&&companion_wifi_credential_reload_at==1);
assert(credential_loads==0);
}
query_error=ESP_FAIL;serviceCompanionWiFiCredentialReload();assert_untouched();query_error=0;
sdk_mode=WIFI_STA;board.ota=false;serviceCompanionWiFiCredentialReload();
assert(!companion_wifi_credential_reload_pending&&companion_wifi_credential_reload_at==0);
assert(credential_loads==1&&mode_writes==1&&disconnects==1&&joins==1);
}else if(scenario=="setup_handoff"){
#ifdef WITH_WEBCONFIG
sdk_mode=WIFI_AP_STA;board.ota=false;the_mesh.setup=the_mesh.recovery=true;
serviceStation();assert(sdk_mode==WIFI_AP_STA&&mode_writes==0&&joins==1&&disconnects==1);
// Even a stale WebConfig setup flag must not authorize changes to an OTA AP.
board.ota=true;mode_writes=joins=disconnects=channel_checks=reconnect_writes=0;
wifi_reconnect_tracker=WiFiReconnectPolicy::Tracker();
wifi_reconnect_tracker.noteDisconnected(1);wifi_reconnect_tracker.noteAttempt(1);
serviceStation();assert_untouched();
#else
sdk_mode=WIFI_AP_STA;board.ota=false;portal.active=true;serviceStation();
assert(sdk_mode==WIFI_AP_STA&&mode_writes==0&&joins==0&&disconnects==0);
#endif
}else if(scenario=="unrelated_setup"){
sdk_mode=WIFI_AP_STA;board.ota=false;the_mesh.setup=true;the_mesh.recovery=false;
serviceStation();assert_untouched();
}else if(scenario=="start_wifi"){
companion_wifi_active=false;
for(int mode:{WIFI_AP,WIFI_AP_STA}){
sdk_mode=mode;startCompanionWiFi();assert_untouched();
assert(!companion_wifi_active&&companion_wifi_requested&&companion_wifi_services_stopped);
assert(socket_starts==0&&console_starts==0&&power_writes==0&&!board.inhibit_sleep);
}
query_error=ESP_FAIL;startCompanionWiFi();assert_untouched();query_error=0;
sdk_mode=WIFI_STA;board.ota=false;startCompanionWiFi();
assert(companion_wifi_active&&!companion_wifi_services_stopped&&board.inhibit_sleep);
assert(mode_writes==1&&joins==1&&socket_starts==1&&console_starts==1&&power_writes==1);
startCompanionWiFi();assert(mode_writes==1&&socket_starts==1);
}else if(scenario=="registration"){
companion_wifi_interface_registered=false;
companion_wifi_active=false;board.ota=false;sdk_mode=WIFI_STA;
startCompanionWiFi();
assert(companion_wifi_active&&board.inhibit_sleep&&!companion_wifi_services_stopped);
assert(socket_starts==0&&console_starts==1&&joins==1);
}else if(scenario=="suspended"){
auto& power=mesh::wifi::networkPower();
power.setManaged(true);power.setSuspended(true);
board.ota=false;companion_wifi_active=false;sdk_mode=WIFI_STA;
serviceCompanionWiFiCredentialReload();startCompanionWiFi();
assert(mode_writes==0&&disconnects==0&&joins==0&&credential_loads==0);
assert(companion_wifi_credential_reload_pending&&companion_wifi_credential_reload_at==1);
assert(!companion_wifi_active&&companion_wifi_requested&&companion_wifi_services_stopped);
assert(companion_wifi_espnow_restore_pending);
assert(socket_starts==0&&console_starts==0&&power_writes==0&&!board.inhibit_sleep);
assert(!companionWiFiAutomaticRecoveryAllowed());
// A fresh foreground hold admits startup, but only after AP teardown.
power.setHold(mesh::wifi::NetworkPowerHold::CompanionClient,true);
startCompanionWiFi();
assert(companion_wifi_active&&!companion_wifi_services_stopped&&board.inhibit_sleep);
assert(mode_writes==1&&joins==1&&socket_starts==1&&console_starts==1&&power_writes==1);
assert(!companion_wifi_espnow_restore_pending);
serviceCompanionWiFiCredentialReload();
assert(!companion_wifi_credential_reload_pending&&companion_wifi_credential_reload_at==0);
assert(credential_loads==1&&mode_writes==2&&disconnects==1&&joins==2);
power.setHold(mesh::wifi::NetworkPowerHold::CompanionClient,false);
power.setManaged(false);
assert(companionWiFiAutomaticRecoveryAllowed()&&!companionWiFiBackgroundSuspended());
}else if(scenario=="suspended_ap"){
auto& power=mesh::wifi::networkPower();
power.setManaged(true);power.setSuspended(true);
companion_wifi_active=false;
for(bool ota:{false,true}){
board.ota=ota;
power.setHold(mesh::wifi::NetworkPowerHold::WebConfig,!ota);
assert(!companionWiFiBackgroundSuspended());
for(int mode:{WIFI_AP,WIFI_AP_STA}){
sdk_mode=mode;serviceCompanionWiFiCredentialReload();startCompanionWiFi();
assert_untouched();
assert(companion_wifi_credential_reload_pending&&companion_wifi_credential_reload_at==1);
assert(companion_wifi_espnow_restore_pending&&credential_loads==0);
assert(!companion_wifi_active&&companion_wifi_requested&&companion_wifi_services_stopped);
assert(socket_starts==0&&console_starts==0&&power_writes==0&&!board.inhibit_sleep);
}
}
}else assert(false);
}