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

Improve fake ad network by providing working example, updating doc, a… #9295

Merged
merged 5 commits into from Jun 10, 2017
Merged

Improve fake ad network by providing working example, updating doc, a… #9295

merged 5 commits into from Jun 10, 2017

Conversation

jonkeller
Copy link
Contributor

  1. Provide a working example of fake ad network
  2. Document the use of fakesig="true"
  3. Fix bug in which, when fakesig="true" is used, it was expecting a file called something.json but which contained HTML, not JSON.
  4. Fix bug in which 2 network requests were issued for the fake creative

}
// Prevent issueing a second network request to try to fetch
// the same JSON again.
this.experimentalNonAmpCreativeRenderMethod_ = XORIGIN_MODE.NAMEFRAME;
Copy link
Contributor Author

@jonkeller jonkeller May 12, 2017

Choose a reason for hiding this comment

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

@keithwrightbos This isn't allowed since this.experimentalNonAmpCreativeRenderMethod_ is private. The reason I want to do this is so that on

const method = this.experimentalNonAmpCreativeRenderMethod_;
it does NOT call this.renderViaCachedContentIframe_(this.adUrl_); 8 lines later, because that is resulting in a second network request for the creative, and would require re-doing all the JSON stuff I just did above.
So I would like to do an /OK/ to override this linter complaint. Or alternatively make a public setter for this, but that seems sketchy too. I figure you own this, per your comment on line 289 of the linked file. Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Disregard - next commit is going to make this moot.

