Skip to content

Commit

Permalink
Raft Snapshot Download Bug (#17769) (#17786)
Browse files Browse the repository at this point in the history
* moves service worker message event listener from addon to raft-storage-overview component

* adds changelog entry

* adds raft-storage-overview test for downloading snapshot via service worker
  • Loading branch information
zofskeez committed Nov 2, 2022
1 parent 0260f25 commit 668e5ac
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 30 deletions.
3 changes: 3 additions & 0 deletions changelog/17769.txt
@@ -0,0 +1,3 @@
```release-note:bug
ui: Fixes issue with not being able to download raft snapshot via service worker
```
24 changes: 23 additions & 1 deletion ui/app/components/raft-storage-overview.js
Expand Up @@ -5,6 +5,8 @@ import { inject as service } from '@ember/service';

export default Component.extend({
flashMessages: service(),
auth: service(),

useServiceWorker: null,

async init() {
Expand All @@ -16,12 +18,32 @@ export default Component.extend({
if ('serviceWorker' in navigator) {
// this checks to see if there's an active service worker - if it failed to register
// for any reason, then this would be null
let worker = await navigator.serviceWorker.getRegistration(config.serviceWorkerScope);
const worker = await navigator.serviceWorker.getRegistration(config.serviceWorkerScope);
if (worker) {
navigator.serviceWorker.addEventListener('message', this.serviceWorkerGetToken.bind(this));

this.set('useServiceWorker', true);
}
}
},
willDestroy() {
if (this.useServiceWorker) {
navigator.serviceWorker.removeEventListener('message', this.serviceWorkerGetToken);
}
this._super(...arguments);
},

serviceWorkerGetToken(event) {
const { action } = event.data;
const [port] = event.ports;

if (action === 'getToken') {
port.postMessage({ token: this.auth.currentToken });
} else {
console.error('Unknown event', event); // eslint-disable-line
port.postMessage({ error: 'Unknown request' });
}
},

actions: {
async removePeer(model) {
Expand Down
@@ -1,32 +1,6 @@
import { addSuccessHandler } from 'ember-service-worker/service-worker-registration';
import Namespace from '@ember/application/namespace';

function getToken() {
// fix this later by allowing registration somewhere in the app lifecycle were we can have access to
// services, etc.
return Namespace.NAMESPACES_BY_ID['vault'].__container__.lookup('service:auth').currentToken;
}

addSuccessHandler(function (registration) {
// attach the handler for the message event so we can send over the auth token
navigator.serviceWorker.addEventListener('message', (event) => {
let { action } = event.data;
let port = event.ports[0];

if (action === 'getToken') {
let token = getToken();
if (!token) {
console.error('Unable to retrieve Vault tokent');
}
port.postMessage({ token: token });
} else {
console.error('Unknown event', event);
port.postMessage({
error: 'Unknown request',
});
}
});

// attempt to unregister the service worker on unload because we're not doing any sort of caching
window.addEventListener('unload', function () {
registration.unregister();
Expand Down
45 changes: 42 additions & 3 deletions ui/tests/integration/components/raft-storage-overview-test.js
Expand Up @@ -2,17 +2,56 @@ import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import sinon from 'sinon';

module('Integration | Component | raft-storage-overview', function (hooks) {
setupRenderingTest(hooks);

test('it renders', async function (assert) {
let model = [
hooks.beforeEach(function () {
this.model = [
{ address: '127.0.0.1:8200', voter: true },
{ address: '127.0.0.1:8200', voter: true, leader: true },
];
this.set('model', model);
});

test('it renders', async function (assert) {
await render(hbs`<RaftStorageOverview @model={{this.model}} />`);
assert.dom('[data-raft-row]').exists({ count: 2 });
});

test('it should download snapshot via service worker', async function (assert) {
assert.expect(3);

const token = this.owner.lookup('service:auth').currentToken;
const generateMockEvent = (action) => ({
data: { action },
ports: [
{
postMessage(message) {
const getToken = action === 'getToken';
const expected = getToken ? { token } : { error: 'Unknown request' };
assert.deepEqual(
message,
expected,
`${
getToken ? 'Token' : 'Error'
} is returned to service worker in message event listener callback`
);
},
},
],
});

sinon.stub(navigator.serviceWorker, 'getRegistration').resolves(true);
sinon.stub(navigator.serviceWorker, 'addEventListener').callsFake((name, cb) => {
assert.strictEqual(name, 'message', 'Event listener added for service worker message');
cb(generateMockEvent('getToken'));
cb(generateMockEvent('unknown'));
});

await render(hbs`<RaftStorageOverview @model={{this.model}} />`);
// avoid clicking the download button or the url will change
// the service worker invokes the event listener callback when it intercepts the request to /v1/sys/storage/raft/snapshot
// for the test we manually fire the callback as soon as it is passed to the addEventListener stub
});
});

0 comments on commit 668e5ac

Please sign in to comment.