feat(ota): channel-base resolver + arg parser with native tests

(cherry picked from commit 52a4ccc39093891b64e3752316fe7c191fd9b9ca)
This commit is contained in:
Elektr0Vodka authored and agessaman committed 2026-10-03 15:17:36 -07:00
1 parent 47c80fecf3
commit f04d163bea
3 files changed
+113 -1

No files matched your search

+17 -1
View File
@@ -177,7 +177,7 @@ build_flags = -std=c++17
-I src
-I test/mocks
test_build_src = yes
test_ignore = test_kiss_modem
test_ignore = test_kiss_modem, test_ota_channel
build_src_filter =
-<*>
+<../src/Utils.cpp>
@@ -203,3 +203,19 @@ build_src_filter =
lib_deps =
google/googletest @ 1.17.0
bblanchon/ArduinoJson @ 7.4.3
[env:native_ota_channel]
platform = native
test_framework = googletest
build_flags = -std=c++17
-I test/mocks
-I src
-DOTA_MANIFEST_BASE="\"https://stable.example/mqtt/v\""
-DOTA_MANIFEST_BASE_STABLE="\"https://stable.example/mqtt/v\""
-DOTA_MANIFEST_BASE_DEV="\"https://dev.example/mqtt/dev/v\""
test_build_src = yes
test_filter = test_ota_channel
build_src_filter =
-<*>
lib_deps =
google/googletest @ 1.17.0
+62
View File
@@ -0,0 +1,62 @@
#pragma once
#include <stdint.h>
#include <string.h>
// OTA release-channel selector, persisted in NodePrefs::ota_channel.
enum OtaChannel : uint8_t {
OTA_CH_NATIVE = 0, // follow the channel this build was made for
OTA_CH_STABLE = 1,
OTA_CH_DEV = 2,
};
// Resolve the effective manifest base URL for a channel selector.
// build.sh injects the three bases as compile-time macros:
// OTA_MANIFEST_BASE = this build's native channel (defined on every OTA build)
// OTA_MANIFEST_BASE_STABLE = stable channel
// OTA_MANIFEST_BASE_DEV = dev channel
// stable/dev fall back to the native base when their macro is undefined (legacy/local
// builds that only define OTA_MANIFEST_BASE), so this never returns nullptr on an
// OTA-capable build. On a non-OTA build it returns nullptr.
static inline const char* ota_resolve_base(uint8_t channel) {
#if defined(OTA_MANIFEST_BASE)
switch (channel) {
case OTA_CH_STABLE:
#if defined(OTA_MANIFEST_BASE_STABLE)
return OTA_MANIFEST_BASE_STABLE;
#else
return OTA_MANIFEST_BASE;
#endif
case OTA_CH_DEV:
#if defined(OTA_MANIFEST_BASE_DEV)
return OTA_MANIFEST_BASE_DEV;
#else
return OTA_MANIFEST_BASE;
#endif
case OTA_CH_NATIVE:
default:
return OTA_MANIFEST_BASE;
}
#else
(void)channel;
return nullptr;
#endif
}
// Human label for a selector (for the `ota branch` report).
static inline const char* ota_channel_name(uint8_t channel) {
switch (channel) {
case OTA_CH_STABLE: return "stable";
case OTA_CH_DEV: return "dev";
default: return "native";
}
}
// Parse an `ota branch` argument. Returns true and sets *out on a known keyword
// (stable|dev|default; "default" -> native); returns false and leaves *out untouched
// otherwise.
static inline bool ota_parse_channel(const char* arg, uint8_t* out) {
if (strcmp(arg, "stable") == 0) { *out = OTA_CH_STABLE; return true; }
if (strcmp(arg, "dev") == 0) { *out = OTA_CH_DEV; return true; }
if (strcmp(arg, "default") == 0) { *out = OTA_CH_NATIVE; return true; }
return false;
}
@@ -0,0 +1,34 @@
#include <gtest/gtest.h>
#include "helpers/OtaChannel.h"
// The three base URLs are provided as -D macros by the test env (see platformio.ini).
TEST(OtaChannel, ResolvesNativeToBaseMacro) {
EXPECT_STREQ(ota_resolve_base(OTA_CH_NATIVE), "https://stable.example/mqtt/v");
}
TEST(OtaChannel, ResolvesStable) {
EXPECT_STREQ(ota_resolve_base(OTA_CH_STABLE), "https://stable.example/mqtt/v");
}
TEST(OtaChannel, ResolvesDev) {
EXPECT_STREQ(ota_resolve_base(OTA_CH_DEV), "https://dev.example/mqtt/dev/v");
}
TEST(OtaChannel, ParseKnownKeywords) {
uint8_t ch = 99;
EXPECT_TRUE(ota_parse_channel("stable", &ch)); EXPECT_EQ(ch, OTA_CH_STABLE);
EXPECT_TRUE(ota_parse_channel("dev", &ch)); EXPECT_EQ(ch, OTA_CH_DEV);
EXPECT_TRUE(ota_parse_channel("default", &ch)); EXPECT_EQ(ch, OTA_CH_NATIVE);
}
TEST(OtaChannel, ParseRejectsUnknownAndLeavesOutputUntouched) {
uint8_t ch = 7;
EXPECT_FALSE(ota_parse_channel("beta", &ch));
EXPECT_EQ(ch, 7);
}
TEST(OtaChannel, NameLabels) {
EXPECT_STREQ(ota_channel_name(OTA_CH_NATIVE), "native");
EXPECT_STREQ(ota_channel_name(OTA_CH_STABLE), "stable");
EXPECT_STREQ(ota_channel_name(OTA_CH_DEV), "dev");
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}