if (getMode().localDev && this.element.getAttribute('type') == 'fake') {
// Prevent issuing a second network request to try to fetch
// the same JSON again.
this.experimentalNonAmpCreativeRenderMethod_ = XORIGIN_MODE.NAMEFRAME;
Copy link
Contributor

Choose a reason for hiding this comment

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

can this be passed in by an attribute?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My original approach was to try to set it from AmpAdNetworkFakeImpl, but it's private to the parent class. I agree this is hacky, but I think any other approach would also be hacky. We could have AmpAdNetworkFakeImpl set some attribute, and then have the parent class say if (this.theAttribute) { this.experimentalNonAmpCreativeRenderMethod_ = theAttribute; } but I'm really bothered by doing any subclass-specific logic in the parent class...

this.adUrl_ = this.getAdUrl();
this.adPromise_ = Promise.resolve();
return;
if (getMode().localDev && this.element.getAttribute('type') == 'fake') {
Copy link
Contributor

Choose a reason for hiding this comment

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

getMode().localDev check is not needed. we already checked in amp-ad.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.

Happy to remove, but note that this check was here previously. Was trying to make as little change as possible...

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's keep. I'd like to have 100% guarantee that this code is not in PROD binary.

// Gracefully handle the case in which the fake ad is still
// formatted in JSON, which it almost certainly is, since
// "gulp serve" won't serve an HTML file under /extensions
const json = JSON.parse(deserialized);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering how does the production logic right now handle this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Basically the issue here is that normally it wants JSON like { "creative": ...html..., "signature": ... }
However if you use a fake ad, then it was just rendering everything it gets, so the ad would contain the JSON structure above, not just the html. But if you change to , then it doesn't work because gulp won't serve a .html file from extensions/. So the ugly workaround was to make a .json file which contained no JSON, only HTML. This fix just solves that, and affects only the fake ad network.
A real ad would come in the JSON format, but we would never be in AmpAdNetworkFakeImpl. extractCreativeAndSignature() in the first place.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, should have made my question clearer. And this is mainly for my own learning. Let me know if any of my understanding went wrong:

  • In fast fetch, runtime first requests a URL via XHR. It returns a JSON (AMP creative) or HTML (non-AMP creative)
  • In case of non-AMP or invalid AMP, runtime creates an iframe and having the src= attribute pointing to the same URL (the cache frame rendering path). And we expect it to hit the browser cache to save a round trip.
  • In case of non-AMP, the HTML is perfectly rendered in the iframe. However, for the invalid AMP case, how do we deal with the cached JSON?

@keithwrightbos

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Your understanding sounds correct to me. I'm not sure of the answer re: the invalid AMP caching question. I'd be happy to research that for you, or maybe Keith knows off the top of his head...

Copy link
Contributor

Choose a reason for hiding this comment

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

We parse the creative HTML out of the JSON in both cases. For non-AMP the creative portion only would be written into safeframe and rendered

Copy link
Contributor

Choose a reason for hiding this comment

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

@keithwrightbos so you meant if the creative is AMP with a wrong signature, we'll always choose SafeFrame rendering method?

// Gracefully handle the case in which the fake ad is still
// formatted in JSON, which it almost certainly is, since
// "gulp serve" won't serve an HTML file under /extensions
const json = JSON.parse(deserialized);
Copy link
Contributor

Choose a reason for hiding this comment

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

@keithwrightbos so you meant if the creative is AMP with a wrong signature, we'll always choose SafeFrame rendering method?

if (getMode().localDev && this.element.getAttribute('type') == 'fake') {
// Prevent issuing a second network request to try to fetch
// the same JSON again.
this.experimentalNonAmpCreativeRenderMethod_ = XORIGIN_MODE.NAMEFRAME;
Copy link
Contributor

Choose a reason for hiding this comment

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

see my other comment. I'm trying to see if we can avoid doing this test only logic. We are making the test widget behave differently than the prod widget, so we're not testing the true logic.

If this does not work, we might be hitting a bug?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe the fake ad network should never be used in prod at all...

Copy link
Contributor

Choose a reason for hiding this comment

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

of course it's not in prod.

my point is: why you have to have this logic in test to make it work? and why prod can work without it? how does prod prevent hitting the json cache?

overall, we want to avoid introducing test-only code in non-test. does it make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I see what you mean. This is due to the setting of "method" here:

const method = fetchResponse.headers.get(RENDERING_TYPE_HEADER) ||

In prod, the HTTP header will be set. But when running locally, it isn't. Without explicitly setting it here, we hit the error on line 615 when testing locally.

Copy link
Contributor

Choose a reason for hiding this comment

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

so i will suggest we change our local server to set the header, instead of putting extra logic into code to bypass this.

@@ -755,16 +755,16 @@ app.use([cloudflareDataDir], function fakeCors(req, res, next) {
*/
app.get([ fakeAdNetworkDataDir + '/*', cloudflareDataDir + '/*'], function(req, res) {
var filePath = req.path;
var unwrap = false;
var unwrap = true;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@lannka Re: your previous question, it turns out that the problem was here. This was implemented backwards. If the creative is a .json file, then it should be unwrapped (signature and HTML extracted), and if it's a .html file then that is not needed. It was done the opposite way. My other main change here is the line that sets the X-AmpAdRender header, which removes the need for the change to amp-a4a.js which you weren't a fan of. Now,

const method = fetchResponse.headers.get(RENDERING_TYPE_HEADER) ||
sets method correctly, and we don't hit the error on line 615.

@jonkeller jonkeller requested a review from taymonbeal May 30, 2017 15:24
filePath = pc.cwd() + filePath;
fs.readFileAsync(filePath).then(file => {
res.setHeader('X-AmpAdRender', 'nameframe');
Copy link
Contributor Author

Choose a reason for hiding this comment

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

(Copying comment over from outdated code, with slight edits for clarity)
@lannka Re: your previous question, it turns out that the problem was here. "unwrap" was implemented backwards. If the creative is a .json file, then it should be unwrapped (signature and HTML extracted), and if it's a .html file then that is not needed (and the extension should NOT be stripped off). But "unwrap" was done the opposite way. My other main change here is the line that sets the X-AmpAdRender header, which removes the need for the change to amp-a4a.js which you weren't a fan of. Now,

const method = fetchResponse.headers.get(RENDERING_TYPE_HEADER) ||
sets method correctly, and we don't hit the error on line 615.

Copy link
Contributor

Choose a reason for hiding this comment

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

much better. appreciate that.

filePath = pc.cwd() + filePath;
fs.readFileAsync(filePath).then(file => {
res.setHeader('X-AmpAdRender', 'nameframe');
Copy link
Contributor

Choose a reason for hiding this comment

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

much better. appreciate that.

@@ -59,15 +59,24 @@ export class AmpAdNetworkFakeImpl extends AmpA4A {
// and the signature is "FAKESIG". This mode is only allowed in
// `localDev` and primarily used for A4A Envelope for testing.
// See DEVELOPING.md for more info.
const creative = this.transformCreativeLocalDev_(deserialized);
let creative = this.transformCreativeLocalDev_(deserialized);
Copy link
Contributor

Choose a reason for hiding this comment

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

now i re-read the code. can we move the transformCreativeLocalDev_ logic to server side? so that we have a correct AMP ad format over the wire. ideally, this should be part of app.use('/a4a(|-3p)/' middleware.

After that, we don't need this try-catch anymore, since we know the exact format over the wire.

again, more logic in this fake extension, the farther away we are from testing the real things.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As it turns out, this change is no longer necessary - it is redundant due to the change in build-system/app.js. So I'll just remove it.

Copy link
Contributor

Choose a reason for hiding this comment

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

did you try if it still works with the /a4a/xxx style URL?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not familiar with what that is...can you give me an example or pointer to a doc?

Copy link
Contributor

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.

I checked at HEAD, and this does not currently seem to work. Unfortunately none of the team was aware of this URL format, so it's likely been broken for quite some time. If it's alright with you, I would suggest that we create a bug to fix that separately, since the current PR does not appear to be the one to have broken this functionality.

Copy link
Contributor

Choose a reason for hiding this comment

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

sounds good.

@@ -0,0 +1,24 @@
<!doctype html>
Copy link
Contributor

Choose a reason for hiding this comment

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

actually, would you move this file to test/manual/fakeada4a.amp.html, to sit together with test/manual/fakead3p.amp.html

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do customers know to look there? What is the intended difference between an example and a manual test?

Copy link
Contributor

Choose a reason for hiding this comment

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

example/ is for AMP page authors.
test/manual is for us.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My preference would be to leave it in examples/ so that an AMP page author that wants to write a page and test including ads in it can use this. But it's up to you. Do you think this is valid/useful?

@keithwrightbos keithwrightbos merged commit 1277428 into ampproject:master Jun 10, 2017
@keithwrightbos keithwrightbos deleted the fix_fake_ad_network branch June 10, 2017 14:03
@jonkeller
Copy link
Contributor Author

jonkeller commented Jun 10, 2017 via email

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

Successfully merging this pull request may close these issues.

None yet

6 participants