Skip to content

Commit 6068061

Browse files
committed
[#404] Configuration Reconstructing
1 parent 9519131 commit 6068061

File tree

2 files changed

+138
-50
lines changed

2 files changed

+138
-50
lines changed

lib/config-builder.js

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ class ConfigBuilder {
2323
this.agentStartupUserDefinedJson = agentStartupUserDefinedJson
2424
this.handlers = [
2525
new AgentIdGenerator(),
26-
new ApplicationNameValidator()
26+
new AgentIdAndApplicationNameAndAgentNameValidator()
2727
]
28-
this.errorMessages = []
29-
this.warnMessages = []
3028
}
3129

3230
setDefaultJson(json) {
@@ -81,8 +79,9 @@ class ConfigBuilder {
8179
const fileContent = fs.readFileSync(configFilePath, 'utf8')
8280
return JSON.parse(fileContent)
8381
} catch (e) {
84-
this.warnMessages.push(`Failed to read or parse pinpoint-config.json at ${configFilePath}: ${e.message}`)
85-
return {}
82+
return new MessagesBuilder()
83+
.addWarns(`Failed to read or parse pinpoint-config.json at ${configFilePath}: ${e.message}`)
84+
.build()
8685
}
8786
}
8887

@@ -130,13 +129,74 @@ class AgentIdGenerator {
130129
}
131130
}
132131

