Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a090170
Work on initial scaffold.
kinyoklion May 19, 2022
0b470ea
Update index exports.
kinyoklion May 19, 2022
93fbac6
Add an extra blank line.
kinyoklion May 19, 2022
8be08da
Attempt using mixin for event emitter.
kinyoklion May 23, 2022
5302683
Add implementation for emitting events for big segment status.
kinyoklion May 23, 2022
263fccd
Add documentation.
kinyoklion May 23, 2022
831b964
Fix lint and interface hierarchy.
kinyoklion May 23, 2022
3b1ece5
Start implementation.
kinyoklion May 23, 2022
cec9858
Progress on option handling.
kinyoklion May 23, 2022
954a135
Add application tags support.
kinyoklion May 23, 2022
1a0dffc
Un-generalize tags.
kinyoklion May 23, 2022
a141aeb
Fix tag formatting.
kinyoklion May 23, 2022
40d27e3
Comments.
kinyoklion May 23, 2022
f429571
Add internal to validated options.
kinyoklion May 23, 2022
5792122
Add tests for type checks. Finish implementing type checks.
kinyoklion May 24, 2022
b93ed50
Add remaining validator tests.
kinyoklion May 24, 2022
82599e2
Improve coverage collection. Start implementing application tags tests.
kinyoklion May 24, 2022
ef67115
Add test logger and finish tag tests.
kinyoklion May 24, 2022
cd8357a
Start testing the Configuration class.
kinyoklion May 24, 2022
7ea76b5
Fix validation. Start on individual option tests.
kinyoklion May 24, 2022
82788fd
Add remaining config tests.
kinyoklion May 24, 2022
9740584
Make sure to check resolves in the logger.
kinyoklion May 24, 2022
2517279
Start implementation.
kinyoklion May 24, 2022
b573151
Implement check for service endpoints consistency. Improve testing me…
kinyoklion May 25, 2022
4283204
Merge branch 'main' into rlamb/sc-154352/options-parsing
kinyoklion May 25, 2022
2f55d1a
Merge branch 'main' into rlamb/sc-154351/attributes-and-context
kinyoklion May 25, 2022
9080329
Remove unintended file.
kinyoklion May 25, 2022
c59c5b9
Merge branch 'rlamb/sc-154352/options-parsing' into rlamb/sc-154351/a…
kinyoklion May 25, 2022
af34183
Empty context.
kinyoklion May 25, 2022
5e0d9b1
Update server-sdk-common/src/options/Configuration.ts
kinyoklion May 25, 2022
3b207fd
Progress
kinyoklion May 25, 2022
79dd5d6
Refactor expectMessages.
kinyoklion May 25, 2022
ab50ad1
Merge branch 'rlamb/sc-154352/options-parsing' into rlamb/sc-154351/a…
kinyoklion May 25, 2022
2b38d40
Show what was received.
kinyoklion May 25, 2022
36c584d
Merge master
kinyoklion May 25, 2022
59ed4c8
Finish moving things.
kinyoklion May 25, 2022
a977353
Move validation. Implement more of Context.
kinyoklion May 25, 2022
a935f1a
Basic context and attribute reference structure.
kinyoklion May 25, 2022
ba71331
Add attribute reference tests.
kinyoklion May 25, 2022
a7a04ea
Add some comments.
kinyoklion May 25, 2022
db8e51d
Flesh out public interface for contexts. Add more documentation.
kinyoklion May 26, 2022
e23954b
Finish adding context tests.
kinyoklion May 26, 2022
552d49e
Update sdk-common/src/Context.ts
kinyoklion Jun 1, 2022
347be72
Update sdk-common/src/Context.ts
kinyoklion Jun 1, 2022
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
74 changes: 74 additions & 0 deletions sdk-common/__tests__/AttributeReference.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { LDContextCommon } from '../src';
import AttributeReference from '../src/AttributeReference';

function AsContextCommon(values: Record<string, any>): LDContextCommon {
return {
...values,
key: 'potato',
};
}

describe.each([
new AttributeReference('/'),
new AttributeReference(''),
new AttributeReference('//'),
new AttributeReference(''),
new AttributeReference('', true),
new AttributeReference('_meta'),
new AttributeReference('/_meta'),
new AttributeReference('/_meta/secondary'),
])('when given invalid attribute references', (reference) => {
it('should not be valid', () => {
expect(reference.isValid).toBeFalsy();
});

it('should not be able to get a value', () => {
expect(reference.get(AsContextCommon({
'/': true,
'//': true,
'/~3': true,
'': true,
_meta: { secondary: true },
}))).toBeUndefined();
});
});

