diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 2292d55..98fdd71 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -69,10 +69,28 @@ "summary": "The current intent as a JSON document.", "schema": { "type": "object", - "required": ["intent", "intentId"], + "required": [ + "intent", + "intentId" + ], "properties": { - "intent": { "type": "string" }, - "intentId": { "type": "integer" } + "intent": { + "type": "object", + "required": ["action"], + "properties": { + "action": { "type": "string" }, + "context": { + "type": "object", + "properties": { + "source": { "type": "string" } + } + } + } + }, + "intentId": { + "type": "integer", + "minimum": 0 + } } } }, @@ -81,7 +99,15 @@ "name": "Get the current intent", "result": { "name": "Default Result", - "value": { "intent": "launch", "intentId": 1 } + "value": { + "intent": { + "action": "pre-load", + "context": { + "source": "system" + } + }, + "intentId": 0 + } } } ] @@ -115,10 +141,28 @@ "summary": "The current intent as a JSON document.", "schema": { "type": "object", - "required": ["intent", "intentId"], + "required": [ + "intent", + "intentId" + ], "properties": { - "intent": { "type": "string" }, - "intentId": { "type": "integer" } + "intent": { + "type": "object", + "required": ["action"], + "properties": { + "action": { "type": "string" }, + "context": { + "type": "object", + "properties": { + "source": { "type": "string" } + } + } + } + }, + "intentId": { + "type": "integer", + "minimum": 0 + } } } }, @@ -133,7 +177,81 @@ ], "result": { "name": "Default Result", - "value": { "intent": "launch", "intentId": 1 } + "value": { + "intent": { + "action": "pre-load", + "context": { + "source": "system" + } + }, + "intentId": 0 + } + } + } + ] + }, + { + "name": "Actions.start", + "summary": "Sends an intent to the platform.", + "tags": [ + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:actions:intent" + ] + } + ], + "params": [ + { + "name": "intent", + "summary": "The intent to send, as a JSON document.", + "required": true, + "schema": { + "type": "object", + "required": ["action"], + "properties": { + "action": { "type": "string" }, + "context": { + "type": "object", + "properties": { + "source": { "type": "string" } + } + } + } + } + }, + { + "name": "handlerAppId", + "summary": "Optional ID of the application that should handle the intent.", + "required": false, + "schema": { + "type": "string" + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + }, + "examples": [ + { + "name": "Start an intent", + "params": [ + { + "name": "intent", + "value": { + "action": "pre-load", + "context": { + "source": "system" + } + } + } + ], + "result": { + "name": "Default Result", + "value": null } } ] @@ -537,39 +655,6 @@ } ] }, - { - "name": "Device.dolbyAtmosExperienceAvailable", - "summary": "Returns whether Dolby Atmos experience is available on the device", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "dolbyAtmosExperienceAvailable", - "summary": "Whether Dolby Atmos experience is available on the device", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Getting Dolby Atmos experience availability", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, { "name": "Discovery.watched", "summary": "Notify the platform that content was partially or completely watched", @@ -690,7 +775,7 @@ }, { "name": "Discovery.watchedV2", - "summary": "Notify the platform that content was partially or completely watched", + "summary": "Notify the platform that content was partially or completely watched, returns whether the notification was accepted", "tags": [ { "name": "polymorphic-reducer" @@ -744,8 +829,9 @@ ], "result": { "name": "result", + "summary": "Whether the platform accepted the watched notification", "schema": { - "type": "null" + "type": "boolean" } }, "examples": [ @@ -771,7 +857,7 @@ ], "result": { "name": "result", - "value": null + "value": true } }, { @@ -800,7 +886,7 @@ ], "result": { "name": "result", - "value": null + "value": true } } ] @@ -1129,39 +1215,6 @@ } ] }, - { - "name": "Localization.timeZone", - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:time-zone" - ] - } - ], - "summary": "Get the IANA timezone of the device.", - "params": [], - "result": { - "name": "timeZone", - "summary": "The device timezone.", - "schema": { - "type": "string" - } - }, - "examples": [ - { - "name": "Default example", - "params": [], - "result": { - "name": "Default Result", - "value": "America/New_York" - } - } - ] - }, { "name": "Metrics.ready", "tags": [ @@ -2303,7 +2356,7 @@ }, { "name": "Stats.memoryUsage", - "summary": "Returns information about container memory usage in bytes.", + "summary": "Returns information about container memory usage, in units of 1024 bytes.", "tags": [ { "name": "capabilities", @@ -2327,10 +2380,10 @@ "name": "value", "description": "The memory usage information", "value": { - "userMemoryUsed": 126418944, - "userMemoryLimit": 807948288, - "gpuMemoryUsed": 353974272, - "gpuMemoryLimit": 922863616 + "userMemoryUsedKiB": 123456, + "userMemoryLimitKiB": 789012, + "gpuMemoryUsedKiB": 345678, + "gpuMemoryLimitKiB": 901234 } } } @@ -3320,52 +3373,6 @@ } } }, - { - "name": "Device.onDolbyAtmosExperienceAvailableChanged", - "summary": "Returns whether Dolby Atmos experience is available on the device", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "tags": [ - { - "name": "event", - "x-notifier": "Device.onDolbyAtmosExperienceAvailableChanged", - "x-subscriber-for": "Device.dolbyAtmosExperienceAvailable" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "examples": [ - { - "name": "Getting Dolby Atmos experience availability", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, { "name": "Localization.onCountryChanged", "tags": [ @@ -3517,52 +3524,6 @@ } } }, - { - "name": "Localization.onTimeZoneChanged", - "tags": [ - { - "name": "event", - "x-notifier": "Localization.onTimeZoneChanged", - "x-subscriber-for": "Localization.timeZone" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:localization:time-zone" - ] - } - ], - "summary": "Get the IANA timezone of the device.", - "params": [ - { - "name": "listen", - "schema": { - "type": "boolean" - } - } - ], - "examples": [ - { - "name": "Default example", - "params": [ - { - "name": "listen", - "value": true - } - ], - "result": { - "name": "result", - "value": null - } - } - ], - "result": { - "name": "result", - "schema": { - "type": "null" - } - } - }, { "name": "Network.onConnectedChanged", "summary": "Returns whether the device currently has a usable network connection.", @@ -3816,32 +3777,28 @@ "type": "object", "description": "Describes current and maximum memory usage of the container.", "properties": { - "userMemoryUsed": { + "userMemoryUsedKiB": { "type": "integer", - "description": "User memory currently used, in bytes.", - "minimum": 0 + "description": "User memory currently used in 1024 bytes." }, - "userMemoryLimit": { + "userMemoryLimitKiB": { "type": "integer", - "description": "Maximum user memory available, in bytes.", - "minimum": 0 + "description": "Maximum user memory available in 1024 bytes." }, - "gpuMemoryUsed": { + "gpuMemoryUsedKiB": { "type": "integer", - "description": "GPU memory currently used, in bytes.", - "minimum": 0 + "description": "GPU memory currently used in 1024 bytes." }, - "gpuMemoryLimit": { + "gpuMemoryLimitKiB": { "type": "integer", - "description": "Maximum GPU memory available, in bytes.", - "minimum": 0 + "description": "Maximum GPU memory available in 1024 bytes." } }, "required": [ - "userMemoryUsed", - "userMemoryLimit", - "gpuMemoryUsed", - "gpuMemoryLimit" + "userMemoryUsedKiB", + "userMemoryLimitKiB", + "gpuMemoryUsedKiB", + "gpuMemoryLimitKiB" ] }, "TTSEnabled": { @@ -4211,4 +4168,4 @@ } } } -} +} \ No newline at end of file diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index 660abd6..dd93d7e 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -26,22 +26,37 @@ #include #include #include -#include #include -#include namespace Firebolt::Actions { +struct IntentContext +{ + std::optional source; +}; + +struct IntentData +{ + std::string action; + std::optional context; +}; + +struct Intent +{ + IntentData intent; + uint32_t intentId{0}; +}; + class IActions { public: virtual ~IActions() = default; - virtual Result intent() const = 0; + virtual Result intent() const = 0; - virtual Result subscribeOnIntent(std::function&& notification) = 0; - virtual Result subscribeOnIntentChanged(std::function&& notification) + virtual Result subscribeOnIntent(std::function&& notification) = 0; + virtual Result subscribeOnIntentChanged(std::function&& notification) { return subscribeOnIntent(std::move(notification)); } @@ -49,6 +64,9 @@ class IActions virtual Result unsubscribe(SubscriptionId id) = 0; virtual void unsubscribeAll() = 0; + virtual Result start(const IntentData& intent, + std::optional handlerAppId = std::nullopt) const = 0; + }; // class IActions } // namespace Firebolt::Actions diff --git a/src/actions_impl.cpp b/src/actions_impl.cpp index e65fc4e..887fb55 100644 --- a/src/actions_impl.cpp +++ b/src/actions_impl.cpp @@ -32,14 +32,29 @@ ActionsImpl::ActionsImpl(Firebolt::Helpers::IHelper& helper) { } -Result ActionsImpl::intent() const +Result ActionsImpl::intent() const { - return helper_.get("Actions.intent"); + return helper_.get("Actions.intent"); } -Result ActionsImpl::subscribeOnIntent(std::function&& notification) +Result ActionsImpl::subscribeOnIntent(std::function&& notification) { - return subscriptionManager_.subscribe("Actions.onIntent", std::move(notification)); + return subscriptionManager_.subscribe("Actions.onIntent", std::move(notification)); +} + +Result ActionsImpl::start(const IntentData& intent, std::optional handlerAppId) const +{ + nlohmann::json params; + params["intent"]["action"] = intent.action; + if (intent.context && intent.context->source) + { + params["intent"]["context"]["source"] = *intent.context->source; + } + if (handlerAppId) + { + params["handlerAppId"] = *handlerAppId; + } + return helper_.invoke("Actions.start", params); } Result ActionsImpl::unsubscribe(SubscriptionId id) diff --git a/src/actions_impl.h b/src/actions_impl.h index 4c8d6ba..523f82d 100644 --- a/src/actions_impl.h +++ b/src/actions_impl.h @@ -36,9 +36,11 @@ class ActionsImpl : public IActions ActionsImpl& operator=(const ActionsImpl&) = delete; ~ActionsImpl() override = default; - Result intent() const override; + Result intent() const override; - Result subscribeOnIntent(std::function&& notification) override; + Result subscribeOnIntent(std::function&& notification) override; + + Result start(const IntentData& intent, std::optional handlerAppId = std::nullopt) const override; Result unsubscribe(SubscriptionId id) override; void unsubscribeAll() override; diff --git a/src/json_types/actions.h b/src/json_types/actions.h index 732775c..4335be8 100644 --- a/src/json_types/actions.h +++ b/src/json_types/actions.h @@ -26,7 +26,7 @@ #include "firebolt/actions.h" #include #include -#include +#include namespace Firebolt::Actions { @@ -34,18 +34,33 @@ namespace Firebolt::Actions namespace JsonData { -// Serialises any JSON value (object, string, …) to its compact JSON text -// representation. Used for Actions.intent / Actions.onIntent whose wire format -// is the object {"intent":"...","intentId":N} but whose public C++ API surface -// exposes the whole document as a std::string, per the Firebolt 9 spec. -class JsonString : public Firebolt::JSON::NL_Json_Basic +// Deserialises the wire object {"intent":{"action":"...","context":{"source":"..."}},"intentId":N} +// into Firebolt::Actions::Intent. nlohmann stays hidden in this impl-layer header. +class JsonValue : public Firebolt::JSON::NL_Json_Basic { public: - void fromJson(const nlohmann::json& json) override { value_ = json.dump(); } - std::string value() const override { return value_; } + void fromJson(const nlohmann::json& json) override + { + value_ = {}; + if (!checkRequiredFields(json, {"intent", "intentId"}) || !json["intent"].is_object() || + !checkRequiredFields(json["intent"], {"action"})) + { + throw std::invalid_argument("Missing required fields in JSON"); + } + value_.intent.action = json["intent"]["action"].get(); + if (json["intent"].contains("context") && json["intent"]["context"].is_object()) + { + IntentContext ctx; + if (json["intent"]["context"].contains("source")) + ctx.source = json["intent"]["context"]["source"].get(); + value_.intent.context = ctx; + } + value_.intentId = json["intentId"].get(); + } + Intent value() const override { return value_; } private: - std::string value_; + Intent value_; }; } // namespace JsonData diff --git a/test/api_test_app/apis/actionsDemo.cpp b/test/api_test_app/apis/actionsDemo.cpp new file mode 100644 index 0000000..bb1fd26 --- /dev/null +++ b/test/api_test_app/apis/actionsDemo.cpp @@ -0,0 +1,108 @@ +/** + * Copyright 2026 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "actionsDemo.h" +#include +#include +#include +#include + +using namespace Firebolt; +using namespace Firebolt::Actions; + +ActionsDemo::ActionsDemo() + : DemoBase("Actions") +{ + methods_.push_back("Actions.intent"); + methods_.push_back("Actions.start"); + methods_.push_back("Actions.onIntent"); + methods_.push_back("Actions.unsubscribe"); + methods_.push_back("Actions.unsubscribeAll"); +} + +void ActionsDemo::runOption(const std::string& method) +{ + std::cout << "Running Actions method: " << method << std::endl; + + if (method == "Actions.intent") + { + auto r = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent(); + if (succeed(r)) + { + std::cout << "Current Intent - action: " << r->intent.action + << ", source: " << (r->intent.context && r->intent.context->source ? *r->intent.context->source : "(none)") + << ", intentId: " << r->intentId << std::endl; + } + } + else if (method == "Actions.start") + { + std::string actionStr = paramFromConsole("action", "pre-load"); + std::string sourceStr = paramFromConsole("context.source (leave empty to skip)", "system"); + std::string handlerAppIdStr = paramFromConsole("handlerAppId (leave empty to skip)", ""); + std::optional handlerAppId; + if (!handlerAppIdStr.empty()) + handlerAppId = handlerAppIdStr; + Firebolt::Actions::IntentData intentData{actionStr}; + if (!sourceStr.empty()) + intentData.context = Firebolt::Actions::IntentContext{sourceStr}; + auto r = Firebolt::IFireboltAccessor::Instance().ActionsInterface().start(intentData, handlerAppId); + if (succeed(r)) + { + std::cout << "Actions.start: Success" << std::endl; + } + } + else if (method == "Actions.onIntent") + { + auto callback = [&](const Intent& payload) + { + std::cout << "Intent received - action: " << payload.intent.action + << ", source: " + << (payload.intent.context && payload.intent.context->source + ? *payload.intent.context->source + : "(none)") + << ", intentId: " << payload.intentId << std::endl; + }; + auto r = Firebolt::IFireboltAccessor::Instance().ActionsInterface().subscribeOnIntent(std::move(callback)); + if (succeed(r)) + { + std::cout << "Subscribed to Actions.onIntent with Subscription ID: " << *r << std::endl; + } + } + else if (method == "Actions.unsubscribe") + { + std::string idStr = paramFromConsole("subscription ID", "0"); + SubscriptionId id = 0; + try + { + id = static_cast(std::stoul(idStr)); + } + catch (const std::exception&) + { + } + auto r = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id); + if (succeed(r)) + { + std::cout << "Unsubscribed from Actions subscription " << id << std::endl; + } + } + else if (method == "Actions.unsubscribeAll") + { + Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribeAll(); + std::cout << "Unsubscribed from all Actions subscriptions" << std::endl; + } +} diff --git a/test/api_test_app/apis/actionsDemo.h b/test/api_test_app/apis/actionsDemo.h new file mode 100644 index 0000000..ae564cc --- /dev/null +++ b/test/api_test_app/apis/actionsDemo.h @@ -0,0 +1,30 @@ +/** + * Copyright 2026 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "utils.h" +#include + +class ActionsDemo : public DemoBase +{ +public: + ActionsDemo(); + ~ActionsDemo() = default; + void runOption(const std::string& method) override; +}; diff --git a/test/api_test_app/apis/lifecycleDemo.cpp b/test/api_test_app/apis/lifecycleDemo.cpp index a550527..f05c133 100644 --- a/test/api_test_app/apis/lifecycleDemo.cpp +++ b/test/api_test_app/apis/lifecycleDemo.cpp @@ -73,15 +73,17 @@ void LifecycleDemo::runOption(const std::string& method) Firebolt::IFireboltAccessor::Instance().LifecycleInterface().subscribeOnStateChanged(std::move(callback)); if (succeed(r)) { + lastSubscriptionId_ = *r; std::cout << "Subscribed to Lifecycle state changes with Subscription ID: " << *r << std::endl; } } else if (method == "Lifecycle2.unsubscribe") { - SubscriptionId id = 0; + SubscriptionId id = lastSubscriptionId_; try { - id = static_cast(std::stoul(paramFromConsole("Subscription ID to unsubscribe", "0"))); + id = static_cast( + std::stoul(paramFromConsole("Subscription ID to unsubscribe", std::to_string(lastSubscriptionId_)))); } catch (const std::exception&) { diff --git a/test/api_test_app/apis/lifecycleDemo.h b/test/api_test_app/apis/lifecycleDemo.h index 9ccf509..d423741 100644 --- a/test/api_test_app/apis/lifecycleDemo.h +++ b/test/api_test_app/apis/lifecycleDemo.h @@ -31,4 +31,5 @@ class LifecycleDemo : public DemoBase private: Firebolt::Lifecycle::LifecycleState currentState_; + Firebolt::SubscriptionId lastSubscriptionId_{0}; }; diff --git a/test/api_test_app/main.cpp b/test/api_test_app/main.cpp index 611cfd7..a6c2f05 100644 --- a/test/api_test_app/main.cpp +++ b/test/api_test_app/main.cpp @@ -17,6 +17,7 @@ */ #include "accessibilityDemo.h" +#include "actionsDemo.h" #include "advertisingDemo.h" #include "deviceDemo.h" #include "discoveryDemo.h" @@ -157,6 +158,7 @@ int main(int argc, char** argv) std::vector> interfaces; interfaces.emplace_back(std::make_unique()); + interfaces.emplace_back(std::make_unique()); interfaces.emplace_back(std::make_unique()); interfaces.emplace_back(std::make_unique()); interfaces.emplace_back(std::make_unique()); diff --git a/test/component/actionsGeneratedTest.cpp b/test/component/actionsGeneratedTest.cpp index a8105c0..a3ce10a 100644 --- a/test/component/actionsGeneratedTest.cpp +++ b/test/component/actionsGeneratedTest.cpp @@ -36,19 +36,23 @@ TEST_F(ActionsGeneratedCTest, Intent) { auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent(); ASSERT_TRUE(result) << toError(result); - auto parsed = nlohmann::json::parse(*result); - EXPECT_EQ(parsed.at("intent").get(), "launch"); - EXPECT_EQ(parsed.at("intentId").get(), 1); + EXPECT_EQ(result->intent.action, "pre-load"); + ASSERT_TRUE(result->intent.context); + ASSERT_TRUE(result->intent.context->source); + EXPECT_EQ(*result->intent.context->source, "system"); + EXPECT_EQ(result->intentId, 0u); } TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) { auto id = Firebolt::IFireboltAccessor::Instance().ActionsInterface().subscribeOnIntent( - [&](const std::string& intent) + [&](const Firebolt::Actions::Intent& payload) { - auto parsed = nlohmann::json::parse(intent); - EXPECT_EQ(parsed.at("intent").get(), "launch"); - EXPECT_EQ(parsed.at("intentId").get(), 1); + EXPECT_EQ(payload.intent.action, "pre-load"); + ASSERT_TRUE(payload.intent.context); + ASSERT_TRUE(payload.intent.context->source); + EXPECT_EQ(*payload.intent.context->source, "system"); + EXPECT_EQ(payload.intentId, 0u); { std::lock_guard lock(mtx); eventReceived = true; @@ -59,9 +63,16 @@ TEST_F(ActionsGeneratedCTest, SubscribeOnIntent) ASSERT_TRUE(id) << toError(id); verifyEventSubscription(id); - triggerEvent("Actions.onIntent", R"({"intent":"launch","intentId":1})"); + triggerEvent("Actions.onIntent", R"({"intent":{"action":"pre-load","context":{"source":"system"}},"intentId":0})"); verifyEventReceived(mtx, cv, eventReceived); auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().unsubscribe(id.value()); verifyUnsubscribeResult(result); } + +TEST_F(ActionsGeneratedCTest, Start) +{ + auto result = Firebolt::IFireboltAccessor::Instance().ActionsInterface().start( + Firebolt::Actions::IntentData{"pre-load", Firebolt::Actions::IntentContext{{"system"}}}); + ASSERT_TRUE(result) << toError(result); +} diff --git a/test/unit/actionsTest.cpp b/test/unit/actionsTest.cpp index feec5ed..236cf91 100644 --- a/test/unit/actionsTest.cpp +++ b/test/unit/actionsTest.cpp @@ -20,21 +20,27 @@ #include "json_engine.h" #include "mock_helper.h" +using ::testing::Invoke; + class ActionsUTest : public ::testing::Test, protected MockBase { protected: Firebolt::Actions::ActionsImpl actionsImpl_{mockHelper}; }; -TEST_F(ActionsUTest, Start) +TEST_F(ActionsUTest, Intent) { - mock_with_response("Actions.intent", nlohmann::json({{"intent", "launch"}, {"intentId", 1}})); + mock_with_response("Actions.intent", + nlohmann::json({{"intent", {{"action", "pre-load"}, {"context", {{"source", "system"}}}}}, + {"intentId", 0u}})); auto result = actionsImpl_.intent(); ASSERT_TRUE(result) << "ActionsImpl::intent() returned an error"; - auto parsed = nlohmann::json::parse(*result); - EXPECT_EQ(parsed.at("intent").get(), "launch"); - EXPECT_EQ(parsed.at("intentId").get(), 1); + EXPECT_EQ(result->intent.action, "pre-load"); + ASSERT_TRUE(result->intent.context); + ASSERT_TRUE(result->intent.context->source); + EXPECT_EQ(*result->intent.context->source, "system"); + EXPECT_EQ(result->intentId, 0u); } TEST_F(ActionsUTest, SubscribeOnIntent) @@ -42,7 +48,7 @@ TEST_F(ActionsUTest, SubscribeOnIntent) nlohmann::json expectedValue = 1; mockSubscribe("Actions.onIntent"); - auto result = actionsImpl_.subscribeOnIntent([&](const std::string& /*value*/) {}); + auto result = actionsImpl_.subscribeOnIntent([&](const Firebolt::Actions::Intent& /*value*/) {}); ASSERT_TRUE(result) << "ActionsImpl::subscribeOnIntent() returned an error"; EXPECT_EQ(*result, expectedValue); @@ -50,3 +56,16 @@ TEST_F(ActionsUTest, SubscribeOnIntent) auto unsubResult = actionsImpl_.unsubscribe(*result); ASSERT_TRUE(unsubResult) << "ActionsImpl::unsubscribe() returned an error"; } + +TEST_F(ActionsUTest, Start) +{ + nlohmann::json expectedParams; + expectedParams["intent"] = {{"action", "pre-load"}, {"context", {{"source", "system"}}}}; + EXPECT_CALL(mockHelper, invoke("Actions.start", expectedParams)) + .WillOnce(Invoke([&](const std::string& /*methodName*/, const nlohmann::json& /*parameters*/) + { return Firebolt::Result{Firebolt::Error::None}; })); + + auto result = actionsImpl_.start( + Firebolt::Actions::IntentData{"pre-load", Firebolt::Actions::IntentContext{{"system"}}}); + ASSERT_TRUE(result) << "ActionsImpl::start() returned an error"; +}