From 99edf7b3844e621135d9b7ed147fde9195219f30 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Wed, 10 Jun 2026 14:02:06 -0400 Subject: [PATCH 1/2] RDKEMW-17483 : Add Discovery.watchedV2 alongside Discovery.watched with same logic --- docs/openrpc/openrpc/discovery.json | 118 +++++++++++++++++++ docs/openrpc/the-spec/firebolt-open-rpc.json | 118 +++++++++++++++++++ include/firebolt/discovery.h | 18 +++ src/discovery_impl.cpp | 26 ++++ src/discovery_impl.h | 4 + test/api_test_app/apis/discoveryDemo.cpp | 26 ++++ test/component/discoveryTest.cpp | 8 ++ test/unit/discoveryTest.cpp | 39 ++++++ 8 files changed, 357 insertions(+) diff --git a/docs/openrpc/openrpc/discovery.json b/docs/openrpc/openrpc/discovery.json index 8862606..6f80f61 100644 --- a/docs/openrpc/openrpc/discovery.json +++ b/docs/openrpc/openrpc/discovery.json @@ -122,6 +122,124 @@ } } ] + }, + { + "name": "watchedV2", + "summary": "Notify the platform that content was partially or completely watched, returns whether the notification was accepted", + "tags": [ + { + "name": "polymorphic-reducer" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:discovery:watched" + ] + } + ], + "params": [ + { + "name": "entityId", + "required": true, + "schema": { + "type": "string" + }, + "summary": "The entity Id of the watched content." + }, + { + "name": "progress", + "summary": "How much of the content has been watched (percentage as (0-0.999) for VOD, number of seconds for live)", + "schema": { + "type": "number", + "minimum": 0 + } + }, + { + "name": "completed", + "summary": "Whether or not this viewing is considered \"complete,\" per the app's definition thereof", + "schema": { + "type": "boolean" + } + }, + { + "name": "watchedOn", + "summary": "Date/Time the content was watched, ISO 8601 Date/Time", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "agePolicy", + "description": "The age policy associated with the watch event. The age policy describes the age groups to which content may be directed.", + "schema": { + "$ref": "https://meta.comcast.com/firebolt/policies#/definitions/AgePolicy" + } + } + ], + "result": { + "name": "result", + "summary": "Whether the platform accepted the watched notification", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Notify the platform of watched content (v2)", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + } + ], + "result": { + "name": "result", + "value": true + } + }, + { + "name": "Notify the platform that child-directed content was watched (v2)", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + }, + { + "name": "agePolicy", + "value": "app:child" + } + ], + "result": { + "name": "result", + "value": true + } + } + ] } ] } diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 9ad9084..1315678 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -644,6 +644,124 @@ } ] }, + { + "name": "Discovery.watchedV2", + "summary": "Notify the platform that content was partially or completely watched, returns whether the notification was accepted", + "tags": [ + { + "name": "polymorphic-reducer" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:discovery:watched" + ] + } + ], + "params": [ + { + "name": "entityId", + "required": true, + "schema": { + "type": "string" + }, + "summary": "The entity Id of the watched content." + }, + { + "name": "progress", + "summary": "How much of the content has been watched (percentage as (0-0.999) for VOD, number of seconds for live)", + "schema": { + "type": "number", + "minimum": 0 + } + }, + { + "name": "completed", + "summary": "Whether or not this viewing is considered \"complete,\" per the app's definition thereof", + "schema": { + "type": "boolean" + } + }, + { + "name": "watchedOn", + "summary": "Date/Time the content was watched, ISO 8601 Date/Time", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "agePolicy", + "description": "The age policy associated with the watch event. The age policy describes the age groups to which content may be directed.", + "schema": { + "$ref": "#/x-schemas/Policies/AgePolicy" + } + } + ], + "result": { + "name": "result", + "summary": "Whether the platform accepted the watched notification", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Notify the platform of watched content (v2)", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + } + ], + "result": { + "name": "result", + "value": true + } + }, + { + "name": "Notify the platform that child-directed content was watched (v2)", + "params": [ + { + "name": "entityId", + "value": "partner.com/entity/123" + }, + { + "name": "progress", + "value": 0.95 + }, + { + "name": "completed", + "value": true + }, + { + "name": "watchedOn", + "value": "2021-04-23T18:25:43.511Z" + }, + { + "name": "agePolicy", + "value": "app:child" + } + ], + "result": { + "name": "result", + "value": true + } + } + ] + }, { "name": "Display.edid", "summary": "Returns the EDID (and extensions) of the connected or integral display, as a Base64 encoded string", diff --git a/include/firebolt/discovery.h b/include/firebolt/discovery.h index 885380e..894a768 100644 --- a/include/firebolt/discovery.h +++ b/include/firebolt/discovery.h @@ -44,5 +44,23 @@ class IDiscovery virtual Result watched(const std::string& entityId, std::optional progress, std::optional completed, std::optional watchedOn, std::optional agePolicy) const = 0; + + /** + * @brief Notify the platform that content was partially or completely watched, returns whether the notification + * was accepted + * + * @param[in] entityId : The entity Id of the watched content + * @param[in] progress : How much of the content has been watched (percentage as (0-0.999) for VOD, number of + * seconds for live) + * @param[in] completed : Whether or not this viewing is considered "complete" per the app's definition thereof + * @param[in] watchedOn : The ISO 8601 timestamp of when the content was watched + * @param[in] agePolicy : The age policy associated with the watch event. The age policy describes the age groups + * to which content may be directed + * + * @retval Whether the platform accepted the watched notification, or an error + */ + virtual Result watchedV2(const std::string& entityId, std::optional progress, + std::optional completed, std::optional watchedOn, + std::optional agePolicy) const = 0; }; } // namespace Firebolt::Discovery diff --git a/src/discovery_impl.cpp b/src/discovery_impl.cpp index e653777..3504399 100644 --- a/src/discovery_impl.cpp +++ b/src/discovery_impl.cpp @@ -52,4 +52,30 @@ Result DiscoveryImpl::watched(const std::string& entityId, std::optional DiscoveryImpl::watchedV2(const std::string& entityId, std::optional progress, + std::optional completed, std::optional watchedOn, + std::optional agePolicy) const +{ + nlohmann::json parameters; + parameters["entityId"] = entityId; + if (progress) + { + parameters["progress"] = *progress; + } + if (completed) + { + parameters["completed"] = *completed; + } + if (watchedOn) + { + parameters["watchedOn"] = *watchedOn; + } + if (agePolicy) + { + parameters["agePolicy"] = Firebolt::JSON::toString(Firebolt::JsonData::AgePolicyEnum, *agePolicy); + } + + return helper_.get("Discovery.watchedV2", parameters); +} } // namespace Firebolt::Discovery diff --git a/src/discovery_impl.h b/src/discovery_impl.h index 34e12f1..96b2d70 100644 --- a/src/discovery_impl.h +++ b/src/discovery_impl.h @@ -37,6 +37,10 @@ class DiscoveryImpl : public IDiscovery std::optional watchedOn, std::optional agePolicy) const override; + Result watchedV2(const std::string& entityId, std::optional progress, std::optional completed, + std::optional watchedOn, + std::optional agePolicy) const override; + private: Firebolt::Helpers::IHelper& helper_; }; diff --git a/test/api_test_app/apis/discoveryDemo.cpp b/test/api_test_app/apis/discoveryDemo.cpp index 5e0b9d6..98b199a 100644 --- a/test/api_test_app/apis/discoveryDemo.cpp +++ b/test/api_test_app/apis/discoveryDemo.cpp @@ -33,6 +33,7 @@ DiscoveryDemo::DiscoveryDemo() : DemoBase("Discovery") { methods_.push_back("Discovery.watched"); + methods_.push_back("Discovery.watchedV2"); } void DiscoveryDemo::runOption(const std::string& method) @@ -64,4 +65,29 @@ void DiscoveryDemo::runOption(const std::string& method) std::cout << "Discovery.watched: Success" << std::endl; } } + else if (method == "Discovery.watchedV2") + { + std::string entityId = paramFromConsole("entityId", "exampleEntityId"); + std::optional progress = 0.5; + try + { + progress = std::stod( + paramFromConsole("progress (percentage as (0-0.999) for VOD, number of seconds for live)", "0.5")); + } + catch (const std::exception&) + { + } + std::optional completed = paramFromConsole("completed (true/false)", "false") == "true"; + std::string watchedOn = paramFromConsole("watchedOn (ISO 8601 timestamp)", "2024-01-01T00:00:00Z"); + + std::optional agePolicyOpt = + chooseEnumFromList(Firebolt::JsonData::AgePolicyEnum, "Choose an age policy for the watch event:"); + + auto r = Firebolt::IFireboltAccessor::Instance().DiscoveryInterface().watchedV2(entityId, progress, completed, + watchedOn, agePolicyOpt); + if (succeed(r)) + { + std::cout << "Discovery.watchedV2: " << (*r ? "true" : "false") << std::endl; + } + } } diff --git a/test/component/discoveryTest.cpp b/test/component/discoveryTest.cpp index c1cfcf1..b95da12 100644 --- a/test/component/discoveryTest.cpp +++ b/test/component/discoveryTest.cpp @@ -31,3 +31,11 @@ TEST_F(DiscoveryCTest, Watched) Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "Failed to call watched"; } + +TEST_F(DiscoveryCTest, WatchedV2) +{ + auto result = Firebolt::IFireboltAccessor::Instance().DiscoveryInterface().watchedV2("entity123", 0.75f, true, + "2024-10-01T12:00:00Z", + Firebolt::AgePolicy::ADULT); + ASSERT_TRUE(result) << "Failed to call watchedV2"; +} diff --git a/test/unit/discoveryTest.cpp b/test/unit/discoveryTest.cpp index 9b7b1b1..46fb672 100644 --- a/test/unit/discoveryTest.cpp +++ b/test/unit/discoveryTest.cpp @@ -70,3 +70,42 @@ TEST_F(DiscoveryUTest, watched_payload) auto result = discoveryImpl_.watched(entityId, progress, completed, watchedOn, agePolicy); ASSERT_TRUE(result) << "Error on watched"; } + +TEST_F(DiscoveryUTest, watchedV2) +{ + mock("Discovery.watchedV2"); + std::string entityId = "content123"; + std::optional progress = 0.75f; + std::optional completed = true; + std::optional watchedOn = "2024-06-01T12:00:00Z"; + std::optional agePolicy = Firebolt::AgePolicy::ADULT; + auto result = discoveryImpl_.watchedV2(entityId, progress, completed, watchedOn, agePolicy); + ASSERT_TRUE(result) << "Error on watchedV2"; + EXPECT_TRUE(*result); +} + +TEST_F(DiscoveryUTest, watchedV2_payload) +{ + nlohmann::json expected; + expected["entityId"] = "content123"; + expected["progress"] = 0.75f; + expected["completed"] = true; + expected["watchedOn"] = "2024-06-01T12:00:00Z"; + expected["agePolicy"] = "app:adult"; + EXPECT_CALL(mockHelper, getJson("Discovery.watchedV2", _)) + .WillOnce(Invoke( + [&](const std::string& /* methodName */, const nlohmann::json& parameters) + { + EXPECT_EQ(parameters, expected) << "Parameters do not match expected payload: " << expected.dump() + << " but got: " << parameters.dump(); + return Firebolt::Result{nlohmann::json(true)}; + })); + std::string entityId = "content123"; + std::optional progress = 0.75f; + std::optional completed = true; + std::optional watchedOn = "2024-06-01T12:00:00Z"; + std::optional agePolicy = Firebolt::AgePolicy::ADULT; + auto result = discoveryImpl_.watchedV2(entityId, progress, completed, watchedOn, agePolicy); + ASSERT_TRUE(result) << "Error on watchedV2"; + EXPECT_TRUE(*result); +} From a7770e8b02e0254dd1670148473266df1b6368bf Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Wed, 10 Jun 2026 14:41:56 -0400 Subject: [PATCH 2/2] RDKEMW-17483 : Fix component test for discovery.watchedV2 --- test/component/discoveryTest.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/component/discoveryTest.cpp b/test/component/discoveryTest.cpp index b95da12..e0ae6f5 100644 --- a/test/component/discoveryTest.cpp +++ b/test/component/discoveryTest.cpp @@ -18,10 +18,13 @@ #include "firebolt/discovery.h" #include "firebolt/firebolt.h" +#include "json_engine.h" #include class DiscoveryCTest : public ::testing::Test { +protected: + JsonEngine jsonEngine; }; TEST_F(DiscoveryCTest, Watched) @@ -34,8 +37,10 @@ TEST_F(DiscoveryCTest, Watched) TEST_F(DiscoveryCTest, WatchedV2) { + auto expectedValue = jsonEngine.get_value("Discovery.watchedV2"); auto result = Firebolt::IFireboltAccessor::Instance().DiscoveryInterface().watchedV2("entity123", 0.75f, true, "2024-10-01T12:00:00Z", Firebolt::AgePolicy::ADULT); ASSERT_TRUE(result) << "Failed to call watchedV2"; + EXPECT_EQ(*result, expectedValue.get()); }