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

Set infinite TTL for redirects #375

Merged
merged 3 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions server/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ middlewareRouter.use(async (req, res) => {

exports.middleware = middlewareRouter

exports.add = async (id, newModified, content) => {
exports.add = async (id, newModified, content, ttl) => {
if (!newModified) throw new Error(`Refusing to store ${id} without modified time.`)

const data = await cache.get(id)
Expand All @@ -49,7 +49,7 @@ exports.add = async (id, newModified, content) => {
// if there was previous data and it is not older than the new data, don't do anything
if (oldContent && modified && !isNewer(modified, newModified)) return // nothing to do if data is current
// store new data in the cache
return cache.set(id, {content, modified: newModified, id})
return cache.set(id, {content, modified: newModified, id}, {ttl: ttl})
}

// expose the purgeCache method externally so that list can call while building tree
Expand Down
2 changes: 1 addition & 1 deletion server/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ async function setRedirects(oldDocsInfo, newDocsInfo) {
// if no lastPath, file is a new addition to the drive
if (currPath && lastPath && currPath !== lastPath) {
log.info(`Doc ${id} moved, REDIRECT ${lastPath} → ${currPath}`)
cache.add(lastPath, new Date(), {redirect: currPath})
cache.add(lastPath, new Date(), {redirect: currPath}, 0)
}
})
}
Expand Down
273 changes: 146 additions & 127 deletions test/functional/pages.test.js
Original file line number Diff line number Diff line change
@@ -1,177 +1,196 @@
'use strict'
"use strict";

const request = require('supertest')
const {expect} = require('chai')
const sinon = require('sinon')
const {allFilenames} = require('../utils')
const request = require("supertest");
const { expect } = require("chai");
const sinon = require("sinon");
const { allFilenames } = require("../utils");

const app = require('../../server/index')
const app = require("../../server/index");

const userInfo = {
emails: [{value: '[email protected]'}],
id: '10',
userId: '10',
_json: {domain: 'test.com'}
}
emails: [{ value: "[email protected]" }],
id: "10",
userId: "10",
_json: { domain: "test.com" },
};

describe('Server responses', () => {
beforeEach(() => sinon.stub(app.request, 'session').value({passport: {user: userInfo}}))
afterEach(() => sinon.restore())
describe("Server responses", () => {
beforeEach(() =>
sinon.stub(app.request, "session").value({ passport: { user: userInfo } })
);
afterEach(() => sinon.restore());

describe('that return HTML', () => {
it('should return 200 and content for homepage', () => {
describe("that return HTML", () => {
it("should return 200 and content for homepage", () => {
return request(app)
.get('/')
.get("/")
.expect(200)
.then((res) => expect(res.text).to.include('<title>Team Library</title>'))
})
.then((res) =>
expect(res.text).to.include("<title>Team Library</title>")
);
});

it('should return 200 OK for healthcheck', () => {
it("should return 200 OK for healthcheck", () => {
return request(app)
.get('/healthcheck')
.get("/healthcheck")
.expect(200)
.then((res) => {
expect(res.text).to.equal('OK')
})
})
expect(res.text).to.equal("OK");
});
});

it('should display subfolders for folder', () => {
it("should display subfolders for folder", () => {
return request(app)
.get('/test-folder-1')
.get("/test-folder-1")
.expect(200)
.then((res) => {
// check it resolves name correclty
expect(res.text).to.include('Pages in Test Folder 1')
expect(res.text).to.include("Pages in Test Folder 1");
// check it has links to children
expect(res.text).to.include('Article 1 in test folder 1')
expect(res.text).to.include('Article 2 in test folder 1')
})
})
expect(res.text).to.include("Article 1 in test folder 1");
expect(res.text).to.include("Article 2 in test folder 1");
});
});

it('should remove trailing slash and redirect', () => {
return request(app)
// should strip trailing slash
.get('/test-folder-1/')
.expect(302) // Should be cached at this point
.then((res) => {
expect(res.text).to.equal('Found. Redirecting to /test-folder-1')
})
})
it("should remove trailing slash and redirect", () => {
return (
request(app)
// should strip trailing slash
.get("/test-folder-1/")
.expect(302) // Should be cached at this point
.then((res) => {
expect(res.text).to.equal("Found. Redirecting to /test-folder-1");
})
);
});

it('should render top level folder in categories', () => {
it("should render top level folder in categories", () => {
return request(app)
.get('/categories')
.get("/categories")
.expect(200)
.then((res) => {
expect(res.text).to.include('<h3>\n <a href="/test-folder-1">\n Test Folder 1\n </a>\n </h3>')
})
})
expect(res.text).to.include(
'<h3>\n <a href="/test-folder-1">\n Test Folder 1\n </a>\n </h3>'
);
});
});

// also tests insertion into datastore
it('folder with home doc should render the doc', () => {
it("folder with home doc should render the doc", () => {
return request(app)
.get('/test-folder-9')
.get("/test-folder-9")
.expect(200)
.then((res) => {
expect(res.text).to.include('<h1 class="headline">Home article 10 for test folder 9</h1>')
expect(res.text).to.include('By <span class="author">John Smith</span>')
expect(res.text).to.include('Last edited by <span class="author">Foo Bar</span>')
expect(res.text).to.include('Home article 10 for test folder 9')
})
})
expect(res.text).to.include(
'<h1 class="headline">Home article 10 for test folder 9</h1>'
);
expect(res.text).to.include(
'By <span class="author">John Smith</span>'
);
expect(res.text).to.include(
'Last edited by <span class="author">Foo Bar</span>'
);
expect(res.text).to.include("Home article 10 for test folder 9");
});
});

it('duplicate doc should render a warning', () => {
it("duplicate doc should render a warning", () => {
return request(app)
.get('/test-folder-9/article-3-in-test-folder-9')
.get("/test-folder-9/article-3-in-test-folder-9")
.expect(200)
.then((res) => {
expect(res.text).to.include('<h1 class="headline">Article 3 in test folder 9</h1>')
expect(res.text).to.include('By <span class="author">John Smith</span>')
expect(res.text).to.include('Last edited by <span class="author">Foo Bar</span>')
expect(res.text).to.include('Article 3 in test folder 9')
expect(res.text).to.include(
'<h1 class="headline">Article 3 in test folder 9</h1>'
);
expect(res.text).to.include(
'By <span class="author">John Smith</span>'
);
expect(res.text).to.include(
'Last edited by <span class="author">Foo Bar</span>'
);
expect(res.text).to.include("Article 3 in test folder 9");
expect(res.text).to.include(
'<div class="warning">\n Warning: Multiple resources in ' +
'<a href="https://drive.google.com/drive/u/0/folders/TestFolder9" target="_blank">' +
'this folder</a> share the same name&#58; Article 3 in test folder 9. Only one will be ' +
'accesible through Library.\n</div>'
)
})
})
'<a href="https://drive.google.com/drive/u/0/folders/TestFolder9" target="_blank">' +
"this folder</a> share the same name&#58; Article 3 in test folder 9. Only one will be " +
"accesible through Library.\n</div>"
);
});
});

