Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit 2373457

Browse files
committed
Merge pull request #28 from launchdarkly/pk/coerce-user-key
added function to coerce user keys into strings, added some tests
2 parents f2cd8ba + b1d885a commit 2373457

File tree

6 files changed

+203
-3
lines changed

6 files changed

+203
-3
lines changed

.hound.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ curly: true,
77
forin: true,
88
immed: true,
99
latedef: "nofunc",
10-
maxlen: 80,
10+
maxlen: 120,
1111
newcap: true,
1212
noarg: true,
1313
noempty: true,
1414
nonew: true,
15+
eqeqeq: true,
1516
predef: [
1617
"$",
1718
"jQuery",
@@ -22,7 +23,8 @@ predef: [
2223
"it",
2324
"angular",
2425
"inject",
25-
"module"
26+
"module",
27+
"require"
2628
],
2729
quotmark: true,
2830
trailing: true,

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
LaunchDarkly SDK for Node.js
22
===========================
33

4+
![Circle CI](https://circleci.com/gh/launchdarkly/node-client.png)
5+
46
Quick setup
57
-----------
68

circle.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
machine:
2+
node:
3+
version: 5.7.0

index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ var new_client = function(api_key, config) {
122122
}
123123

124124
client.toggle = function(key, user, default_val, fn) {
125+
sanitize_user(user);
125126
var cb = fn || noop;
126127

127128
var request_params = {
@@ -230,6 +231,7 @@ var new_client = function(api_key, config) {
230231
}
231232

232233
client.track = function(eventName, user, data) {
234+
sanitize_user(user);
233235
var event = {"key": eventName,
234236
"user": user,
235237
"kind": "custom",
@@ -243,6 +245,7 @@ var new_client = function(api_key, config) {
243245
};
244246

245247
client.identify = function(user) {
248+
sanitize_user(user);
246249
var event = {"key": user.key,
247250
"kind": "identify",
248251
"user": user,
@@ -463,3 +466,9 @@ function intersect_safe(a, b)
463466
return b.indexOf(value) > -1;
464467
});
465468
}
469+
470+
function sanitize_user(u) {
471+
if (u['key']) {
472+
u['key'] = u['key'].toString();
473+
}
474+
}

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "LaunchDarkly SDK for Node.js",
55
"main": "index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
7+
"test": "mocha"
88
},
99
"repository": {
1010
"type": "git",
@@ -29,5 +29,9 @@
2929
},
3030
"engines": {
3131
"node": ">= 0.8.x"
32+
},
33+
"devDependencies": {
34+
"mocha": "^2.4.5",
35+
"rewire": "^2.5.1"
3236
}
3337
}

test/test.js

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
var rewire = require('rewire');
2+
var assert = require('assert');
3+
4+
var ld = rewire('../index.js');
5+
6+
match_target = ld.__get__('match_target');
7+
match_user = ld.__get__('match_user');
8+
sanitize_user = ld.__get__('sanitize_user');
9+
10+
describe('match_target', function() {
11+
it('should match users based on top-level attributes', function () {
12+
var u = {key: 'foo', firstName: 'alice'};
13+
var t = {
14+
attribute: 'firstName',
15+
op: 'in',
16+
values: [ 'alice', 'bob']
17+
}
18+
assert(match_target(t, u));
19+
});
20+
it('should not match users based on non-matching top-level attributes', function () {
21+
var u = {key: 'foo', firstName: 'clarisse'};
22+
var t = {
23+
attribute: 'firstName',
24+
op: 'in',
25+
values: [ 'alice', 'bob']
26+
}
27+
assert(!match_target(t, u));
28+
});
29+
it('should match users based single-value custom string attributes', function () {
30+
var u = {
31+
key: 'foo',
32+
custom: {
33+
favoriteColor: 'green'
34+
}
35+
};
36+
var t = {
37+
attribute: 'favoriteColor',
38+
op: 'in',
39+
values: [ 'green', 'red' ]
40+
}
41+
assert(match_target(t, u));
42+
});
43+
it('should not match users without single-value custom attributes', function () {
44+
var u = {
45+
key: 'foo',
46+
custom: {
47+
favoriteDog: 'labrador'
48+
}
49+
};
50+
var t = {
51+
attribute: 'favoriteColor',
52+
op: 'in',
53+
values: [ 'green', 'red' ]
54+
}
55+
assert(!match_target(t, u));
56+
});
57+
it('should not match users with non-matching single-value custom attributes', function () {
58+
var u = {
59+
key: 'foo',
60+
custom: {
61+
favoriteDog: 'labrador'
62+
}
63+
};
64+
var t = {
65+
attribute: 'favoriteColor',
66+
op: 'in',
67+
values: [ 'green', 'red' ]
68+
}
69+
assert(!match_target(t, u));
70+
});
71+
it('should match users based intersecting list custom string attributes', function () {
72+
var u = {
73+
key: 'foo',
74+
custom: {
75+
favoriteColor: [ 'green', 'blue' ]
76+
}
77+
};
78+
var t = {
79+
attribute: 'favoriteColor',
80+
op: 'in',
81+
values: [ 'green', 'red' ]
82+
};
83+
assert(match_target(t, u));
84+
});
85+
it('should not match users based non-intersecting list custom string attributes', function () {
86+
var u = {
87+
key: 'foo',
88+
custom: {
89+
favoriteColor: [ 'purple', 'blue' ]
90+
}
91+
};
92+
var t = {
93+
attribute: 'favoriteColor',
94+
op: 'in',
95+
values: [ 'green', 'red' ]
96+
};
97+
assert(!match_target(t, u));
98+
});
99+
});
100+
101+
describe('match_user', function() {
102+
it('should match the user when the key matches', function () {
103+
var u = {key: 'foo', firstName: 'alice'};
104+
var v = {
105+
value: true,
106+
weight: 0,
107+
userTarget: {
108+
attribute: 'key',
109+
op: 'in',
110+
values: ['bar', 'foo']
111+
},
112+
targets: []
113+
};
114+
assert(match_user(v, u));
115+
});
116+
it('should not match the user when the key does not match', function () {
117+
var u = {key: 'foo', firstName: 'alice'};
118+
var v = {
119+
value: true,
120+
weight: 0,
121+
userTarget: {
122+
attribute: 'key',
123+
op: 'in',
124+
values: ['bar', 'fiz']
125+
},
126+
targets: []
127+
};
128+
assert(!match_user(v, u));
129+
});
130+
it('should not match the user when the user target is empty', function () {
131+
var u = {key: 'foo', firstName: 'alice'};
132+
var v = {
133+
value: true,
134+
weight: 0,
135+
userTarget: {
136+
attribute: 'key',
137+
op: 'in',
138+
values: []
139+
},
140+
targets: []
141+
};
142+
assert(!match_user(v, u));
143+
});
144+
it('should not match the user when the user target is missing', function () {
145+
var u = {key: 'foo', firstName: 'alice'};
146+
var v = {
147+
value: true,
148+
weight: 0,
149+
targets: []
150+
};
151+
assert(!match_user(v, u));
152+
});
153+
});
154+
155+
describe('sanitize_user', function () {
156+
it('should do nothing when the key is already a string', function () {
157+
var u = {key: 'foo', firstName: 'alice'};
158+
var u0 = {key: 'foo', firstName: 'alice'};
159+
sanitize_user(u);
160+
assert.deepStrictEqual(u0, u);
161+
});
162+
it('should coerce a numeric key to a string', function () {
163+
var u = {key: 33, firstName: 'alice'};
164+
var u0 = {key: '33', firstName: 'alice'};
165+
sanitize_user(u);
166+
assert.deepStrictEqual(u0, u);
167+
});
168+
it('should coerce a boolean key to a string', function () {
169+
var u = {key: true, firstName: 'alice'};
170+
var u0 = {key: 'true', firstName: 'alice'};
171+
sanitize_user(u);
172+
assert.deepStrictEqual(u0, u);
173+
});
174+
it('should not blow up if the key is missing', function () {
175+
var u = {firstName: 'alice'};
176+
var u0 = {firstName: 'alice'};
177+
sanitize_user(u);
178+
assert.deepStrictEqual(u0, u);
179+
});
180+
});

0 commit comments

Comments
 (0)