| 120 | |
| 121 | private: |
| 122 | void runTest(const char* name, const char* url, |
| 123 | const char* expected, TestSequenceState next_state) { |
| 124 | FL_WARN("[LOOPBACK] Running test: " << name << " -> " << url); |
| 125 | Serial.print("Running test: "); |
| 126 | Serial.println(name); |
| 127 | |
| 128 | tests_run++; |
| 129 | |
| 130 | // Launch async HTTP request with non-blocking .then()/.catch_() callbacks |
| 131 | fl::net::http::fetch_get(url) |
| 132 | .then([this, expected, next_state](const fl::net::http::Response& resp) { |
| 133 | // Success callback - validate response |
| 134 | if (resp.status() == 200 && resp.text() == expected) { |
| 135 | tests_passed++; |
| 136 | Serial.println(" ✓ PASSED"); |
| 137 | } else { |
| 138 | has_failure = true; |
| 139 | Serial.print(" ✗ FAILED - "); |
| 140 | if (resp.status() != 200) { |
| 141 | Serial.print("Status: "); |
| 142 | Serial.print(static_cast<int>(resp.status())); |
| 143 | } else { |
| 144 | Serial.print("Expected: '"); |
| 145 | Serial.print(expected); |
| 146 | Serial.print("', Got: '"); |
| 147 | Serial.print(resp.text().c_str()); |
| 148 | Serial.print("'"); |
| 149 | } |
| 150 | Serial.println(); |
| 151 | } |
| 152 | |
| 153 | // Advance to next test state |
| 154 | state = next_state; |
| 155 | }) |
| 156 | .catch_([this](const fl::task::Error& err) { |
| 157 | // Error callback - network/connection failure |
| 158 | has_failure = true; |
| 159 | Serial.print(" ✗ FAILED - Error: "); |
| 160 | Serial.println(err.message.c_str()); |
| 161 | |
| 162 | // Abort remaining tests on network error |
| 163 | state = COMPLETED; |
| 164 | }); |
| 165 | |
| 166 | // Immediately transition to waiting state (non-blocking) |
| 167 | state = static_cast<TestSequenceState>(state + 1); // RUNNING_X -> WAITING_X |
| 168 | } |
| 169 | |
| 170 | TestSequenceState state; |
| 171 | int tests_run; |