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

More config v6 tests #102

Merged
merged 25 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
637c5ed
Add test for another special case of segment condition logging
adams85 Jan 29, 2024
f19837a
Add test for multi-level flag dependency
adams85 Jan 29, 2024
a008415
Add tests for comparison attribute and comparison value trimming
adams85 Jan 29, 2024
3dda451
Use valid SDK keys in cache key generation tests
adams85 Jan 29, 2024
f629050
Add tests for comparison attribute conversion to canonical string rep…
adams85 Jan 30, 2024
1ad6f9f
Simplify EvaluateContext + improve perf. of user attribute retrieval …
adams85 Feb 5, 2024
4523a3a
Bump version
adams85 Feb 5, 2024
24ef61d
Set eslint as default formatter for VSCode workspace
adams85 Feb 5, 2024
3cca96d
Minor corrections
adams85 Feb 6, 2024
4a2a836
Move isStringArray into Utils
adams85 Feb 6, 2024
3582e4c
Improve naming (use the term "match" in the context of targeting rule…
adams85 Feb 6, 2024
9771dae
Minor correction
adams85 Feb 7, 2024
f59c3da
Make line break char sequence configurable in log messages
adams85 Feb 8, 2024
c80110a
Minor corrections
adams85 Feb 8, 2024
8126420
Align config json error handling of EvaluateLogBuilder with error rep…
adams85 Feb 14, 2024
859a909
Improve naming
adams85 Feb 14, 2024
008a4df
Improve User Object tests
adams85 Feb 16, 2024
6153b8c
Add a few more test cases
adams85 Feb 29, 2024
0269d96
Correct visibility of appendTargetingRuleThenPart
adams85 Feb 29, 2024
19b6415
Minor corrections
adams85 Feb 29, 2024
06934d8
Correct grammar mistake
adams85 Mar 14, 2024
5dea1b6
Make naming of UserComparator member consistent
adams85 Mar 14, 2024
56fca53
Add tests for some number parsing edge cases
adams85 Mar 14, 2024
9f7c407
Adjust terminology to docs (eliminate the usage of term 'match' in th…
adams85 Mar 14, 2024
a3763ef
Bump version
adams85 Mar 21, 2024
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
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"editor.rulers": [160],
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"eslint.format.enable": true,
"eslint.validate": [
"typescript"
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "configcat-common",
"version": "9.2.0",
"version": "9.3.0",
"description": "ConfigCat is a configuration as a service that lets you manage your features and configurations without actually deploying new code.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
11 changes: 9 additions & 2 deletions src/ConfigCatLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export interface IConfigCatLogger {
/** Gets the log level (the minimum level to use for filtering log events). */
readonly level?: LogLevel;

/** Gets the character sequence to use for line breaks in log messages. Defaults to "\n". */
readonly eol?: string;

/**
* Writes an event into the log.
* @param level Event severity level.
Expand All @@ -79,6 +82,10 @@ export class LoggerWrapper implements IConfigCatLogger {
return this.logger.level ?? LogLevel.Warn;
}

get eol(): string {
return this.logger.eol ?? "\n";
}

constructor(
private readonly logger: IConfigCatLogger,
private readonly hooks?: SafeHooksWrapper) {
Expand Down Expand Up @@ -369,7 +376,7 @@ export class ConfigCatConsoleLogger implements IConfigCatLogger {
/**
* Create an instance of ConfigCatConsoleLogger
*/
constructor(public level = LogLevel.Warn) {
constructor(public level = LogLevel.Warn, readonly eol = "\n") {
}

/** @inheritdoc */
Expand All @@ -381,7 +388,7 @@ export class ConfigCatConsoleLogger implements IConfigCatLogger {
level === LogLevel.Error ? [console.error, "ERROR"] :
[console.log, LogLevel[level].toUpperCase()];

const exceptionString = exception !== void 0 ? "\n" + errorToString(exception, true) : "";
const exceptionString = exception !== void 0 ? this.eol + errorToString(exception, true) : "";

logMethod(`${this.SOURCE} - ${levelString} - [${eventId}] ${message}${exceptionString}`);
}
Expand Down
104 changes: 52 additions & 52 deletions src/ConfigJson.ts

Large diffs are not rendered by default.

77 changes: 46 additions & 31 deletions src/EvaluateLogBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PrerequisiteFlagComparator, SegmentComparator, UserComparator } from "./ConfigJson";
import type { PrerequisiteFlagCondition, SegmentCondition, SettingValue, TargetingRule, UserCondition, UserConditionUnion } from "./ProjectConfig";
import type { PrerequisiteFlagCondition, SegmentCondition, Setting, SettingValue, TargetingRule, UserCondition, UserConditionUnion } from "./ProjectConfig";
import { isAllowedValue } from "./RolloutEvaluator";
import { formatStringList, isArray } from "./Utils";
import { formatStringList, isArray, isStringArray } from "./Utils";

const invalidValuePlaceholder = "<invalid value>";
const invalidNamePlaceholder = "<invalid name>";
Expand All @@ -14,6 +14,9 @@
private log = "";
private indent = "";

constructor(private readonly eol: string) {
}

resetIndent(): this {
this.indent = "";
return this;
Expand All @@ -30,7 +33,7 @@
}

newLine(text?: string): this {
this.log += "\n" + this.indent + (text ?? "");
this.log += this.eol + this.indent + (text ?? "");
return this;
}

Expand All @@ -43,20 +46,20 @@
return this.log;
}

appendEvaluationResult(isMatch: boolean): this {
return this.append(`${isMatch}`);
}

private appendUserConditionCore(comparisonAttribute: string, comparator: UserComparator, comparisonValue?: unknown) {
return this.append(`User.${comparisonAttribute} ${formatUserComparator(comparator)} '${comparisonValue ?? invalidValuePlaceholder}'`);
}

private appendUserConditionString(comparisonAttribute: string, comparator: UserComparator, comparisonValue: string, isSensitive: boolean) {
if (typeof comparisonValue !== "string") {
return this.appendUserConditionCore(comparisonAttribute, comparator);

Check warning on line 55 in src/EvaluateLogBuilder.ts

View check run for this annotation

Codecov / codecov/patch

src/EvaluateLogBuilder.ts#L55

Added line #L55 was not covered by tests
}

return this.appendUserConditionCore(comparisonAttribute, comparator, !isSensitive ? comparisonValue : "<hashed value>");
}

private appendUserConditionStringList(comparisonAttribute: string, comparator: UserComparator, comparisonValue: ReadonlyArray<string>, isSensitive: boolean): this {
if (comparisonValue == null) {
if (!isStringArray(comparisonValue)) {
return this.appendUserConditionCore(comparisonAttribute, comparator);
}

Expand All @@ -74,7 +77,7 @@
}

private appendUserConditionNumber(comparisonAttribute: string, comparator: UserComparator, comparisonValue: number, isDateTime?: boolean) {
if (comparisonValue == null) {
if (typeof comparisonValue !== "number") {
return this.appendUserConditionCore(comparisonAttribute, comparator);
}

Expand All @@ -86,12 +89,14 @@
}

appendUserCondition(condition: UserConditionUnion): this {
const { comparisonAttribute, comparator } = condition;
const comparisonAttribute = typeof condition.comparisonAttribute === "string" ? condition.comparisonAttribute : invalidNamePlaceholder;
const comparator = condition.comparator;

switch (condition.comparator) {
case UserComparator.IsOneOf:
case UserComparator.IsNotOneOf:
case UserComparator.ContainsAnyOf:
case UserComparator.NotContainsAnyOf:
case UserComparator.TextIsOneOf:
case UserComparator.TextIsNotOneOf:
case UserComparator.TextContainsAnyOf:
case UserComparator.TextNotContainsAnyOf:
case UserComparator.SemVerIsOneOf:
case UserComparator.SemVerIsNotOneOf:
case UserComparator.TextStartsWithAnyOf:
Expand All @@ -118,8 +123,8 @@
case UserComparator.NumberGreaterOrEquals:
return this.appendUserConditionNumber(comparisonAttribute, comparator, condition.comparisonValue);

case UserComparator.SensitiveIsOneOf:
case UserComparator.SensitiveIsNotOneOf:
case UserComparator.SensitiveTextIsOneOf:
case UserComparator.SensitiveTextIsNotOneOf:
case UserComparator.SensitiveTextStartsWithAnyOf:
case UserComparator.SensitiveTextNotStartsWithAnyOf:
case UserComparator.SensitiveTextEndsWithAnyOf:
Expand All @@ -141,8 +146,12 @@
}
}

appendPrerequisiteFlagCondition(condition: PrerequisiteFlagCondition): this {
const prerequisiteFlagKey = condition.prerequisiteFlagKey;
appendPrerequisiteFlagCondition(condition: PrerequisiteFlagCondition, settings: Readonly<{ [name: string]: Setting }>): this {
const prerequisiteFlagKey =
typeof condition.prerequisiteFlagKey !== "string" ? invalidNamePlaceholder :
!(condition.prerequisiteFlagKey in settings) ? invalidReferencePlaceholder :
condition.prerequisiteFlagKey;

const comparator = condition.comparator;
const comparisonValue = condition.comparisonValue;

Expand All @@ -153,18 +162,24 @@
const segment = condition.segment;
const comparator = condition.comparator;

const segmentName = segment?.name ??
(segment == null ? invalidReferencePlaceholder : invalidNamePlaceholder);
const segmentName =
segment == null ? invalidReferencePlaceholder :
typeof segment.name !== "string" || !segment.name ? invalidNamePlaceholder :
segment.name;

return this.append(`User ${formatSegmentComparator(comparator)} '${segmentName}'`);
}

appendConditionConsequence(isMatch: boolean): this {
this.append(" => ").appendEvaluationResult(isMatch);
return isMatch ? this : this.append(", skipping the remaining AND conditions");
appendConditionResult(result: boolean): this {
return this.append(`${result}`);
}

appendConditionConsequence(result: boolean): this {
this.append(" => ").appendConditionResult(result);
return result ? this : this.append(", skipping the remaining AND conditions");
}

appendTargetingRuleThenPart(targetingRule: TargetingRule, newLine: boolean): this {
private appendTargetingRuleThenPart(targetingRule: TargetingRule, newLine: boolean): this {
(newLine ? this.newLine() : this.append(" "))
.append("THEN");

Expand All @@ -184,14 +199,14 @@

export function formatUserComparator(comparator: UserComparator): string {
switch (comparator) {
case UserComparator.IsOneOf:
case UserComparator.SensitiveIsOneOf:
case UserComparator.TextIsOneOf:
case UserComparator.SensitiveTextIsOneOf:
case UserComparator.SemVerIsOneOf: return "IS ONE OF";
case UserComparator.IsNotOneOf:
case UserComparator.SensitiveIsNotOneOf:
case UserComparator.TextIsNotOneOf:
case UserComparator.SensitiveTextIsNotOneOf:
case UserComparator.SemVerIsNotOneOf: return "IS NOT ONE OF";
case UserComparator.ContainsAnyOf: return "CONTAINS ANY OF";
case UserComparator.NotContainsAnyOf: return "NOT CONTAINS ANY OF";
case UserComparator.TextContainsAnyOf: return "CONTAINS ANY OF";
case UserComparator.TextNotContainsAnyOf: return "NOT CONTAINS ANY OF";
case UserComparator.SemVerLess:
case UserComparator.NumberLess: return "<";
case UserComparator.SemVerLessOrEquals:
Expand Down Expand Up @@ -225,7 +240,7 @@
}

export function formatUserCondition(condition: UserConditionUnion): string {
return new EvaluateLogBuilder().appendUserCondition(condition).toString();
return new EvaluateLogBuilder("").appendUserCondition(condition).toString();
}

export function formatPrerequisiteFlagComparator(comparator: PrerequisiteFlagComparator): string {
Expand Down
12 changes: 6 additions & 6 deletions src/ProjectConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,10 @@ export interface ICondition<TCondition extends keyof ConditionTypeMap = keyof Co
export type ConditionUnion = UserConditionUnion | PrerequisiteFlagCondition | SegmentCondition;

export type UserConditionComparisonValueTypeMap = {
[UserComparator.IsOneOf]: Readonly<string[]>;
[UserComparator.IsNotOneOf]: Readonly<string[]>;
[UserComparator.ContainsAnyOf]: Readonly<string[]>;
[UserComparator.NotContainsAnyOf]: Readonly<string[]>;
[UserComparator.TextIsOneOf]: Readonly<string[]>;
[UserComparator.TextIsNotOneOf]: Readonly<string[]>;
[UserComparator.TextContainsAnyOf]: Readonly<string[]>;
[UserComparator.TextNotContainsAnyOf]: Readonly<string[]>;
[UserComparator.SemVerIsOneOf]: Readonly<string[]>;
[UserComparator.SemVerIsNotOneOf]: Readonly<string[]>;
[UserComparator.SemVerLess]: string;
Expand All @@ -288,8 +288,8 @@ export type UserConditionComparisonValueTypeMap = {
[UserComparator.NumberLessOrEquals]: number;
[UserComparator.NumberGreater]: number;
[UserComparator.NumberGreaterOrEquals]: number;
[UserComparator.SensitiveIsOneOf]: Readonly<string[]>;
[UserComparator.SensitiveIsNotOneOf]: Readonly<string[]>;
[UserComparator.SensitiveTextIsOneOf]: Readonly<string[]>;
[UserComparator.SensitiveTextIsNotOneOf]: Readonly<string[]>;
[UserComparator.DateTimeBefore]: number;
[UserComparator.DateTimeAfter]: number;
[UserComparator.SensitiveTextEquals]: string;
Expand Down
Loading
Loading