describe.each([
[new AttributeReference('/', true), { '/': true }, true],
[new AttributeReference('//', true), { '//': 17 }, 17],
[new AttributeReference('/~0', true), { '/~0': 'string' }, 'string'],
[new AttributeReference('a~b', true), { 'a~b': 'another' }, 'another'],
[new AttributeReference('a~b'), { 'a~b': 'another' }, 'another'],
[new AttributeReference('a/b', true), { 'a/b': true }, true],
[new AttributeReference('a/b'), { 'a/b': true }, true],
[new AttributeReference('/a~1~0b'), { 'a/~b': true }, true],
[new AttributeReference('/a~0b'), { 'a~b': true }, true],
[new AttributeReference(' /a/b', true), { ' /a/b': true }, true],
[new AttributeReference(' /a/b', false), { ' /a/b': true }, true],
[new AttributeReference('/a/b'), { a: { b: 'c' } }, 'c'],
[new AttributeReference('/a/1'), { a: ['b', 'c'] }, 'c'],
])('when given valid attribute references', (reference, object, expected) => {
it('should be valid', () => {
expect(reference.isValid).toBeTruthy();
});

it('should be able to get a value', () => {
expect(reference.get(AsContextCommon(object))).toEqual(expected);
});
});

describe.each([
[new AttributeReference('name'), { }],
[new AttributeReference('/a/b'), { a: {} }],
[new AttributeReference('/a/0'), { a: 'test' }],
[new AttributeReference('/a/b'), { a: null }],
[new AttributeReference('/a/7'), { a: [0, 1] }],
])('should gracefully handle values that do not exist', (reference, object) => {
it('should be valid', () => {
expect(reference.isValid).toBeTruthy();
});

it('should not be able to get a value', () => {
expect(reference.get(AsContextCommon(object))).toBeUndefined();
});
});
221 changes: 221 additions & 0 deletions sdk-common/__tests__/Context.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import AttributeReference from '../src/AttributeReference';
import Context from '../src/Context';

// A sample of invalid characters.
const invalidSampleChars = [...`#$%&'()*+,/:;<=>?@[\\]^\`{|}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²
³´µ¶·¸¹º»¼½¾¿À汉字`];
const badKinds = invalidSampleChars.map((char) => ({ kind: char, key: 'test' }));

describe.each([
{},
{ kind: 'kind', key: 'kind' },
{ kind: {}, key: 'key' },
{ kind: 17, key: 'key' },
{ kind: 'multi', key: 'key' },
{ kind: 'multi', bad: 'value' },
{ kind: 'multi', 'p@rty': 'value' },
{
kind: 'multi',
bad: {
key: 17,
},
},
...badKinds,
])('given invalid LDContext', (ldConext) => {
it('should not create a context', () => {
// Force TS to accept our bad contexts.
// @ts-ignore
expect(Context.FromLDContext(ldConext)).toBeUndefined();
});
});

describe.each([
{
key: 'test',
name: 'context name',
custom: { cat: 'calico', '/dog~~//': 'lab' },
anonymous: true,
secondary: 'secondary',
privateAttributeNames: ['/dog~~//'],
},
{
kind: 'user',
key: 'test',
name: 'context name',
cat: 'calico',
transient: true,
_meta: { secondary: 'secondary', privateAttributes: ['/~1dog~0~0~1~1'] },
},
{
kind: 'multi',
user: {
key: 'test',
cat: 'calico',
transient: true,
name: 'context name',
_meta: { secondary: 'secondary', privateAttributes: ['/~1dog~0~0~1~1'] },
},
},
])('given a series of equivalent good user contexts', (ldConext) => {
// Here we are providing good contexts, but the types derived from
// the parameterization are causing some problems.
// @ts-ignore
const context = Context.FromLDContext(ldConext);

it('should create a context', () => {
expect(context).toBeDefined();
});

it('should get the same values', () => {
expect(context?.valueForKind('user', new AttributeReference('cat'))).toEqual('calico');
expect(context?.valueForKind('user', new AttributeReference('name'))).toEqual('context name');
expect(context?.kinds).toStrictEqual(['user']);
expect(context?.kindsAndKeys).toStrictEqual({ user: 'test' });
// Canonical keys for 'user' contexts are just the key.
expect(context?.canonicalKey).toEqual('test');
expect(context?.valueForKind('user', new AttributeReference('transient'))).toBeTruthy();
expect(context?.secondary('user')).toEqual('secondary');
expect(context?.isMultiKind).toBeFalsy();
expect(context?.privateAttributes('user')?.[0].redactionName)
.toEqual(new AttributeReference('/~1dog~0~0~1~1').redactionName);
});

it('should not get values for a context kind that does not exist', () => {
expect(context?.valueForKind('org', new AttributeReference('cat'))).toBeUndefined();
});

it('should have the correct kinds', () => {
expect(context?.kinds).toEqual(['user']);
});

it('should have the correct kinds and keys', () => {
expect(context?.kindsAndKeys).toEqual({ user: 'test' });
});
});

