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

[service-workers] Use asynchronous cleanup #13164

Merged

Conversation

jugglinmike
Copy link
Contributor

Previously, many tests un-registered service workers only after all
assertions had been satisfied. This meant that failing tests would not
un-register workers. In order to account for workers that persisted from
previous test failures, the tests included "setup" code to defensively
un-register such workers.

The Test#add_cleanup method was recently extended to support
asynchronous "clean up" operations [1]. Use that API to schedule service
worker un-registration so that it occurs regardless of the result of
each test.

[1] #8748


This patch is not intended to influence test results. To verify that, I used
the WPT CLI to run the affected tests in Chromium and Firefox, comparing the
summary it produced both on master and on this branch.

Chromium on master:

web-platform-test
~~~~~~~~~~~~~~~~~
Ran 145 checks (32 tests, 113 subtests)
Expected results: 120
Unexpected results: 25
  test: 2 (2 timeout)
  subtest: 23 (15 fail, 6 notrun, 2 timeout)

Chromium with patch applied:

web-platform-test
~~~~~~~~~~~~~~~~~
Ran 145 checks (32 tests, 113 subtests)
Expected results: 120
Unexpected results: 25
  test: 2 (2 timeout)
  subtest: 23 (15 fail, 6 notrun, 2 timeout)

Firefox on master:

web-platform-test
~~~~~~~~~~~~~~~~~
Ran 145 checks (32 tests, 113 subtests)
Expected results: 134
Unexpected results: 11
  test: 2 (2 timeout)
  subtest: 9 (6 fail, 1 notrun, 2 timeout)

Firefox with patch applied:

 web-platform-test
 ~~~~~~~~~~~~~~~~~
 Ran 145 checks (32 tests, 113 subtests)
 Expected results: 134
 Unexpected results: 11
   test: 2 (2 timeout)
   subtest: 9 (6 fail, 1 notrun, 2 timeout)

Copy link
Contributor

@mkruisselbrink mkruisselbrink left a comment

Choose a reason for hiding this comment

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

