Skip to content

Commit

Permalink
Merge pull request anuraghazra#117 from anuraghazra/custom-cache
Browse files Browse the repository at this point in the history
feat: added ability to set custom cache
  • Loading branch information
anuraghazra authored Jul 20, 2020
2 parents 9fb28c9 + fdf445d commit a5fa1a0
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 34 deletions.
17 changes: 15 additions & 2 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
require("dotenv").config();
const { renderError, parseBoolean } = require("../src/utils");
const {
renderError,
parseBoolean,
clampValue,
CONSTANTS,
} = require("../src/utils");
const fetchStats = require("../src/fetchStats");
const renderStatsCard = require("../src/renderStatsCard");

Expand All @@ -17,10 +22,10 @@ module.exports = async (req, res) => {
text_color,
bg_color,
theme,
cache_seconds,
} = req.query;
let stats;

res.setHeader("Cache-Control", "public, max-age=1800");
res.setHeader("Content-Type", "image/svg+xml");

try {
Expand All @@ -29,6 +34,14 @@ module.exports = async (req, res) => {
return res.send(renderError(err.message));
}

const cacheSeconds = clampValue(
parseInt(cache_seconds || CONSTANTS.THIRTY_MINUTES, 10),
CONSTANTS.THIRTY_MINUTES,
CONSTANTS.ONE_DAY
);

res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`);

res.send(
renderStatsCard(stats, {
hide: JSON.parse(hide || "[]"),
Expand Down
30 changes: 28 additions & 2 deletions api/pin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
require("dotenv").config();
const { renderError, parseBoolean } = require("../src/utils");
const {
renderError,
parseBoolean,
clampValue,
CONSTANTS,
} = require("../src/utils");
const fetchRepo = require("../src/fetchRepo");
const renderRepoCard = require("../src/renderRepoCard");

Expand All @@ -13,11 +18,11 @@ module.exports = async (req, res) => {
bg_color,
theme,
show_owner,
cache_seconds,
} = req.query;

let repoData;

res.setHeader("Cache-Control", "public, max-age=1800");
res.setHeader("Content-Type", "image/svg+xml");

try {
Expand All @@ -27,6 +32,27 @@ module.exports = async (req, res) => {
return res.send(renderError(err.message));
}

let cacheSeconds = clampValue(
parseInt(cache_seconds || CONSTANTS.THIRTY_MINUTES, 10),
CONSTANTS.THIRTY_MINUTES,
CONSTANTS.ONE_DAY
);

/*
if star count & fork count is over 1k then we are kFormating the text
and if both are zero we are not showing the stats
so we can just make the cache longer, since there is no need to frequent updates
*/
const stars = repoData.stargazers.totalCount;
const forks = repoData.forkCount;
const isBothOver1K = stars > 1000 && forks > 1000;
const isBothUnder1 = stars < 1 && forks < 1;
if (!cache_seconds && (isBothOver1K || isBothUnder1)) {
cacheSeconds = CONSTANTS.TWO_HOURS;
}

res.setHeader("Cache-Control", `public, max-age=${cacheSeconds}`);

res.send(
renderRepoCard(repoData, {
title_color,
Expand Down
2 changes: 1 addition & 1 deletion src/renderRepoCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const renderRepoCard = (repo, options = {}) => {
`;

const svgForks =
totalForks > 0 &&
forkCount > 0 &&
`
<svg class="icon" y="-12" viewBox="0 0 16 16" version="1.1" width="16" height="16">
${icons.fork}
Expand Down
12 changes: 12 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ function parseBoolean(value) {
}
}

function clampValue(number, min, max) {
return Math.max(min, Math.min(number, max));
}

function fallbackColor(color, fallbackColor) {
return (isValidHexColor(color) && `#${color}`) || fallbackColor;
}
Expand Down Expand Up @@ -112,6 +116,12 @@ function getCardColors({
return { titleColor, iconColor, textColor, bgColor };
}

const CONSTANTS = {
THIRTY_MINUTES: 1800,
TWO_HOURS: 7200,
ONE_DAY: 86400,
};

module.exports = {
renderError,
kFormatter,
Expand All @@ -122,4 +132,6 @@ module.exports = {
fallbackColor,
FlexLayout,
getCardColors,
clampValue,
CONSTANTS,
};
107 changes: 78 additions & 29 deletions tests/api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const axios = require("axios");
const MockAdapter = require("axios-mock-adapter");
const api = require("../api/index");
const renderStatsCard = require("../src/renderStatsCard");
const { renderError } = require("../src/utils");
const { renderError, CONSTANTS } = require("../src/utils");
const calculateRank = require("../src/calculateRank");

const stats = {
Expand Down Expand Up @@ -55,22 +55,29 @@ const error = {

const mock = new MockAdapter(axios);

const faker = (query, data) => {
const req = {
query: {
username: "anuraghazra",
...query,
},
};
const res = {
setHeader: jest.fn(),
send: jest.fn(),
};
mock.onPost("https://api.github.com/graphql").reply(200, data);

return { req, res };
};

afterEach(() => {
mock.reset();
});

describe("Test /api/", () => {
it("should test the request", async () => {
const req = {
query: {
username: "anuraghazra",
},
};
const res = {
setHeader: jest.fn(),
send: jest.fn(),
};
mock.onPost("https://api.github.com/graphql").reply(200, data);
const { req, res } = faker({}, data);

await api(req, res);

Expand All @@ -79,16 +86,7 @@ describe("Test /api/", () => {
});

it("should render error card on error", async () => {
const req = {
query: {
username: "anuraghazra",
},
};
const res = {
setHeader: jest.fn(),
send: jest.fn(),
};
mock.onPost("https://api.github.com/graphql").reply(200, error);
const { req, res } = faker({}, error);

await api(req, res);

Expand All @@ -97,8 +95,8 @@ describe("Test /api/", () => {
});

it("should get the query options", async () => {
const req = {
query: {
const { req, res } = faker(
{
username: "anuraghazra",
hide: `["issues","prs","contribs"]`,
show_icons: true,
Expand All @@ -109,12 +107,8 @@ describe("Test /api/", () => {
text_color: "fff",
bg_color: "fff",
},
};
const res = {
setHeader: jest.fn(),
send: jest.fn(),
};
mock.onPost("https://api.github.com/graphql").reply(200, data);
data
);

await api(req, res);

Expand All @@ -132,4 +126,59 @@ describe("Test /api/", () => {
})
);
});

it("should have proper cache", async () => {
const { req, res } = faker({}, data);
mock.onPost("https://api.github.com/graphql").reply(200, data);

await api(req, res);

expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
["Cache-Control", `public, max-age=${CONSTANTS.THIRTY_MINUTES}`],
]);
});

it("should set proper cache", async () => {
const { req, res } = faker({ cache_seconds: 2000 }, data);
await api(req, res);

expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
["Cache-Control", `public, max-age=${2000}`],
]);
});

it("should set proper cache with clamped values", async () => {
{
let { req, res } = faker({ cache_seconds: 200000 }, data);
await api(req, res);

expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
["Cache-Control", `public, max-age=${CONSTANTS.ONE_DAY}`],
]);
}

// note i'm using block scoped vars
{
let { req, res } = faker({ cache_seconds: 0 }, data);
await api(req, res);

expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
["Cache-Control", `public, max-age=${CONSTANTS.THIRTY_MINUTES}`],
]);
}

{
let { req, res } = faker({ cache_seconds: -10000 }, data);
await api(req, res);

expect(res.setHeader.mock.calls).toEqual([
["Content-Type", "image/svg+xml"],
["Cache-Control", `public, max-age=${CONSTANTS.THIRTY_MINUTES}`],
]);
}
});
});

0 comments on commit a5fa1a0

Please sign in to comment.