Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for cache:getClientId #14450

Merged
merged 21 commits into from Apr 11, 2018
Merged

Conversation

RJSumi
Copy link
Contributor

@RJSumi RJSumi commented Apr 5, 2018

  • Implements support for cache:getClientId via a new class, CacheCidApi.

Fixes #13118

Copy link

@dreamofabear dreamofabear left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good! Needs unit tests for cache-cid-api.js.

* See the License for the specific language governing permissions and
* limitations under the License.
* amp-lUSTQLTz0csodkt327ZRHm30PG-6sJOuZwTh-PPmzqRMGZrTCRBMJ8Pfdw8f_UGC
* amp-lUSTQLTz0csodkt327ZRHm30PG-6sJOuZwTh-PPmzqRMGZrTCRBMJ8Pfdw8f_UGC

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

const TAG = 'CacheCidApi';
const CACHE_API_URL = 'https://ampcid.google.com/v1/cache:getClientId?key=';

const TIMEOUT = 30000;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add JSDoc for all of these constants.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

*/
export class CacheCidApi {

constructor(ampdoc) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSDoc please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* @return {!Promise<?string>}
*/
getScopedCid(scope) {
// promise for whether we do stuff at all

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what this comment means.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it was a draft holdover from when the structure of the method was more confusing and I was starting comment stubs.

// The client is still responsible for appending API keys to the URL.
const alt = `${response['alternateUrl']}?key=${SERVICE_KEY_}`;
return this.fetchCid_(dev().assertString(alt))
.then(altRes => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than dupe this logic, let's add an optional param to fetchCid_ that checks for alternateUrl and defaults to true. Then pass false for this invocation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks.

import {dict} from '../utils/object';
import {getSourceOrigin} from '../url';

const GOOGLE_CLIENT_ID_API_META_NAME = 'amp-google-client-id-api';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's be consistent wrt "CLIENT_ID" vs "CID" -- GOOGLE_CID_API_META_NAME.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* Returns scoped CID extracted from the fetched publisherCid.
* @param {string} publisherCid
* @param {string} scope
* @return {?string}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns !Promise<string>, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks.

* @return {?string}
*/
scopeCid_(publisherCid, scope) {
if (!publisherCid) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{string} is non-nullable by default. Is it possible for this to be empty string or should we change the type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetchCid_ returns a nullable string, which used to propagate to this method. I moved the null check to the call site.

}

/**
* @return {!Object<string, string>}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a description with an example of what the <meta> tag can looks like here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this what you meant?

@dreamofabear
Copy link

BTW, an editor with eslint plugin configured will save a lot of time compared to gulp lint. SublimeText and VSCode are good choices.

@dreamofabear
Copy link

Just merged #14224, please merge latest changes from master.

/**
* @return {!Object<string, string>}
*/
getOptedInScopes_() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this verbatim from viewer-cid-api.js? Can it live in cid-impl.js instead and be called at time of invocation of isScopeOptedIn and passed in as a param?

Copy link

@dreamofabear dreamofabear left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall.

* Returns scoped CID retrieved from the Viewer.
* @param {string|undefined} apiKey
* @param {string} scope
* @return {!Promise<string>}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!Promise<?string>

@@ -94,12 +123,20 @@ export class Cid {
*/
this.externalCidCache_ = Object.create(null);

/**
* @private {!CacheCidApi}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @const.

@@ -175,8 +212,8 @@ export class Cid {
const scope = getCidStruct.scope;
/** @const {!Location} */
const url = parseUrl(this.ampdoc.win.location.href);
const apiKey = this.isScopeOptedIn_(scope);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's only call this if necessary to avoid wasted work.

const SERVICE_KEY_ = 'AIzaSyDKtqGxnoeIqVM33Uf7hRSa3GJxuzR7mLc';
const API_KEY = 'AIzaSyA65lEHUEizIsNtlbNo-l2K18dT680nsaM';
const TEST_CID_ =
'amp-mJW1ZjoviqBJydzRI8KnitWEpqyhQqDegGClrvvfkCif_N9oYLdZEB976uJDhYgL';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use the actual keys in tests if possible. If we need to change them in the future then it would appear we'd need to update these tests too. Something readable like my-service-key and my-api-key would suffice.

return api.getScopedCid(API_KEY, 'AMP_ECID_GOOGLE').then(cid => {
expect(cid).to.equal(TEST_CID_);
expect(fetchJsonStub)
.to.be.calledWith(`https://ampcid.google.com/v1/cache:getClientId?key=${SERVICE_KEY_}`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just use the actual string literal for readability. ToTT issue 510. 😉

@@ -795,7 +800,8 @@ describes.realWin('cid', {amp: true}, env => {

beforeEach(() => {
sandbox.stub(url, 'isProxyOrigin').returns(false);
sandbox.stub(cid.viewerCidApi_, 'isScopeOptedIn').returns('api-key');
ampdoc.win.document.head.innerHTML +=
'<meta name="amp-google-client-id-api" content="googleanalytics">';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change (and line 821) necessary? It's better to avoid mutating the document during tests (e.g. can break other tests if you forget to revert in afterEach).

I did notice that this is patterned off of test-viewer-cid-api.js. ☹️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't think it'll be easy to avoid adding to the document, given that the behaviour under test is supposed to extract the configuration from it.

@@ -44,6 +44,8 @@ import {stubServiceForDoc} from '../../testing/test-helper';

const DAY = 24 * 3600 * 1000;

const API_KEY = 'AIzaSyA65lEHUEizIsNtlbNo-l2K18dT680nsaM';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this and inline it in the original isScopedOptedIn_ tests you moved.

});
});

describe('getScopedCid', () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing the timeout logic would be nice. You can use sinon's fake clock to simulate 30s passing synchronously.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and this revealed a promise chaining bug (catch block didn't catch the timeout because it was chained to the XHR).

@dreamofabear
Copy link

dreamofabear commented Apr 10, 2018

/cc @jridgewell Another unavoidable size bump FYI. We could move viewer-cid-api.js to amp-viewer-integration but I don't think it'll help much.

What's interesting is that the browserify build increased by 0.1KB while the minified build increased by 0.26KB. Looks like the obfuscation impeded compressibility.

@dreamofabear
Copy link

From Travis, looks like Viewer#isProxyOrigin() function might've been lost in a merge. You can also run gulp check-types locally.

@dreamofabear dreamofabear merged commit 82fd3a1 into ampproject:master Apr 11, 2018
Copy link
Contributor

@jridgewell jridgewell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much duplication between this and https://github.com/ampproject/amphtml/blob/9b101fa000b7dc911073cacdf3ccafb187c2012d/src/service/cid-api.js.

And, there are now 4 different CID api files:

  1. src/service/cid-api.js
  2. src/service/cid-impl.js
  3. src/service/viewer-cid-api.js
  4. src/service/cache-cid-api.js

What's the difference? What is the responsibility of each file?

/cc @lannka

if (this.cacheCidApi_.isSupported()) {
const apiKey = this.isScopeOptedIn_(scope);
if (!apiKey) {
return /** @type {!Promise<?string>} */ (Promise.resolve(null));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't CCT fall back to normal cids?

*/
getScopedCid(scope) {
if (!this.viewer_.isCctEmbedded()) {
return /** @type {!Promise<?string>} */ (Promise.resolve(null));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throw an error.

body: payload,
})).then(res => {
return res.json().then(response => {
if (response['optOut']) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire function's whitespace is borked.

// If an alternate url is provided, try again with the alternate url
// The client is still responsible for appending API keys to the URL.
const alt = `${response['alternateUrl']}?key=${SERVICE_KEY_}`;
return this.fetchCid_(dev().assertString(alt), false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertString is unnecessary.

glevitzky pushed a commit that referenced this pull request Apr 27, 2018
* Add a class to interface with the new Google CID API endpoint for cache-served pages without a viewer.

* fix lint errors

* assorted fixes based on testing

* added TODOs to indicate that this will merge with #14224. The CCT-embedded implementations are just for the interim.

* unit test stuff

* add unit tests for cache cid api

* documentation fixes

* fix broken partial change

* fix secretly broken unit test and copied naming and introduce a bunch of lint errors

* fix lint errors

* move isScopeOptedIn into cid-impl rather than duplicating for cache and viewer APIs

* fix unit tests

* Re-add lost size cap bump.

* address comments and fix unit tests

* fix type errors and missing viewer.isProxyOrigin

* Update size caps again.
@lannka
Copy link
Contributor

lannka commented May 10, 2018

@jridgewell agree with you. This new file can be merged into cid-api.js

The way the code was organized:

cid-impl.js  -> cid-api.js (Get CID from CID API)
             -> viewer-cid-api.js (Get CID from Viewer)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants