fix(appium,support): re-enable log-filters
server option `log-filters` is now supported via embedding in Appium config files _or_ via CLI using an external JSON file.
example fixtures included.
Note that the `Rule` type has been replaced with the `LogFilter` type automatically generated from the schema (see previous commit).
MODIFY
packages/appium/test/e2e/config-file.e2e.spec.js
packages/appium/test/e2e/config-file.e2e.spec.js
@@ -5,20 +5,21 @@ import {readConfigFile} from '../../lib/config-file';
import {finalizeSchema, registerSchema, resetSchema} from '../../lib/schema/schema';
import extSchema from '../fixtures/driver-schema';
import {resolveFixture} from '../helpers';
+import _ from 'lodash';
+
+const resolveConfigFixture = _.partial(resolveFixture, 'config');
describe('config file behavior', function () {
- const GOOD_FILEPATH = resolveFixture('config', 'appium-config-good.json');
- const BAD_NODECONFIG_FILEPATH = resolveFixture('config', 'appium-config-bad-nodeconfig.json');
- const BAD_FILEPATH = resolveFixture('config', 'appium-config-bad.json');
- const INVALID_JSON_FILEPATH = resolveFixture('config', 'appium-config-invalid.json');
- const SECURITY_ARRAY_FILEPATH = resolveFixture('config', 'appium-config-security-array.json');
- const SECURITY_DELIMITED_FILEPATH = resolveFixture(
- 'config',
- 'appium-config-security-delimited.json'
- );
- const SECURITY_PATH_FILEPATH = resolveFixture('config', 'appium-config-security-path.json');
- const UNKNOWN_PROPS_FILEPATH = resolveFixture('config', 'appium-config-ext-unknown-props.json');
- const EXT_PROPS_FILEPATH = resolveFixture('config', 'appium-config-ext-good.json');
+ const GOOD_FILEPATH = resolveConfigFixture('appium-config-good.json');
+ const BAD_NODECONFIG_FILEPATH = resolveConfigFixture('appium-config-bad-nodeconfig.json');
+ const BAD_FILEPATH = resolveConfigFixture('appium-config-bad.json');
+ const INVALID_JSON_FILEPATH = resolveConfigFixture('appium-config-invalid.json');
+ const SECURITY_ARRAY_FILEPATH = resolveConfigFixture('appium-config-security-array.json');
+ const SECURITY_DELIMITED_FILEPATH = resolveConfigFixture('appium-config-security-delimited.json');
+ const SECURITY_PATH_FILEPATH = resolveConfigFixture('appium-config-security-path.json');
+ const UNKNOWN_PROPS_FILEPATH = resolveConfigFixture('appium-config-ext-unknown-props.json');
+ const EXT_PROPS_FILEPATH = resolveConfigFixture('appium-config-ext-good.json');
+ const LOG_FILTERS_FILEPATH = resolveConfigFixture('appium-config-log-filters.json');
beforeEach(function () {
finalizeSchema();
@@ -71,7 +72,7 @@ describe('config file behavior', function () {
});
});
- describe('server.nodeconfig behavior', function () {
+ describe('`server.nodeconfig` behavior', function () {
describe('when a string', function () {
it('should return errors', async function () {
const result = await readConfigFile(BAD_NODECONFIG_FILEPATH);
@@ -87,7 +88,7 @@ describe('config file behavior', function () {
});
});
- describe('server.allow-insecure behavior', function () {
+ describe('`server.allow-insecure` behavior', function () {
describe('when a string path', function () {
it('should return errors', async function () {
const result = await readConfigFile(SECURITY_PATH_FILEPATH);
@@ -117,6 +118,26 @@ describe('config file behavior', function () {
});
});
});
+
+ describe('`server.log-filters` behavior', function () {
+ describe('when the log filters are valid', function () {
+ it('should return a valid config object', async function () {
+ const result = await readConfigFile(LOG_FILTERS_FILEPATH);
+ result.should.deep.equal({
+ config: {
+ server: {
+ logFilters: [
+ {text: 'foo', replacer: 'bar'},
+ {pattern: '/foo/', flags: 'i'},
+ ],
+ },
+ },
+ filepath: LOG_FILTERS_FILEPATH,
+ errors: [],
+ });
+ });
+ });
+ });
});
describe('when the config file is invalid per the schema', function () {

ADD
packages/appium/test/fixtures/config/appium-config-log-filters.json
+{
+ "server": {
+ "log-filters": [
+ {
+ "text": "foo",
+ "replacer": "bar"
+ },
+ {
+ "pattern": "/foo/",
+ "flags": "i"
+ }
+ ]
+ }
+}

ADD
packages/appium/test/fixtures/log-filters.json
+[
+ {
+ "text": "foo",
+ "replacer": "bar"
+ },
+ {
+ "pattern": "/foo/",
+ "flags": "i"
+ }
+]

MODIFY
packages/appium/test/unit/parser.spec.js
packages/appium/test/unit/parser.spec.js
@@ -9,6 +9,7 @@ import {resolveFixture} from '../helpers';
const ALLOW_FIXTURE = resolveFixture('allow-feat.txt');
const DENY_FIXTURE = resolveFixture('deny-feat.txt');
const CAPS_FIXTURE = resolveFixture('caps.json');
+const LOG_FILTERS_FIXTURE = resolveFixture('log-filters.json');
describe('parser', function () {
let p;
@@ -152,6 +153,10 @@ describe('parser', function () {
it('should recognize --log-level', function () {
p.parseArgs(['--log-level', 'debug']).should.have.property('loglevel', 'debug');
});
+
+ it('should parse a file for --log-filters', function () {
+ p.parseArgs(['--log-filters', LOG_FILTERS_FIXTURE]).should.have.property('logFilters');
+ });
});
describe('extension arguments', function () {

MODIFY
packages/support/lib/log-internal.js
packages/support/lib/log-internal.js
@@ -3,6 +3,15 @@ import _ from 'lodash';
const DEFAULT_REPLACER = '**SECURE**';
+/**
+ * Type guard for log filter type
+ * @param {object} value
+ * @returns {value is import('@appium/types').LogFilterRegex}
+ */
+function isLogFilterRegex(value) {
+ return 'pattern' in value;
+}
+
class SecureValuesPreprocessor {
constructor() {
this._rules = [];
@@ -19,7 +28,7 @@ class SecureValuesPreprocessor {
/**
* Parses single rule from the given JSON file
*
- * @param {string|Rule} rule The rule might either be represented as a single string
+ * @param {string|import('@appium/types').LogFilter} rule The rule might either be represented as a single string
* or a configuration object
* @throws {Error} If there was an error while parsing the rule
* @returns {SecureValuePreprocessingRule} The parsed rule
@@ -34,7 +43,7 @@ class SecureValuesPreprocessor {
}
pattern = `\\b${_.escapeRegExp(rule)}\\b`;
} else if (_.isPlainObject(rule)) {
- if (_.has(rule, 'pattern')) {
+ if (isLogFilterRegex(rule)) {
if (!_.isString(rule.pattern) || rule.pattern.length === 0) {
throw new Error(
`${JSON.stringify(rule)} -> The value of 'pattern' must be a valid non-empty string`
@@ -81,7 +90,7 @@ class SecureValuesPreprocessor {
/**
* Loads rules from the given JSON file
*
- * @param {string|string[]|Rule[]} source The full path to the JSON file containing secure
+ * @param {string|string[]|import('@appium/types').LogFiltersConfig} source The full path to the JSON file containing secure
* values replacement rules or the rules themselves represented as an array
* @throws {Error} If the format of the source file is invalid or
* it does not exist
@@ -144,19 +153,6 @@ const SECURE_VALUES_PREPROCESSOR = new SecureValuesPreprocessor();
export {SECURE_VALUES_PREPROCESSOR, SecureValuesPreprocessor};
export default SECURE_VALUES_PREPROCESSOR;
-/**
- * @typedef Rule
- * @property {string} pattern A valid RegExp pattern to be replaced
- * @property {string} text A text match to replace. Either this property or the
- * above one must be provided. `pattern` has priority over `text` if both are provided.
- * @property {string} [flags] Regular expression flags for the given pattern.
- * Supported flag are the same as for the standard JavaScript RegExp constructor:
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2
- * The 'g' (global matching) is always enabled though.
- * @property {string} [replacer] The replacer value to use. By default
- * equals to `DEFAULT_SECURE_REPLACER`
- */
-
/**
* @typedef SecureValuePreprocessingRule
* @property {RegExp} pattern The parsed pattern which is going to be used for replacement

MODIFY
packages/support/lib/logging.js
packages/support/lib/logging.js
@@ -137,10 +137,9 @@ function getLogger(prefix = null) {
* appear in Appium logs.
* Each call to this method replaces the previously loaded rules if any existed.
*
- * @param {string|string[]|import('./log-internal').Rule[]} rulesJsonPath The full path to the JSON file containing
+ * @param {string|string[]|import('@appium/types').LogFiltersConfig} rulesJsonPath The full path to the JSON file containing
* the replacement rules. Each rule could either be a string to be replaced
- * or an object with predefined properties. See the `Rule` type definition in
- * `log-internals.js` to get more details on its format.
+ * or an object with predefined properties.
* @throws {Error} If the given file cannot be loaded
* @returns {Promise<LoadResult>}
*/

MODIFY
packages/support/test/unit/log-internals.spec.js
packages/support/test/unit/log-internals.spec.js
@@ -6,6 +6,7 @@ import {SecureValuesPreprocessor} from '../../lib/log-internal';
const CONFIG_PATH = path.resolve(os.tmpdir(), 'rules.json');
describe('Log Internals', function () {
+ /** @type {import('../../lib/log-internal').SecureValuesPreprocessor} */
let preprocessor;
beforeEach(function () {
@@ -45,6 +46,7 @@ describe('Log Internals', function () {
});
it(`should preprocess a string and apply a rule where 'pattern' has priority over 'text'`, async function () {
+ // NOTE: this is disallowed in the config schema, but is currently allowed when using an external JSON file.
const replacer = '***';
const issues = await preprocessor.loadRules([{pattern: '^:', text: 'yo', replacer}]);
issues.length.should.eql(0);

fix(appium,support): re-enable log-filters

server option `log-filters` is now supported via embedding in Appium config files _or_ via CLI using an external JSON file.

example fixtures included.

Note that the `Rule` type has been replaced with the `LogFilter` type automatically generated from the schema (see previous commit).