From b8182c4eb5a8caf2f5014c1246b5b84d4bc3821e Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Tue, 2 Feb 2021 14:05:01 +0100 Subject: [PATCH] Improve mocking and debugging with web instance (#91) --- CONTRIBUTING.md | 2 +- .../listEventsForAuthenticatedUser.mjs} | 1 + .../rest/{ratelimit.mjs => rateLimit/get.mjs} | 0 .../getContributorsStats.mjs} | 0 .../rest/{views.mjs => repos/getViews.mjs} | 0 .../{commits.mjs => repos/listCommits.mjs} | 0 .../listContributors.mjs} | 0 .../api/github/rest/{raw.mjs => request.mjs} | 0 .../{username.mjs => users/getByUsername.mjs} | 0 source/app/mocks/index.mjs | 31 +++++++-------- source/app/web/instance.mjs | 39 +++++++++++-------- source/app/web/settings.example.json | 3 +- 12 files changed, 40 insertions(+), 36 deletions(-) rename source/app/mocks/api/github/rest/{events.mjs => activity/listEventsForAuthenticatedUser.mjs} (98%) rename source/app/mocks/api/github/rest/{ratelimit.mjs => rateLimit/get.mjs} (100%) rename source/app/mocks/api/github/rest/{stats.mjs => repos/getContributorsStats.mjs} (100%) rename source/app/mocks/api/github/rest/{views.mjs => repos/getViews.mjs} (100%) rename source/app/mocks/api/github/rest/{commits.mjs => repos/listCommits.mjs} (100%) rename source/app/mocks/api/github/rest/{contributors.mjs => repos/listContributors.mjs} (100%) rename source/app/mocks/api/github/rest/{raw.mjs => request.mjs} (100%) rename source/app/mocks/api/github/rest/{username.mjs => users/getByUsername.mjs} (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dbb8026c..329b90d3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -587,7 +587,7 @@ Add them in [`source/app/mocks/api/`](/source/app/mocks/api) folder. If you're using `axios` or GitHub GraphQL API, these files are autoloaded so you just need to create new functions (see other mocked data for examples). -If you're using GitHub REST API, you'll also need to edit [`source/app/mocks/index.mjs`](/source/app/mocks/index.mjs) to add a new proxied method. +If you're using GitHub REST API, add your mocks in [`source/app/mocks/rest`](/source/app/mocks/rest) with same path as octokit. diff --git a/source/app/mocks/api/github/rest/events.mjs b/source/app/mocks/api/github/rest/activity/listEventsForAuthenticatedUser.mjs similarity index 98% rename from source/app/mocks/api/github/rest/events.mjs rename to source/app/mocks/api/github/rest/activity/listEventsForAuthenticatedUser.mjs index 1f3acd16..aa036b15 100644 --- a/source/app/mocks/api/github/rest/events.mjs +++ b/source/app/mocks/api/github/rest/activity/listEventsForAuthenticatedUser.mjs @@ -261,6 +261,7 @@ { sha:"MOCKED_SHA", message:faker.lorem.sentence(), + url:"https://api.github.com/repos/lowlighter/metrics/commits/MOCKED_SHA", } ] }, diff --git a/source/app/mocks/api/github/rest/ratelimit.mjs b/source/app/mocks/api/github/rest/rateLimit/get.mjs similarity index 100% rename from source/app/mocks/api/github/rest/ratelimit.mjs rename to source/app/mocks/api/github/rest/rateLimit/get.mjs diff --git a/source/app/mocks/api/github/rest/stats.mjs b/source/app/mocks/api/github/rest/repos/getContributorsStats.mjs similarity index 100% rename from source/app/mocks/api/github/rest/stats.mjs rename to source/app/mocks/api/github/rest/repos/getContributorsStats.mjs diff --git a/source/app/mocks/api/github/rest/views.mjs b/source/app/mocks/api/github/rest/repos/getViews.mjs similarity index 100% rename from source/app/mocks/api/github/rest/views.mjs rename to source/app/mocks/api/github/rest/repos/getViews.mjs diff --git a/source/app/mocks/api/github/rest/commits.mjs b/source/app/mocks/api/github/rest/repos/listCommits.mjs similarity index 100% rename from source/app/mocks/api/github/rest/commits.mjs rename to source/app/mocks/api/github/rest/repos/listCommits.mjs diff --git a/source/app/mocks/api/github/rest/contributors.mjs b/source/app/mocks/api/github/rest/repos/listContributors.mjs similarity index 100% rename from source/app/mocks/api/github/rest/contributors.mjs rename to source/app/mocks/api/github/rest/repos/listContributors.mjs diff --git a/source/app/mocks/api/github/rest/raw.mjs b/source/app/mocks/api/github/rest/request.mjs similarity index 100% rename from source/app/mocks/api/github/rest/raw.mjs rename to source/app/mocks/api/github/rest/request.mjs diff --git a/source/app/mocks/api/github/rest/username.mjs b/source/app/mocks/api/github/rest/users/getByUsername.mjs similarity index 100% rename from source/app/mocks/api/github/rest/username.mjs rename to source/app/mocks/api/github/rest/users/getByUsername.mjs diff --git a/source/app/mocks/index.mjs b/source/app/mocks/index.mjs index 93a05749..e4886bc2 100644 --- a/source/app/mocks/index.mjs +++ b/source/app/mocks/index.mjs @@ -60,25 +60,20 @@ { //Unmocked console.debug(`metrics/compute/mocks > mocking rest api`) - const unmocked = { - request:rest.request, - rateLimit:rest.rateLimit.get, - listEventsForAuthenticatedUser:rest.activity.listEventsForAuthenticatedUser, - getViews:rest.repos.getViews, - getContributorsStats:rest.repos.getContributorsStats, - listCommits:rest.repos.listCommits, - listContributors:rest.repos.listContributors, - getByUsername:rest.users.getByUsername, - } + const unmocked = {} //Mocked - rest.request = new Proxy(unmocked.request, {apply:mocks.github.rest.raw.bind(null, {faker})}) - rest.rateLimit.get = new Proxy(unmocked.rateLimit, {apply:mocks.github.rest.ratelimit.bind(null, {faker})}) - rest.activity.listEventsForAuthenticatedUser = new Proxy(unmocked.listEventsForAuthenticatedUser, {apply:mocks.github.rest.events.bind(null, {faker})}) - rest.repos.getViews = new Proxy(unmocked.getViews, {apply:mocks.github.rest.views.bind(null, {faker})}) - rest.repos.getContributorsStats = new Proxy(unmocked.getContributorsStats, {apply:mocks.github.rest.stats.bind(null, {faker})}) - rest.repos.listCommits = new Proxy(unmocked.listCommits, {apply:mocks.github.rest.commits.bind(null, {faker})}) - rest.repos.listContributors = new Proxy(unmocked.listContributors, {apply:mocks.github.rest.contributors.bind(null, {faker})}) - rest.users.getByUsername = new Proxy(unmocked.getByUsername, {apply:mocks.github.rest.username.bind(null, {faker})}) + const mocker = ({path = "rest", mocks, mocked}) => { + for (const [key, value] of Object.entries(mocks)) { + console.debug(`metrics/compute/mocks > mocking rest api > mocking ${path}.${key}`) + if (typeof value === "function") { + unmocked[path] = value + mocked[key] = new Proxy(unmocked[path], {apply:value.bind(null, {faker})}) + } + else + mocker({path:`${path}.${key}`, mocks:mocks[key], mocked:mocked[key]}) + } + } + mocker({mocks:mocks.github.rest, mocked:rest}) } //Axios mocking diff --git a/source/app/web/instance.mjs b/source/app/web/instance.mjs index eed6203b..6298f7ce 100644 --- a/source/app/web/instance.mjs +++ b/source/app/web/instance.mjs @@ -18,25 +18,32 @@ const {token, maxusers = 0, restricted = [], debug = false, cached = 30*60*1000, port = 3000, ratelimiter = null, plugins = null} = conf.settings mock = mock || conf.settings.mocked - //Apply configuration mocking if needed - if (mock) { - console.debug(`metrics/app > using mocked settings`) - const {settings} = conf - //Mock token if it's undefined - if (!settings.token) - settings.token = (console.debug(`metrics/app > using mocked token`), "MOCKED_TOKEN") + //Process mocking and default plugin state + for (const plugin of Object.keys(Plugins).filter(x => !["base", "core"].includes(x))) { + //Initialization + const {settings} = conf + if (!settings.plugins[plugin]) + settings.plugins[plugin] = {} + //Auto-enable plugin if needed + if (conf.settings["plugins.default"]) + settings.plugins[plugin].enabled = settings.plugins[plugin].enabled ?? (console.debug(`metrics/app > auto-enabling ${plugin}`), true) //Mock plugins state and tokens if they're undefined - for (const plugin of Object.keys(Plugins)) { - if (!settings.plugins[plugin]) - settings.plugins[plugin] = {} - settings.plugins[plugin].enabled = settings.plugins[plugin].enabled ?? (console.debug(`metrics/app > using mocked token enable state for ${plugin}`), true) - if (["tweets", "pagespeed"].includes(plugin)) - settings.plugins[plugin].token = settings.plugins[plugin].token ?? (console.debug(`metrics/app > using mocked token for ${plugin}`), "MOCKED_TOKEN") - if (["music"].includes(plugin)) - settings.plugins[plugin].token = settings.plugins[plugin].token ?? (console.debug(`metrics/app > using mocked token for ${plugin}`), "MOCKED_CLIENT_ID, MOCKED_CLIENT_SECRET, MOCKED_REFRESH_TOKEN") + if (mock) { + const tokens = Object.entries(conf.metadata.plugins[plugin].inputs).filter(([key, value]) => (!/^plugin_/.test(key))&&(value.type === "token")).map(([key]) => key) + for (const token of tokens) { + if ((!settings.plugins[plugin][token])||(mock === "force")) { + console.debug(`metrics/app > using mocked token for ${plugin}.${token}`) + settings.plugins[plugin][token] = "MOCKED_TOKEN" + } + } } - console.debug(util.inspect(settings, {depth:Infinity, maxStringLength:256})) } + if (((mock)&&(!conf.settings.token))||(mock === "force")) { + console.debug(`metrics/app > using mocked token`) + conf.settings.token = "MOCKED_TOKEN" + } + if (debug) + console.debug(util.inspect(conf.settings, {depth:Infinity, maxStringLength:256})) //Load octokits const api = {graphql:octokit.graphql.defaults({headers:{authorization: `token ${token}`}}), rest:new OctokitRest.Octokit({auth:token})} diff --git a/source/app/web/settings.example.json b/source/app/web/settings.example.json index 5cac435c..dd9bf3d7 100644 --- a/source/app/web/settings.example.json +++ b/source/app/web/settings.example.json @@ -10,7 +10,7 @@ "port": 3000, "//": "Listening port", "optimize": true, "//": "SVG optimization", "debug": false, "//": "Debug logs", - "mocked": false, "//": "Use mocked data instead of live APIs", + "mocked": false, "//": "Use mocked data instead of live APIs (use 'force' to use mocked token even if real token are defined)", "repositories": 100, "//": "Number of repositories to use", "community": { "templates": [], "//": "Additional community templates to setup" @@ -19,6 +19,7 @@ "default": "classic", "//": "Default template", "enabled": [], "//": "Enabled templates (empty to enable all)" }, + "plugins.default": false, "//": "Default plugin state (advised to let 'false' unless in debug mode)", "plugins": { "//": "Global plugin configuration", <% for (const name of Object.keys(plugins).filter(v => !["base", "core"].includes(v))) { -%> "<%= name %>":{