Skip to content

Commit

Permalink
feat: add user assigned mock geo for edge local dev (#4708)
Browse files Browse the repository at this point in the history
* feat: add user assigned mock geo for edge local dev

* feat: add user assigned mock geo for edge local dev

* feat: add user assigned mock geo for edge local dev

* fix: fix dot diff in test

* fix: change regex to remove loading dots

* fix: revert change

* feat: alternate approach using CLI flag

* fix: remove unneeded imports

* chore: update docs

* fix: add update command to allowables in validation

* fix: fix logic error

* feat: add cli flag for geo country

* Update src/commands/dev/dev.js

Co-authored-by: Eduardo BouΓ§as <[email protected]>

* chore: npm run docs

* fix: update mock location defaults

* chore: merge main

* chore: merge main

* chore: clean up code

* fix: remove unnecessary prop

* fix: add tests, refactor code

* fix: remove unneccessary lines

* fix: ignore geo flag when passing country flag

* fix: update docs/add link to country codes

* chore: update docs in right place this time

* chore: fix parenthesis

* chore: update contributors field

* fix: rename mock props, update doc line

* fix: update test

* chore: update contributors field

* chore: update contributors field

* Update docs/commands/dev.md

Co-authored-by: Daniel Tschinder <[email protected]>

* Update src/commands/dev/dev.js

Co-authored-by: Daniel Tschinder <[email protected]>

* chore: update contributors field

* chore: npm run docs

Co-authored-by: Eduardo BouΓ§as <[email protected]>
Co-authored-by: JWhist <[email protected]>
Co-authored-by: token-generator-app[bot] <token-generator-app[bot]@users.noreply.github.com>
Co-authored-by: Daniel Tschinder <[email protected]>
  • Loading branch information
5 people authored Jul 11, 2022
1 parent 46168f1 commit f17b8a3
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 12 deletions.
1 change: 1 addition & 0 deletions docs/commands/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ netlify dev
**Flags**

- `command` (*string*) - command to run
- `country` (*string*) - Two-letter country code (ISO 3166-1 alpha-2, https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements) to use as mock geolocation (enables --geo=mock autmatically)
- `dir` (*string*) - dir with static files
- `edgeInspect` (*string*) - enable the V8 Inspector Protocol for Edge Functions, with an optional address in the host:port format
- `edgeInspectBrk` (*string*) - enable the V8 Inspector Protocol for Edge Functions and pause execution on the first line of code, with an optional address in the host:port format
Expand Down
23 changes: 23 additions & 0 deletions src/commands/dev/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
* @param {InspectSettings} params.inspectSettings
* @param {() => Promise<object>} params.getUpdatedConfig
* @param {string} params.geolocationMode
* @param {string} params.geoCountry
* @param {*} params.settings
* @param {boolean} params.offline
* @param {*} params.site
Expand All @@ -243,6 +244,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
const startProxyServer = async ({
addonsUrls,
config,
geoCountry,
geolocationMode,
getUpdatedConfig,
inspectSettings,
Expand All @@ -256,6 +258,7 @@ const startProxyServer = async ({
config,
configPath: site.configPath,
geolocationMode,
geoCountry,
getUpdatedConfig,
inspectSettings,
offline,
Expand Down Expand Up @@ -386,6 +389,19 @@ const validateShortFlagArgs = (args) => {
return args
}

const validateGeoCountryCode = (arg) => {
// Validate that the arg passed is two letters only for country
// See https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
if (!/^[a-z]{2}$/i.test(arg)) {
throw new Error(
`The geo country code must use a two letter abbreviation.
${chalk.red(BANG)} Example:
netlify dev --geo=mock --country=FR`,
)
}
return arg.toUpperCase()
}

/**
* The dev command
* @param {import('commander').OptionValues} options
Expand Down Expand Up @@ -460,6 +476,7 @@ const dev = async (options, command) => {
addonsUrls,
config,
geolocationMode: options.geo,
geoCountry: options.country,
getUpdatedConfig,
inspectSettings,
offline: options.offline,
Expand Down Expand Up @@ -599,6 +616,12 @@ const createDevCommand = (program) => {
.choices(['cache', 'mock', 'update'])
.default('cache'),
)
.addOption(
new Option(
'--country <geoCountry>',
'Two-letter country code (ISO 3166-1 alpha-2, https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements) to use as mock geolocation (enables --geo=mock autmatically)',
).argParser(validateGeoCountryCode),
)
.addOption(
new Option('--staticServerPort <port>', 'port of the static app server used when no framework is detected')
.argParser((value) => Number.parseInt(value))
Expand Down
3 changes: 2 additions & 1 deletion src/lib/edge-functions/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const handleProxyRequest = (req, proxyReq) => {
const initializeProxy = async ({
config,
configPath,
geoCountry,
geolocationMode,
getUpdatedConfig,
inspectSettings,
Expand Down Expand Up @@ -84,7 +85,7 @@ const initializeProxy = async ({
}

const [geoLocation, registry] = await Promise.all([
getGeoLocation({ mode: geolocationMode, offline, state }),
getGeoLocation({ mode: geolocationMode, geoCountry, offline, state }),
server,
])

Expand Down
28 changes: 17 additions & 11 deletions src/lib/geo-location.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const fetch = require('node-fetch')

const API_URL = 'https://netlifind.netlify.app'
const STATE_GEO_PROPERTY = 'geolocation'

// 24 hours
const CACHE_TTL = 8.64e7

Expand All @@ -17,12 +16,11 @@ const REQUEST_TIMEOUT = 1e4
* @property {object} country
* @property {string} country.code
* @property {string} country.name
* @property {object} country
* @property {string} country.code
* @property {string} country.name
* @property {object} subdivision
* @property {string} subdivision.code
* @property {string} subdivision.name
*/

// The default location to be used if we're unable to talk to the API.
const mockLocation = {
city: 'San Francisco',
country: { code: 'US', name: 'United States' },
Expand All @@ -34,13 +32,13 @@ const mockLocation = {
* location, depending on the mode selected.
*
* @param {object} params
* @param {string} params.geolocationMode
* @param {"cache"|"update"|"mock"} params.mode
* @param {string} params.geoCountry
* @param {boolean} params.offline
* @param {import('../utils/state-config').StateConfig} params.state
* @returns {Promise<GeoLocation>}
*/
const getGeoLocation = async ({ mode, offline, state }) => {
const getGeoLocation = async ({ geoCountry, mode, offline, state }) => {
const cacheObject = state.get(STATE_GEO_PROPERTY)

// If we have cached geolocation data and the `--geo` option is set to
Expand All @@ -56,10 +54,18 @@ const getGeoLocation = async ({ mode, offline, state }) => {
}
}

// If the `--geo` option is set to `mock`, we use the mock location. Also,
// if the `--offline` option was used, we can't talk to the API, so let's
// also use the mock location.
if (mode === 'mock' || offline) {
// If the `--geo` option is set to `mock`, we use the default mock location.
// If the `--offline` option was used, we can't talk to the API, so let's
// also use the mock location. Otherwise, use the country code passed in by
// the user.
if (mode === 'mock' || offline || geoCountry) {
if (geoCountry) {
return {
city: 'Mock City',
country: { code: geoCountry, name: 'Mock Country' },
subdivision: { code: 'SD', name: 'Mock Subdivision' },
}
}
return mockLocation
}

Expand Down
2 changes: 2 additions & 0 deletions src/utils/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ const startProxy = async function ({
addonsUrls,
config,
configPath,
geoCountry,
geolocationMode,
getUpdatedConfig,
inspectSettings,
Expand All @@ -478,6 +479,7 @@ const startProxy = async function ({
config,
configPath,
geolocationMode,
geoCountry,
getUpdatedConfig,
inspectSettings,
offline,
Expand Down
22 changes: 22 additions & 0 deletions tests/integration/660.command.dev.geo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const process = require('process')

const test = require('ava')

const callCli = require('./utils/call-cli')
const { withSiteBuilder } = require('./utils/site-builder')

test('should throw if invalid country arg is passed', async (t) => {
await withSiteBuilder('site-env', async (builder) => {
await builder.buildAsync()

const options = {
cwd: builder.directory,
extendEnv: false,
PATH: process.env.PATH,
}

await t.throwsAsync(() => callCli(['dev', '--geo=mock', '--country=a1'], options))
await t.throwsAsync(() => callCli(['dev', '--geo=mock', '--country=NotARealCountryCode'], options))
await t.throwsAsync(() => callCli(['dev', '--geo=mock', '--country='], options))
})
})
34 changes: 34 additions & 0 deletions tests/unit/lib/geo-location.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,37 @@ test('`getGeoLocation` returns mock geolocation data if `mode: "mock"`', async (
t.false(hasCalledStateSet)
t.deepEqual(geo, mockLocation)
})

test('`getGeoLocation` returns mock geolocation data if valid country code set', async (t) => {
const returnedLocation = {
city: 'Mock City',
country: { code: 'CA', name: 'Mock Country' },
subdivision: { code: 'SD', name: 'Mock Subdivision' },
}

const mockState = {
get() {},
set() {},
}

const geo = await getGeoLocation({ mode: 'mock', state: mockState, geoCountry: 'CA' })

t.deepEqual(geo, returnedLocation)
})

test('`getGeoLocation` mocks country code when not using mock flag', async (t) => {
const mockState = {
get() {},
set() {},
}

const returnedLocation = {
city: 'Mock City',
country: { code: 'CA', name: 'Mock Country' },
subdivision: { code: 'SD', name: 'Mock Subdivision' },
}

const geo = await getGeoLocation({ mode: 'update', offline: false, state: mockState, geoCountry: 'CA' })

t.deepEqual(geo, returnedLocation)
})

5 comments on commit f17b8a3

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“Š Benchmark results

Package size: 227 MB

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“Š Benchmark results

Package size: 227 MB

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“Š Benchmark results

Package size: 227 MB

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“Š Benchmark results

Package size: 227 MB

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“Š Benchmark results

Package size: 227 MB

Please sign in to comment.