Skip to content

Commit

Permalink
Update short URL access fields on resolution by slug (#142731)
Browse files Browse the repository at this point in the history
* update short url access fields on resolution by slug

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* improve field update method

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* [CI] Auto-commit changed files from 'node scripts/build_plugin_list_docs'

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
vadimkibana and kibanamachine authored Oct 5, 2022
1 parent 803189f commit 6b1e448
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ const setup = () => {
};
};

const tick = (ms: number = 1) => new Promise((r) => setTimeout(r, ms));

const until = async (check: () => Promise<boolean>, pollInterval: number = 1) => {
do {
if (await check()) return;
await tick(pollInterval);
} while (true);
};

describe('ServerShortUrlClient', () => {
describe('.create()', () => {
test('can create a short URL', async () => {
Expand Down Expand Up @@ -72,6 +81,20 @@ describe('ServerShortUrlClient', () => {
},
});
});

test('initializes "accessDate" and "accessCount" fields on URL creation', async () => {
const { client, locator } = setup();
const { data } = await client.create({
locator,
slug: 'lala',
params: {
url: '/app/test#foo/bar/baz',
},
});

expect(data.accessDate).toBeGreaterThan(Date.now() - 1000000);
expect(data.accessCount).toBe(0);
});
});

describe('.resolve()', () => {
Expand All @@ -85,7 +108,7 @@ describe('ServerShortUrlClient', () => {
});
const shortUrl2 = await client.resolve(shortUrl1.data.slug);

expect(shortUrl2.data).toMatchObject(shortUrl1.data);
expect(shortUrl2.data).toStrictEqual(shortUrl1.data);
});

test('can create short URL with custom slug', async () => {
Expand Down Expand Up @@ -128,6 +151,33 @@ describe('ServerShortUrlClient', () => {
})
).rejects.toThrowError(new UrlServiceError(`Slug "lala" already exists.`, 'SLUG_EXISTS'));
});

test('updates "accessCount" and "accessDate" on URL resolution by slug', async () => {
const { client, locator } = setup();
const shortUrl1 = await client.create({
locator,
params: {
url: '/app/test#foo/bar/baz',
},
});

expect(shortUrl1.data.accessDate).toBeGreaterThan(Date.now() - 1000000);
expect(shortUrl1.data.accessCount).toBe(0);

await client.resolve(shortUrl1.data.slug);
await until(async () => (await client.get(shortUrl1.data.id)).data.accessCount === 1);
const shortUrl2 = await client.get(shortUrl1.data.id);

expect(shortUrl2.data.accessDate).toBeGreaterThanOrEqual(shortUrl1.data.accessDate);
expect(shortUrl2.data.accessCount).toBe(1);

await client.resolve(shortUrl1.data.slug);
await until(async () => (await client.get(shortUrl1.data.id)).data.accessCount === 2);
const shortUrl3 = await client.get(shortUrl1.data.id);

expect(shortUrl3.data.accessDate).toBeGreaterThanOrEqual(shortUrl2.data.accessDate);
expect(shortUrl3.data.accessCount).toBe(2);
});
});

describe('.get()', () => {
Expand All @@ -141,7 +191,7 @@ describe('ServerShortUrlClient', () => {
});
const shortUrl2 = await client.get(shortUrl1.data.id);

expect(shortUrl2.data).toMatchObject(shortUrl1.data);
expect(shortUrl2.data).toStrictEqual(shortUrl1.data);
});

test('throws when fetching non-existing short URL', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,29 @@ export class ServerShortUrlClient implements IShortUrlClient {
const { storage } = this.dependencies;
const record = await storage.getBySlug(slug);
const data = this.injectReferences(record);
this.updateAccessFields(record);

return {
data,
};
}

/**
* Access field updates are executed in the background as we don't need to
* wait for them and confirm that they were successful.
*/
protected updateAccessFields(record: ShortUrlRecord) {
const { storage } = this.dependencies;
const { id, ...attributes } = record.data;
storage
.update(id, {
...attributes,
accessDate: Date.now(),
accessCount: (attributes.accessCount || 0) + 1,
})
.catch(() => {}); // We are not interested if it succeeds or not.
}

public async delete(id: string): Promise<void> {
const { storage } = this.dependencies;
await storage.delete(id);
Expand Down

0 comments on commit 6b1e448

Please sign in to comment.