diff --git a/src/entryPoints/HttpRoutes.cpp b/src/entryPoints/HttpRoutes.cpp index bac969e..14f1bac 100644 --- a/src/entryPoints/HttpRoutes.cpp +++ b/src/entryPoints/HttpRoutes.cpp @@ -118,6 +118,13 @@ void registerHttpRoutes(AsyncWebServer &server) { ESP_LOGD(TAG, "No restore options sent. Using defaults..."); opts.shades = true; } + // Otherwise the device would reboot having restored nothing. + const uint8_t parts = restoreParts(opts); + if(parts == 0) { + LittleFS.remove("/shades.tmp"); + request->send(400, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No part of the backup was chosen, so nothing was restored.\"}")); + return; + } // Checked here so the client hears about a bad file. It only reads // the file; the shades are still changed on loop() alone. if(!ShadeConfigFile::validateFile("/shades.tmp")) { @@ -129,7 +136,7 @@ void registerHttpRoutes(AsyncWebServer &server) { // codes, and then reboots. loop_item_t item; item.type = loop_item_type_t::restore_shades; - item.restoreParts = restoreParts(opts); + item.restoreParts = parts; if(!queueLoopItem(request, item)) return; request->send(200, _encoding_json, "{\"status\":\"Success\",\"desc\":\"Restoring Shade settings\"}"); } diff --git a/test/e2e/test_restore.py b/test/e2e/test_restore.py index e4b1e25..96593b7 100644 --- a/test/e2e/test_restore.py +++ b/test/e2e/test_restore.py @@ -28,6 +28,14 @@ def test_restore_reads_the_options_sent_as_a_form_field(host, token): assert json.loads(body)["desc"] == "JSON parse error" +def test_a_restore_with_no_part_chosen_is_refused(host, token): + """Checked before the file, so this file, which isn't a backup, restores nothing either way.""" + options = json.dumps({"shades": False}) + status, _, body = upload(host, "/restore", auth(token), fields={"data": options}) + assert status == 400, body + assert json.loads(body)["desc"] == "No part of the backup was chosen, so nothing was restored." + + def test_a_refused_restore_leaves_no_upload_behind(host, token): """A later /restore without a file must not find the refused one's upload.""" status, _, _ = upload(host, "/restore", auth(token), fields={"data": "{"})