I think this looks good, modulo some nits and the thing I raised on IRC where it appears that using service_worker_unregister() from a cleanup function will result in any failures during that unregister to be silently ignored (as rather than returning a rejected promise service_worker_unregister() runs some code inside a t.step() to handle errors). Not sure how bad it is if those are ignored though, so it might be okay to leave it like this until somebody has time for more extensive cleanups of this code?

}).then(_ => {
return service_worker_unregister_and_done(t, opts.scope);

t.done();
Copy link
Contributor

Choose a reason for hiding this comment

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

is there actually a need to call t.done()? It always seems suspicious to me if a promise_test calls done(), since the promise resolving itself should have that same effect?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right: that's superfluous.

@@ -32,9 +32,13 @@

// Register a service worker.
.then(() => service_worker_unregister_and_register(t, script, scope))
.then(r => worker = r.installing)
.then(() => wait_for_state(t, worker, 'activated'))
.then((r) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: not sure why you're adding () around r? it seems more consistent with the rest of the file to not add those.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, my personal style leaked through while re-writing these callbacks. Should be fixed, now.

@@ -30,9 +30,13 @@
'fetch() should not be intercepted.'))
// Register a service worker.
.then(() => service_worker_unregister_and_register(t, script, scope))
.then(r => worker = r.installing)
.then(() => wait_for_state(t, worker, 'activated'))
.then((r) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: here too, no () for consistency with rest of file

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

@@ -17,7 +17,11 @@
let slowURL = url + '&slow';
let frame;
return service_worker_unregister_and_register(t, script, scope)
.then(reg => wait_for_state(t, reg.installing, 'activated'))
.then((reg) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: here too no ()

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

@mkruisselbrink
Copy link
Contributor

(the test that is flaky in chrome that is causing travis to fail is https://crbug.com/831509)

@jugglinmike
Copy link
Contributor Author

Thanks for the review, @mkruisselbrink. Regarding cleanup failures: I wouldn't mind extending this patch to trigger harness errors. To me, it's more a question of how much change we should tolerate in one patch.

We could define a new function that does everything service_worker_unregister does up until the t.step invocation. We should probably keep service_worker_unregister as is, but that makes this new function hard to name. service_worker_unregister_simple is the best I have right now. Pretty dopey, right?

We could overload service_worker_unregister:

 function service_worker_unregister(test, scope) {
   var absoluteScope = (new URL(scope, window.location).href);
+  var fail = test === null ?
+    null : unreached_rejection(test, 'unregister should not fail')
   return navigator.serviceWorker.getRegistration(scope)
     .then(function(registration) {
         if (registration && registration.scope === absoluteScope)
           return registration.unregister();
       })
-    .catch(unreached_rejection(test, 'unregister should not fail'));
+    .catch(fail);
 }

That's an awkward API, but intentionally so--we wouldn't want folks accidentally opting in to this behavior.

My favorite option is more drastic. I've had my eyes on removing service_worker_unregister_and_register because as far as I can tell, it's obviated by proper cleanup. I've held off on that for these patches because they're large enough as it is. If we wanted to start that here, we could define a replacement helper that would consolidate registration and cleanup:

function service_worker_hygienic_register(test, url, scope) {
  if (!scope)
    return Promise.reject(new Error('tests must define a scope'));

  var options = { scope: scope };
  return navigator.serviceWorker.register(url, options)
    .then(function(registration) {
      test.add_cleanup(function() {
          return registration.unregister();
        });

      return registration;
    });
}

@mkruisselbrink
Copy link
Contributor

I think I'd prefer not to have too many unrelated changes in one PR, so probably not the change to service_worker_hygienic_register (as an aside, even if proper cleanup should alleviate the need for an unregister before register, it might still be a good idea to keep that unregister anyway, just in case... At least personally I'm a fan of tests of course cleaning up everything they do, but still also being somewhat resistant to other tests not doing so where it doesn't complicate stuff too much).

I'd be fine with just landing this as is, or something like that overload your suggesting/a separate method (unregister_service_worker? or unregister_service_worker_by_scope?)

@jugglinmike
Copy link
Contributor Author

@mattto Do you have a preference between the options @mkruisselbrink has selected?

@mfalken
Copy link
Member

mfalken commented Oct 18, 2018

Not totally sure I've followed everything in the thread, but I'd say land this as-is and then add service_worker_hygienic_register (just call it service_worker_register?) in another patch. I'd also prefer to bundle unregister at the beginning of service_worker_register just to make good tests resilient to bad tests.

BTW we can probably remove that "tests must define a scope" thing. I added that back when everything was an async_test. You had to give each test a unique scope so the tests didn't stomp on each other, so that warning helped ensure you added a scope.

@jugglinmike
Copy link
Contributor Author

@mattto reminder that you can merge things :)

Also, the instability that TravisCI has reported is unrelated--see gh-14083

Copy link
Member

@mfalken mfalken left a comment

Choose a reason for hiding this comment

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

I'm very sorry for the delay. I think I finally have a system that filters the "review requested" mails to a folder that I'll notice.

Unfortunately I can't merge on the web UI due to the CI error, so I'm looking into doing this by the command line.

@mfalken
Copy link
Member

mfalken commented Dec 3, 2018

I couldn't figure out the command line but I've heard Travis stability is no longer blocking, so I've restarted the Travis check.

Previously, many tests un-registered service workers only after all
assertions had been satisfied. This meant that failing tests would not
un-register workers. In order to account for workers that persisted from
previous test failures, the tests included "setup" code to defensively
un-register such workers.

The `Test#add_cleanup` method was recently extended to support
asynchronous "clean up" operations [1]. Use that API to schedule service
worker un-registration so that it occurs regardless of the result of
each test.

[1] web-platform-tests#8748
@jugglinmike jugglinmike force-pushed the service-workers-async-cleanup-use branch from d9ab513 to e065b16 Compare December 3, 2018 18:25
@jugglinmike
Copy link
Contributor Author

You heard right, but this branch predated the change which allowed instability. I've rebased to incorporate that change, so this pull request is no longer blocked by unrelated instability (though the instability is still present).

The prior version of this branch is available on Bocoup's fork of wpt:

master...bocoup:service-workers-async-cleanup-use-orig

@mfalken mfalken merged commit 1abcb70 into web-platform-tests:master Dec 4, 2018
@mfalken
Copy link
Member

mfalken commented Dec 4, 2018

Thanks for the patch and for rebasing!

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.

4 participants