133-
class ApplicationNameValidator {
132+
class MessagesBuilder {
133+
constructor() {
134+
this.errors = []
135+
this.warns = []
136+
}
137+
138+
addError(error) {
139+
this.errors.push(error)
140+
return this
141+
}
142+
143+
addWarn(warn) {
144+
this.warns.push(warn)
145+
return this
146+
}
147+
148+
build() {
149+
return { messages: { errors: this.errors, warns: this.warns } }
150+
}
151+
}
152+
153+
class AgentIdAndApplicationNameAndAgentNameValidator {
134154
handle(config) {
135-
if (config.applicationName?.length > 1) {
136-
return {}
155+
const fields = [
156+
{ label: 'Agent ID', value: config.agentId, maxLength: 24, required: true },
157+
{ label: 'Application Name', value: config.applicationName, maxLength: 24, required: true },
158+
{ label: 'Agent Name', value: config.agentName, maxLength: 255, required: false }
159+
]
160+
161+
const messages = new MessagesBuilder()
162+
163+
for (const field of fields) {
164+
const errors = validateIdField(field)
165+
for (const err of errors) {
166+
messages.addError(err)
167+
}
168+
}
169+
170+
if (messages.errors.length > 0) {
171+
return mergeConfig({ enable: false }, messages.build())
172+
}
173+
174+
if (typeof config.agentName === 'string' && config.agentName.trim().length === 0) {
175+
config.agentName = undefined
137176
}
138-
return { enable: false }
177+
178+
return {}
179+
}
180+
}
181+
182+
function validateIdField({ label, value, maxLength, required }) {
183+
const link = 'https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables'
184+
185+
if (!value || value.trim().length === 0) {
186+
return required ? [`${label} is required. See ${link}`] : []
187+
}
188+
189+
const errors = []
190+
191+
if (value.length > maxLength) {
192+
errors.push(`${label} is too long (max ${maxLength} characters). See ${link}`)
193+
}
194+
195+
if (!/^[a-zA-Z0-9\._\-]+$/.test(value)) {
196+
errors.push(`${label} has invalid characters; allowed [a-zA-Z0-9._-]. Value: ${value}. See ${link}`)
139197
}
198+
199+
return errors
140200
}
141201

142202
function makeEnvironmentConfig() {

test/config.test.js

Lines changed: 69 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -89,138 +89,166 @@ test('Agent ID length check', (t) => {
8989
process.env['PINPOINT_AGENT_ID'] = 'agentId'
9090
process.env['PINPOINT_APPLICATION_NAME'] = 'appication-name'
9191
process.env['PINPOINT_AGENT_NAME'] = 'agent-name'
92-
93-
let given = getConfig()
92+
let given = new ConfigBuilder().build()
9493
t.true(given.enable, 'configuration agentId, Name, ApplicationName enable agent id')
9594
t.equal(given.agentName, 'agent-name', 'agent name is agent name')
96-
9795
delete process.env.PINPOINT_AGENT_ID
9896
delete process.env.PINPOINT_APPLICATION_NAME
97+
delete process.env.PINPOINT_AGENT_NAME
9998

100-
clear()
10199
process.env['PINPOINT_AGENT_ID'] = 'agentIdagentIdagentIdage'
102100
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
103-
104-
given = getConfig()
101+
given = new ConfigBuilder().build()
105102
t.true(given.enable, 'maxlength agentID and application Name')
106-
103+
t.equal(given.messages, undefined, 'no error message')
107104
delete process.env.PINPOINT_AGENT_ID
108105
delete process.env.PINPOINT_APPLICATION_NAME
109106

110-
clear()
111107
process.env['PINPOINT_AGENT_ID'] = 'agentIdagentIdagentIdageE'
112108
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
113-
114-
given = getConfig()
109+
given = new ConfigBuilder().build()
115110
t.false(given.enable, 'maxlength agentID error')
116-
111+
t.equal(given.messages.errors[0], 'Agent ID is too long (max 24 characters). See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
117112
delete process.env.PINPOINT_AGENT_ID
118113
delete process.env.PINPOINT_APPLICATION_NAME
119114

120-
clear()
121115
process.env['PINPOINT_AGENT_ID'] = 'agentIdagentIdagentIdage'
122116
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappicationE'
123-
124-
given = getConfig()
117+
given = new ConfigBuilder().build()
125118
t.false(given.enable, 'maxlength application Name error')
126-
119+
t.equal(given.messages.errors[0], 'Application Name is too long (max 24 characters). See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
127120
delete process.env.PINPOINT_AGENT_ID
128121
delete process.env.PINPOINT_APPLICATION_NAME
129122

130-
clear()
131123
process.env['PINPOINT_AGENT_ID'] = '~'
132124
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
133-
134-
given = getConfig()
125+
given = new ConfigBuilder().build()
135126
t.false(given.enable, 'invalide agent ID')
136-
127+
t.equal(given.messages.errors[0], 'Agent ID has invalid characters; allowed [a-zA-Z0-9._-]. Value: ~. See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
137128
delete process.env.PINPOINT_AGENT_ID
138129
delete process.env.PINPOINT_APPLICATION_NAME
139130

140-
clear()
141131
process.env['PINPOINT_AGENT_ID'] = 'agentIdagentIdagentIdage'
142132
process.env['PINPOINT_APPLICATION_NAME'] = '~'
143-
144-
given = getConfig()
133+
given = new ConfigBuilder().build()
145134
t.false(given.enable, 'invalide application name')
146-
135+
t.equal(given.messages.errors[0], 'Application Name has invalid characters; allowed [a-zA-Z0-9._-]. Value: ~. See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
147136
delete process.env.PINPOINT_AGENT_ID
148137
delete process.env.PINPOINT_AGENT_NAME
149138
delete process.env.PINPOINT_APPLICATION_NAME
150139

151-
clear()
152140
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
153-
154-
given = getConfig()
141+
given = new ConfigBuilder().build()
155142
t.true(given.enable, 'agent ID nullable test')
156143
t.equal(given.applicationName, 'appicationnameappication', 'application name is appicationnameappication')
157144
t.equal(given.agentId.length, 16, 'random generated agent ID length is 16')
158-
159145
delete process.env.PINPOINT_AGENT_ID
160146
delete process.env.PINPOINT_AGENT_NAME
161147
delete process.env.PINPOINT_APPLICATION_NAME
162148

163-
clear()
164-
given = getConfig()
149+
given = new ConfigBuilder().build()
165150
t.false(given.enable, 'Application Name must be set')
166151
t.true(given.agentId.length === 16, 'Agent ID was generated randomly')
167152
t.false(given.agentName, 'Agent Name is optional value and only set from developer')
168153
t.equal(given.applicationName, undefined, 'Application Name is required and only set from developer')
169-
154+
t.equal(given.messages.errors[0], 'Application Name is required. See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
170155
delete process.env.PINPOINT_AGENT_ID
171156
delete process.env.PINPOINT_AGENT_NAME
172157
delete process.env.PINPOINT_APPLICATION_NAME
173158

174-
clear()
175159
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
176160
process.env['PINPOINT_AGENT_NAME'] = 'agent name'
177-
given = getConfig()
161+
given = new ConfigBuilder().build()
178162
t.false(given.enable, 'Application Name must be set')
179163
t.true(given.agentId.length === 16, 'Agent ID was generated randomly')
180164
t.equal(given.agentName, 'agent name', 'Agent Name is optional value and only set from developer')
181165
t.equal(given.applicationName, 'appicationnameappication', 'Application Name is required and only set from developer')
182-
166+
t.equal(given.messages.errors[0], 'Agent Name has invalid characters; allowed [a-zA-Z0-9._-]. Value: agent name. See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
183167
delete process.env.PINPOINT_AGENT_ID
184168
delete process.env.PINPOINT_AGENT_NAME
185169
delete process.env.PINPOINT_APPLICATION_NAME
186170

187-
clear()
188171
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
189172
process.env['PINPOINT_AGENT_NAME'] = 'agent?name'
190-
given = getConfig()
173+
given = new ConfigBuilder().build()
191174
t.false(given.enable, 'Application Name must be set')
192175
t.true(given.agentId.length === 16, 'Agent ID was generated randomly')
193176
t.equal(given.agentName, 'agent?name', 'Agent Name is optional value and only set from developer')
194177
t.equal(given.applicationName, 'appicationnameappication', 'Application Name is required and only set from developer')
195-
178+
t.equal(given.messages.errors[0], 'Agent Name has invalid characters; allowed [a-zA-Z0-9._-]. Value: agent?name. See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
196179
delete process.env.PINPOINT_AGENT_ID
197180
delete process.env.PINPOINT_AGENT_NAME
198181
delete process.env.PINPOINT_APPLICATION_NAME
199182

200-
clear()
201183
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
202184
process.env['PINPOINT_AGENT_NAME'] = 'agentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagen'
203-
given = getConfig()
185+
given = new ConfigBuilder().build()
204186
t.false(given.enable, 'Application Name must be set')
205187
t.true(given.agentId.length === 16, 'Agent ID was generated randomly')
206188
t.equal(given.agentName, 'agentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagen', 'Agent Name is optional value and only set from developer')
207189
t.equal(given.applicationName, 'appicationnameappication', 'Application Name is required and only set from developer')
208-
190+
t.equal(given.messages.errors[0], 'Agent Name is too long (max 255 characters). See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
209191
delete process.env.PINPOINT_AGENT_ID
210192
delete process.env.PINPOINT_AGENT_NAME
211193
delete process.env.PINPOINT_APPLICATION_NAME
212194

213-
clear()
214195
process.env['PINPOINT_APPLICATION_NAME'] = 'appicationnameappication'
215196
process.env['PINPOINT_AGENT_NAME'] = 'agentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameage'
216-
given = getConfig()
197+
given = new ConfigBuilder().build()
217198
t.true(given.enable, 'Application Name must be set')
218199
t.true(given.agentId.length === 16, 'Agent ID was generated randomly')
219200
t.equal(given.agentName, 'agentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameagentnameage', 'Agent Name is optional value and only set from developer')
220201
t.equal(given.applicationName, 'appicationnameappication', 'Application Name is required and only set from developer')
202+
t.equal(given.messages, undefined, 'no error message')
203+
delete process.env.PINPOINT_AGENT_ID
204+
delete process.env.PINPOINT_AGENT_NAME
205+
delete process.env.PINPOINT_APPLICATION_NAME
206+
207+
208+
209+
t.end()
210+
})
211+
212+
test('Agent Name validation', (t) => {
213+
t.plan(6)
214+
215+
// too long (256 chars)
216+
process.env.PINPOINT_AGENT_ID = 'agent-valid'
217+
process.env.PINPOINT_APPLICATION_NAME = 'application-valid'
218+
process.env.PINPOINT_AGENT_NAME = 'a'.repeat(256)
219+
let given = new ConfigBuilder().build()
220+
t.false(given.enable, 'agent name over 255 disables agent')
221+
t.equal(given.messages.errors[0], 'Agent Name is too long (max 255 characters). See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
222+
223+
// invalid characters
224+
process.env.PINPOINT_AGENT_NAME = 'agent?name'
225+
given = new ConfigBuilder().build()
226+
t.false(given.enable, 'agent name with invalid chars disables agent')
227+
t.equal(given.messages.errors[0], 'Agent Name has invalid characters; allowed [a-zA-Z0-9._-]. Value: agent?name. See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
228+
229+
// empty allowed (optional)
230+
process.env.PINPOINT_AGENT_NAME = ''
231+
given = new ConfigBuilder().build()
232+
t.true(given.enable, 'empty agent name is allowed')
233+
t.equal(given.agentName, undefined, 'empty agent name not set')
221234

222235
delete process.env.PINPOINT_AGENT_ID
236+
delete process.env.PINPOINT_APPLICATION_NAME
223237
delete process.env.PINPOINT_AGENT_NAME
238+
})
239+
240+
test('Agent ID and Application Name multiple errors', (t) => {
241+
process.env.PINPOINT_AGENT_ID = 'agentIdagentIdagentIdageE' // 25 chars -> too long
242+
process.env.PINPOINT_APPLICATION_NAME = 'appicationnameappication?' // invalid char
243+
244+
const given = new ConfigBuilder().build()
245+
t.false(given.enable, 'config disabled when multiple id/app errors')
246+
t.ok(given.messages?.errors?.length >= 2, 'aggregates multiple errors')
247+
t.equal(given.messages.errors[0], 'Agent ID is too long (max 24 characters). See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
248+
t.equal(given.messages.errors[1], 'Application Name is too long (max 24 characters). See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
249+
t.equal(given.messages.errors[2], 'Application Name has invalid characters; allowed [a-zA-Z0-9._-]. Value: appicationnameappication?. See https://github.com/pinpoint-apm/pinpoint-node-agent?tab=readme-ov-file#3-configuration-with-environment-variables')
250+
251+
delete process.env.PINPOINT_AGENT_ID
224252
delete process.env.PINPOINT_APPLICATION_NAME
225253

226254
t.end()

0 commit comments

Comments
 (0)