it('should render an inline <style> tag and no JS on error pages', () => {
it("should render an inline <style> tag and no JS on error pages", () => {
return request(app)
.get('/this-route-does-not-exist')
.get("/this-route-does-not-exist")
.expect(404)
.then((res) => {
expect(res.text).to.match(/<style type="text\/css">[^<]/i)
expect(res.text).to.not.include('<link href="/assets')
expect(res.text).to.not.include('<script src="/assets')
})
})
})
expect(res.text).to.match(/<style type="text\/css">[^<]/i);
expect(res.text).to.not.include('<link href="/assets');
expect(res.text).to.not.include('<script src="/assets');
});
});
});

describe('that return JSON', () => {
it('should contain a complete filename listing', () => {
describe("that return JSON", () => {
it("should contain a complete filename listing", () => {
return request(app)
.get('/filename-listing.json')
.get("/filename-listing.json")
.expect(200)
.then((res) => {
const {filenames} = res.body
expect(Array.isArray(filenames), 'cached file listing should be an array')
expect(filenames).to.include(...allFilenames)
expect(filenames.length).to.equal(allFilenames.length)
})
})
const { filenames } = res.body;
expect(
Array.isArray(filenames),
"cached file listing should be an array"
);
expect(filenames).to.include(...allFilenames);
expect(filenames.length).to.equal(allFilenames.length);
});
});

it('folder with home doc should render the doc', () => {
it("folder with home doc should render the doc", () => {
return request(app)
.get('/test-folder-9')
.set('Accept', 'application/json')
.get("/test-folder-9")
.set("Accept", "application/json")
.expect(200)
.expect('Content-Type', /json/)
.expect("Content-Type", /json/)
.then((res) => {
const data = JSON.parse(res.text)
expect(data).to.deep.include(
{
url: '/test-folder-9',
title: 'Home article 10 for test folder 9',
lastUpdatedBy: 'Foo Bar',
modifiedAt: '2018-03-02T14:13:20.000Z',
createdAt: '2018-02-19T00:26:40.000Z',
id: 'Test10',
resourceType: 'document',
content: '<p> This is a simple test document export.</p>',
byline: 'John Smith',
createdBy: 'John Smith',
sections: []
}
)
})
})
const data = JSON.parse(res.text);
expect(data).to.deep.include({
url: "/test-folder-9",
title: "Home article 10 for test folder 9",
lastUpdatedBy: "Foo Bar",
modifiedAt: "2018-03-02T14:13:20.000Z",
createdAt: "2018-02-19T00:26:40.000Z",
id: "Test10",
resourceType: "document",
content: "<p> This is a simple test document export.</p>",
byline: "John Smith",
createdBy: "John Smith",
sections: [],
});
});
});

it('folder with home doc should render the doc (.json suffix)', () => {
it("folder with home doc should render the doc (.json suffix)", () => {
return request(app)
.get('/test-folder-9.json')
.get("/test-folder-9.json")
.expect(200)
.expect('Content-Type', /json/)
.expect("Content-Type", /json/)
.then((res) => {
const data = JSON.parse(res.text)
expect(data).to.deep.include(
{
url: '/test-folder-9',
title: 'Home article 10 for test folder 9',
lastUpdatedBy: 'Foo Bar',
modifiedAt: '2018-03-02T14:13:20.000Z',
createdAt: '2018-02-19T00:26:40.000Z',
id: 'Test10',
resourceType: 'document',
content: '<p> This is a simple test document export.</p>',
byline: 'John Smith',
createdBy: 'John Smith',
sections: []
}
)
})
})
})
})
const data = JSON.parse(res.text);
expect(data).to.deep.include({
url: "/test-folder-9",
title: "Home article 10 for test folder 9",
lastUpdatedBy: "Foo Bar",
modifiedAt: "2018-03-02T14:13:20.000Z",
createdAt: "2018-02-19T00:26:40.000Z",
id: "Test10",
resourceType: "document",
content: "<p> This is a simple test document export.</p>",
byline: "John Smith",
createdBy: "John Smith",
sections: [],
});
});
});
});
});
Loading