describe('given a valid legacy user without custom attributes', () => {
const context = Context.FromLDContext({
key: 'test',
name: 'context name',
custom: { cat: 'calico', '/dog~~//': 'lab' },
anonymous: true,
secondary: 'secondary',
privateAttributeNames: ['/dog~~//'],
});

it('should create a context', () => {
expect(context).toBeDefined();
});

it('should get expected values', () => {
expect(context?.valueForKind('user', new AttributeReference('name'))).toEqual('context name');
expect(context?.kinds).toStrictEqual(['user']);
expect(context?.kindsAndKeys).toStrictEqual({ user: 'test' });
// Canonical keys for 'user' contexts are just the key.
expect(context?.canonicalKey).toEqual('test');
expect(context?.valueForKind('user', new AttributeReference('transient'))).toBeTruthy();
expect(context?.secondary('user')).toEqual('secondary');
expect(context?.isMultiKind).toBeFalsy();
expect(context?.privateAttributes('user')?.[0].redactionName)
.toEqual(new AttributeReference('/~1dog~0~0~1~1').redactionName);
});
});

describe('given a non-user single kind context', () => {
const context = Context.FromLDContext({
kind: 'org',
// Key will be URL encoded.
key: 'Org/Key',
value: 'OrgValue',
});
it('should have the correct canonical key', () => {
expect(context?.canonicalKey).toEqual('org:Org%2FKey');
});

it('secondary should not be defined when not present', () => {
expect(context?.secondary('org')).toBeUndefined();
});

it('should have the correct kinds', () => {
expect(context?.kinds).toEqual(['org']);
});

it('should have the correct kinds and keys', () => {
expect(context?.kindsAndKeys).toEqual({ org: 'Org/Key' });
});
});

it('secondary should be defined when present', () => {
const context = Context.FromLDContext({
kind: 'org',
// Key will be URL encoded.
key: 'Org/Key',
value: 'OrgValue',
_meta: { secondary: 'secondary' },
});
expect(context?.secondary('org')).toEqual('secondary');
});

it('secondary should be undefined when meta is present, but secondary is not', () => {
const context = Context.FromLDContext({
kind: 'org',
// Key will be URL encoded.
key: 'Org/Key',
value: 'OrgValue',
_meta: {},
});
expect(context?.secondary('org')).toBeUndefined();
});

it('secondary key should be undefined when not a string', () => {
const context = Context.FromLDContext({
// @ts-ignore
kind: 'org',
// Key will be URL encoded.
key: 'Org/Key',
// @ts-ignore
value: 'OrgValue',
// @ts-ignore
_meta: { secondary: 17 }, // This really displeases typescript.
});
expect(context?.secondary('org')).toBeUndefined();
});

describe('given a multi-kind context', () => {
const context = Context.FromLDContext({
kind: 'multi',

org: {
key: 'OrgKey',
value: 'OrgValue',
_meta: {
secondary: 'value',
},
},
user: {
key: 'User /Key',
// Key will be URL encoded.
value: 'UserValue',
},
});

it('should have the correct canonical key', () => {
expect(context?.canonicalKey).toEqual('org:OrgKey:user:User%20%2FKey');
});

it('should get values from the correct context', () => {
expect(context?.valueForKind('org', new AttributeReference('value'))).toEqual('OrgValue');
expect(context?.valueForKind('user', new AttributeReference('value'))).toEqual('UserValue');

expect(context?.secondary('org')).toEqual('value');
expect(context?.secondary('user')).toBeUndefined();
});

it('should have the correct kinds', () => {
expect(context?.kinds).toEqual(['org', 'user']);
});

it('should have the correct kinds and keys', () => {
expect(context?.kindsAndKeys).toEqual({ org: 'OrgKey', user: 'User /Key' });
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import TypeValidators, { TypeArray } from '../../src/options/validators';
import { TypeArray, TypeValidators } from '../src';

const stringValue = 'this is a string';
const numberValue = 3.14159;
Expand Down
Loading