-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: evaluation event being reported with no user ID (#89)
- Loading branch information
1 parent
edc1657
commit a59a36b
Showing
7 changed files
with
252 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import test from 'ava'; | ||
import { User } from '../objects/user'; | ||
import { assertGetEvaluationRequest } from '../assert'; | ||
|
||
const assertGetEvaluationRequestTestCases = [ | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for invalid user', | ||
user: { id: '', data: {} }, | ||
featureID: 'feature1', | ||
errorMessage: 'userID is empty' | ||
}, | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for missing featureID', | ||
user: { id: '123', data: {} }, | ||
featureID: '', | ||
errorMessage: 'featureID is required' | ||
}, | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for null user', | ||
user: null as any, | ||
featureID: 'feature1', | ||
errorMessage: 'user is null or undefined' | ||
}, | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for undefined user', | ||
user: undefined as any, | ||
featureID: 'feature1', | ||
errorMessage: 'user is null or undefined' | ||
}, | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for user with null id', | ||
user: { id: null as any, data: {} }, | ||
featureID: 'feature1', | ||
errorMessage: 'userID is empty' | ||
}, | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for user with undefined id', | ||
user: { id: undefined as any, data: {} }, | ||
featureID: 'feature1', | ||
errorMessage: 'userID is empty' | ||
}, | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for null featureID', | ||
user: { id: '123', data: {} }, | ||
featureID: null as any, | ||
errorMessage: 'featureID is required' | ||
}, | ||
{ | ||
name: 'assertGetEvaluationRequest throws error for undefined featureID', | ||
user: { id: '123', data: {} }, | ||
featureID: undefined as any, | ||
errorMessage: 'featureID is required' | ||
} | ||
]; | ||
|
||
assertGetEvaluationRequestTestCases.forEach(testCase => { | ||
test(testCase.name, t => { | ||
const error = t.throws(() => { | ||
assertGetEvaluationRequest(testCase.user, testCase.featureID); | ||
}, { instanceOf: Error }); | ||
t.is(error.message, testCase.errorMessage); | ||
}); | ||
}); | ||
|
||
test('assertGetEvaluationRequest does not throw error for valid user and featureID', t => { | ||
const user: User = { | ||
id: '123', | ||
data: {} | ||
}; | ||
t.notThrows(() => { | ||
assertGetEvaluationRequest(user, 'feature1'); | ||
}); | ||
}); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import anyTest, { TestFn } from 'ava'; | ||
import { BKTClientImpl, Bucketeer, initialize } from '..'; | ||
import { Config, User } from '../bootstrap'; | ||
import { DefaultLogger } from '../logger'; | ||
import { newDefaultBKTEvaluationDetails } from '../evaluationDetails'; | ||
|
||
const test = anyTest as TestFn<{ | ||
bktClient: Bucketeer; | ||
targetedUser: User; | ||
config: Config; | ||
}>; | ||
|
||
test.beforeEach((t) => { | ||
const config = { | ||
host: 'api.bucketeer.io', | ||
token: 'api_key_value', | ||
tag: 'feature_tag_value', | ||
logger: new DefaultLogger('expected'), | ||
}; | ||
t.context = { | ||
bktClient: initialize(config), | ||
targetedUser: { id: 'user_id', data: {} }, | ||
config: config, | ||
}; | ||
}); | ||
|
||
const testCases = [ | ||
{ | ||
description: 'return default value when featureID is empty', | ||
featureId: '', | ||
user: { id: 'user_id', data: {} }, | ||
expected: newDefaultBKTEvaluationDetails('user_id', '', 'default-test', 'DEFAULT'), | ||
}, | ||
{ | ||
description: 'return default value when userID is empty', | ||
featureId: 'stringEvaluationDetails', | ||
user: { id: '', data: {} }, | ||
expected: newDefaultBKTEvaluationDetails('', 'stringEvaluationDetails', 'default-test', 'DEFAULT'), | ||
}, | ||
{ | ||
description: 'return default value when userID & featureID is empty', | ||
featureId: '', | ||
user: { id: '', data: {} }, | ||
expected: newDefaultBKTEvaluationDetails('', '', 'default-test', 'DEFAULT'), | ||
}, | ||
// Simulate the case where the object is null when passed from JavaScript code. | ||
{ | ||
description: 'return default value when userID is null', | ||
featureId: 'featureId', | ||
user: null, | ||
expected: newDefaultBKTEvaluationDetails('', 'featureId', 'default-test', 'DEFAULT'), | ||
}, | ||
{ | ||
description: 'return default value when featureId is null', | ||
featureId: null, | ||
user: { id: 'user_id', data: {} }, | ||
expected: newDefaultBKTEvaluationDetails('user_id', '', 'default-test', 'DEFAULT'), | ||
}, | ||
{ | ||
description: 'return default value when featureId & userID is null', | ||
featureId: null, | ||
user: null, | ||
expected: newDefaultBKTEvaluationDetails('', '', 'default-test', 'DEFAULT'), | ||
}, | ||
// Simulate the case where the user.id is null when passed from JavaScript code. | ||
{ | ||
description: 'return default value when user.id is null', | ||
featureId: 'featureId', | ||
user: { id: null, data: {} }, | ||
expected: newDefaultBKTEvaluationDetails('', 'featureId', 'default-test', 'DEFAULT'), | ||
}, | ||
// Simulate the case where the user.id is undefined when passed from JavaScript code. | ||
{ | ||
description: 'return default value when user.id is undefined', | ||
featureId: 'featureId', | ||
user: { id: undefined, data: {} }, | ||
expected: newDefaultBKTEvaluationDetails('', 'featureId', 'default-test', 'DEFAULT'), | ||
}, | ||
// Simulate the case where the object is undefined when passed from JavaScript code. | ||
{ | ||
description: 'return default value when userID is undefined', | ||
featureId: 'featureId', | ||
user: undefined, | ||
expected: newDefaultBKTEvaluationDetails('', 'featureId', 'default-test', 'DEFAULT'), | ||
}, | ||
{ | ||
description: 'return default value when featureId is undefined', | ||
featureId: undefined, | ||
user: { id: 'user_id', data: {} }, | ||
expected: newDefaultBKTEvaluationDetails('user_id', '', 'default-test', 'DEFAULT'), | ||
}, | ||
{ | ||
description: 'return default value when featureId & userID is undefined', | ||
featureId: undefined, | ||
user: undefined, | ||
expected: newDefaultBKTEvaluationDetails('', '', 'default-test', 'DEFAULT'), | ||
}, | ||
]; | ||
|
||
for (const testCase of testCases) { | ||
test.serial(`getEvaluation: ${testCase.description}`, async (t) => { | ||
const client = t.context.bktClient; | ||
const clientImpl = client as BKTClientImpl; | ||
|
||
t.deepEqual( | ||
// Type cast for simulate the case where the user object is null when passed from JavaScript code. | ||
await client.stringVariationDetails(testCase.user as User, testCase.featureId as string, 'default-test'), | ||
testCase.expected, | ||
); | ||
t.true(clientImpl.eventStore.size() == 0, 'eventStore should be empty and not contain any error events'); | ||
}); | ||
} | ||
|
||
test.afterEach.always((t) => { | ||
t.context.bktClient.destroy(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { User } from './objects/user' | ||
|
||
/** | ||
* Asserts that the provided user and featureID are valid for an evaluation request. | ||
* | ||
* @param user - The user object to be validated. | ||
* @param featureID - The feature ID to be validated. | ||
* @throws Will throw an error if the user is invalid or if the featureID is not provided. | ||
*/ | ||
function assertGetEvaluationRequest(user: User, featureID: string) { | ||
if (!user) { | ||
throw new Error('user is null or undefined') | ||
} | ||
|
||
if (!user.id) { | ||
throw new Error('userID is empty') | ||
} | ||
|
||
if (!featureID) { | ||
throw new Error('featureID is required') | ||
} | ||
} | ||
|
||
export { assertGetEvaluationRequest } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters