Skip to content

Commit

Permalink
DGAPI: Blink changes for DGAPI v2.1
Browse files Browse the repository at this point in the history
- Behind DigitalGoodsV2_1 runtime feature flag
- add ListPurchaseHistory method
- add to ItemDetails:
  - ItemType type
  - sequence<DOMString> iconUrls
  - unsigned short introductoryPriceCycles
- Corresponding unit tests and WPT tests
- IWYU in digital_goods_service & digital_goods_type_converters

I2P for blink changes:
https://groups.google.com/a/chromium.org/g/blink-dev/c/JaNDPCUr1ws/m/JFt-E7ePAQAJ

Bug: 1250604
Change-Id: Ia621ec6fc004ca251135fb053715db13253bd42e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3288243
Reviewed-by: Dominick Ng <dominickn@chromium.org>
Reviewed-by: Nico Weber <thakis@chromium.org>
Commit-Queue: Glen Robertson <glenrob@chromium.org>
Cr-Commit-Position: refs/heads/main@{#983617}
  • Loading branch information
Glen Robertson authored and Chromium LUCI CQ committed Mar 22, 2022
1 parent 1fdafa6 commit 5028e3e
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 12 deletions.
2 changes: 2 additions & 0 deletions third_party/blink/renderer/bindings/generated_in_modules.gni
Expand Up @@ -1184,6 +1184,8 @@ generated_enumeration_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_idb_transaction_mode.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_smoothing_quality.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_smoothing_quality.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_item_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_item_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_landmark_type.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_landmark_type.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_latency_mode.cc",
Expand Down
Expand Up @@ -2,22 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <type_traits>
#include <utility>

#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "base/check.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/struct_ptr.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink-forward.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_item_details.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_purchase_details.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/payments/goods/digital_goods_service.h"
#include "third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/to_v8.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {

class ItemDetails;
class PurchaseDetails;

using payments::mojom::blink::BillingResponseCode;

namespace {
Expand All @@ -42,7 +54,7 @@ void OnGetDetailsResponse(
resolver->Resolve(std::move(blink_item_details_list));
}

void OnListPurchasesResponse(
void ResolveWithPurchaseReferenceList(
ScriptPromiseResolver* resolver,
BillingResponseCode code,
Vector<payments::mojom::blink::PurchaseReferencePtr>
Expand Down Expand Up @@ -106,7 +118,17 @@ ScriptPromise DigitalGoodsService::listPurchases(ScriptState* script_state) {
ScriptPromise promise = resolver->Promise();

mojo_service_->ListPurchases(
WTF::Bind(&OnListPurchasesResponse, WrapPersistent(resolver)));
WTF::Bind(&ResolveWithPurchaseReferenceList, WrapPersistent(resolver)));
return promise;
}

ScriptPromise DigitalGoodsService::listPurchaseHistory(
ScriptState* script_state) {
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();

mojo_service_->ListPurchaseHistory(
WTF::Bind(&ResolveWithPurchaseReferenceList, WrapPersistent(resolver)));
return promise;
}

Expand Down
Expand Up @@ -5,10 +5,14 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DIGITAL_GOODS_SERVICE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DIGITAL_GOODS_SERVICE_H_

#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/forward.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {

Expand All @@ -25,6 +29,7 @@ class DigitalGoodsService final : public ScriptWrappable {
// IDL Interface:
ScriptPromise getDetails(ScriptState*, const Vector<String>& item_ids);
ScriptPromise listPurchases(ScriptState*);
ScriptPromise listPurchaseHistory(ScriptState*);
ScriptPromise consume(ScriptState*, const String& purchase_token);

void Trace(Visitor* visitor) const override;
Expand Down
Expand Up @@ -13,6 +13,9 @@
[CallWith=ScriptState, MeasureAs=DigitalGoodsListPurchases]
Promise<sequence<PurchaseDetails>> listPurchases();

[CallWith=ScriptState, MeasureAs=DigitalGoodsListPurchaseHistory, RuntimeEnabled=DigitalGoodsV2_1]
Promise<sequence<PurchaseDetails>> listPurchaseHistory();

[CallWith=ScriptState, MeasureAs=DigitalGoodsConsume]
Promise<void> consume(DOMString purchaseToken);
};
Expand Up @@ -4,14 +4,22 @@

#include "third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h"

#include <utility>

#include "base/notreached.h"
#include "components/payments/mojom/payment_request_data.mojom-blink-forward.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink.h"
#include "third_party/blink/renderer/modules/payments/payment_event_data_conversion.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace mojo {

using payments::mojom::blink::BillingResponseCode;
using payments::mojom::blink::CreateDigitalGoodsResponseCode;
using payments::mojom::blink::ItemDetailsPtr;
using payments::mojom::blink::ItemType;
using payments::mojom::blink::PurchaseReferencePtr;

WTF::String TypeConverter<WTF::String, CreateDigitalGoodsResponseCode>::Convert(
Expand Down Expand Up @@ -53,6 +61,26 @@ blink::ItemDetails* TypeConverter<blink::ItemDetails*, ItemDetailsPtr>::Convert(
!input->introductory_price_period.IsEmpty()) {
output->setIntroductoryPricePeriod(input->introductory_price_period);
}
if (input->introductory_price_cycles > 0)
output->setIntroductoryPriceCycles(input->introductory_price_cycles);
switch (input->type) {
case ItemType::kUnknown:
// Omit setting ItemType on output.
break;
case ItemType::kProduct:
output->setType("product");
break;
case ItemType::kSubscription:
output->setType("subscription");
break;
}
WTF::Vector<WTF::String> icon_urls;
if (input->icon_urls.has_value()) {
for (const blink::KURL& icon_url : input->icon_urls.value()) {
icon_urls.push_back(icon_url.GetString());
}
}
output->setIconURLs(std::move(icon_urls));
return output;
}

Expand Down
Expand Up @@ -5,14 +5,17 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DIGITAL_GOODS_TYPE_CONVERTERS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_GOODS_DIGITAL_GOODS_TYPE_CONVERTERS_H_

#include "mojo/public/cpp/bindings/type_converter.h"
#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink-forward.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_item_details.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_purchase_details.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace mojo {

template <typename T, typename U>
struct TypeConverter;

template <>
struct MODULES_EXPORT
TypeConverter<WTF::String,
Expand Down
Expand Up @@ -7,6 +7,7 @@
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-blink.h"
#include "third_party/blink/public/mojom/digital_goods/digital_goods.mojom-shared.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_item_details.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_currency_amount.h"
#include "third_party/blink/renderer/modules/payments/goods/digital_goods_type_converters.h"
Expand Down Expand Up @@ -42,6 +43,9 @@ TEST(DigitalGoodsTypeConvertersTest, MojoItemDetailsToIdl_WithOptionalFields) {
const String introductory_price_currency = "USD";
const String introductory_price_value = "1.00";
const String introductory_price_period = "P1W";
const uint64_t introductory_price_cycles = 123;
const String icon_url_1 = "https://foo.com/icon_url_1.png";
const String icon_url_2 = "https://foo.com/icon_url_2.png";

mojo_item_details->item_id = item_id;
mojo_item_details->title = title;
Expand All @@ -55,6 +59,9 @@ TEST(DigitalGoodsTypeConvertersTest, MojoItemDetailsToIdl_WithOptionalFields) {
introductory_price_currency, introductory_price_value);
mojo_item_details->introductory_price = std::move(introductory_price);
mojo_item_details->introductory_price_period = introductory_price_period;
mojo_item_details->introductory_price_cycles = introductory_price_cycles;
mojo_item_details->type = payments::mojom::ItemType::kSubscription;
mojo_item_details->icon_urls = {KURL(icon_url_1), KURL(icon_url_2)};

auto* idl_item_details = mojo_item_details.To<ItemDetails*>();
EXPECT_EQ(idl_item_details->itemId(), item_id);
Expand All @@ -70,6 +77,12 @@ TEST(DigitalGoodsTypeConvertersTest, MojoItemDetailsToIdl_WithOptionalFields) {
introductory_price_value);
EXPECT_EQ(idl_item_details->introductoryPricePeriod(),
introductory_price_period);
EXPECT_EQ(idl_item_details->introductoryPriceCycles(),
introductory_price_cycles);
EXPECT_EQ(idl_item_details->type(), "subscription");
ASSERT_EQ(idl_item_details->iconURLs().size(), 2u);
EXPECT_EQ(idl_item_details->iconURLs()[0], icon_url_1);
EXPECT_EQ(idl_item_details->iconURLs()[1], icon_url_2);
}

TEST(DigitalGoodsTypeConvertersTest,
Expand Down Expand Up @@ -99,6 +112,9 @@ TEST(DigitalGoodsTypeConvertersTest,
EXPECT_FALSE(idl_item_details->hasFreeTrialPeriod());
EXPECT_FALSE(idl_item_details->hasIntroductoryPrice());
EXPECT_FALSE(idl_item_details->hasIntroductoryPricePeriod());
EXPECT_FALSE(idl_item_details->hasIntroductoryPriceCycles());
EXPECT_FALSE(idl_item_details->hasType());
EXPECT_EQ(idl_item_details->iconURLs().size(), 0u);
}

TEST(DigitalGoodsTypeConvertersTest, NullMojoItemDetailsToIdl) {
Expand Down
11 changes: 11 additions & 0 deletions third_party/blink/renderer/modules/payments/goods/item_details.idl
Expand Up @@ -7,11 +7,22 @@ dictionary ItemDetails {
required DOMString itemId;
required DOMString title;
required PaymentCurrencyAmount price;
[RuntimeEnabled=DigitalGoodsV2_1]
ItemType type;
DOMString description;
[RuntimeEnabled=DigitalGoodsV2_1]
sequence<DOMString> iconURLs;
// Periods are specified as ISO 8601 durations.
// https://en.wikipedia.org/wiki/ISO_8601#Durations
DOMString subscriptionPeriod;
DOMString freeTrialPeriod;
PaymentCurrencyAmount introductoryPrice;
DOMString introductoryPricePeriod;
[EnforceRange, RuntimeEnabled=DigitalGoodsV2_1]
unsigned long long introductoryPriceCycles;
};

enum ItemType {
"product",
"subscription",
};
Expand Up @@ -896,6 +896,12 @@
"default": "test"
},
},
{
name: "DigitalGoodsV2_1",
// crbug.com/1143079: Web tests cannot differentiate ChromeOS and Linux,
// so enable the API on all platforms for testing.
status: "test",
},
{
name: "DirectSockets",
status: "test",
Expand Down
Expand Up @@ -92,25 +92,35 @@
assert_equals(response[0].description, 'description:id2');
assert_equals(response[0].price.currency, 'AUD');
assert_equals(response[0].price.value, '2.00');
// Optional fields are absent or empty.
assert_equals(response[0].type, undefined);
assert_array_equals(response[0].iconURLs, []);
assert_equals(response[0].subscriptionPeriod, undefined);
assert_equals(response[0].freeTrialPeriod, undefined);
assert_equals(response[0].introductoryPrice, undefined);
assert_equals(response[0].introductoryPricePeriod, undefined);
assert_equals(response[0].introductoryPriceCycles, undefined);
}, {title: 'GetDetails round trip, required fields.'});

digital_goods_test(async service => {
const response = await service.getDetails(['id1']);
assert_equals(response.length, 1);
const response = await service.getDetails(['id1', 'id3']);
assert_equals(response.length, 2);
assert_equals(response[0].itemId, 'id1');
assert_equals(response[0].title, 'title:id1');
assert_equals(response[0].description, 'description:id1');
assert_equals(response[0].price.currency, 'AUD');
assert_equals(response[0].price.value, '1.00');
assert_equals(response[0].type, 'subscription');
assert_equals(response[0].description, 'description:id1');
assert_equals(response[0].iconURLs.length, 1, 'iconURLs.length');
assert_equals(response[0].iconURLs[0], 'https://example.com/icon.png');
assert_equals(response[0].subscriptionPeriod, 'P1Y');
assert_equals(response[0].freeTrialPeriod, 'P1M');
assert_equals(response[0].introductoryPrice.currency, 'JPY');
assert_equals(response[0].introductoryPrice.value, '2');
assert_equals(response[0].introductoryPricePeriod, 'P1D');
assert_equals(response[0].introductoryPriceCycles, 3);
// itemType has two valid values.
assert_equals(response[1].type, 'product');
}, {title: 'GetDetails round trip, optional fields.'});

digital_goods_test(async service => {
Expand Down Expand Up @@ -182,7 +192,18 @@
assert_equals(response[1].purchaseToken, 'purchaseToken:1');
}, {title: 'ListPurchases round trip.'});

// TODO (crbug.com/1250604): Add ListPurchaseHistory test with blink impl.
digital_goods_test(async service => {
const response = await service.listPurchaseHistory();
assert_equals(response.length, 20);

assert_equals(response[0].itemId, 'id:0');
assert_equals(response[0].purchaseToken, 'purchaseToken:0');
// Should not have DGAPI v1 fields exposed.
assert_equals(response[0].acknowledged, undefined);

assert_equals(response[1].itemId, 'id:1');
assert_equals(response[1].purchaseToken, 'purchaseToken:1');
}, {title: 'ListPurchaseHistory round trip.'});

digital_goods_test(async service => {
const response1 = await service.getDetails(['id1']);
Expand Down
Expand Up @@ -5,6 +5,7 @@ import {
DigitalGoodsFactoryReceiver,
DigitalGoodsReceiver,
DigitalGoodsRemote,
ItemType,
} from '/gen/third_party/blink/public/mojom/digital_goods/digital_goods.mojom.m.js';

class MockDigitalGoods {
Expand Down Expand Up @@ -48,6 +49,9 @@ class MockDigitalGoods {
itemDetails.introductoryPrice.currency = 'JPY';
itemDetails.introductoryPrice.value = 2*num + '';
itemDetails.introductoryPricePeriod = 'P' + num + 'D';
itemDetails.introductoryPriceCycles = 3*num;
itemDetails.type = Math.floor(num / 2) % 2 ? ItemType.kProduct : ItemType.kSubscription;
itemDetails.iconUrls = [{url: 'https://example.com/icon.png'}];
}
return itemDetails;
}
Expand Down

0 comments on commit 5028e3e

Please sign in to comment.