1 /* eslint-disable sonarjs/no-duplicate-string */
5 * For testing, this is a configurable endpoint server.
7 * Set how a subscriber id responds to a verification GET call
8 * PUT /subscriber/:id/verify?responseCode=xxx&matchChallenge=true
9 * Set how an id responds to a content delivery POST call
10 * PUT /subscriber/:id/content?responseCode=xxx
12 * DELETE /subscriber/:id
14 * Set how a topic id returns
15 * PUT /topic/:id?statusCode=xxx&content=xxx&contentType=foo/bar
18 const http
= require('http');
19 const { Dingus
, Enum
, Errors
} = require('@squeep/api-dingus');
21 const subscriberPort
= process
.env
.FAKE_SUBSCRIBER_PORT
|| 9876;
22 const topicPort
= process
.env
.FAKE_TOPIC_PORT
|| 9875;
23 const listenAddress
= process
.env
.FAKE_LISTEN_ADDR
|| '127.0.0.1';
25 class TopicFake
extends Dingus
{
28 ignoreTrailingSlash: true,
30 this.topicBehaviors
= new Map();
31 this.on(['GET'], '/topic/:id', this.getId
.bind(this));
33 this.on(['PUT'], '/topic/:id', this.putId
.bind(this));
34 this.on(['DELETE'], '/topic/:id', this.deleteId
.bind(this));
37 async
getId(req
, res
, ctx
) {
38 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
39 const behavior
= this.topicBehaviors
.get(ctx
.params
.id
);
41 throw new Errors
.ResponseError(Enum
.ErrorResponse
.NotFound
);
43 if (behavior
.contentType
) {
44 res
.setHeader(Enum
.Header
.ContentType
, behavior
.contentType
);
46 res
.setHeader('Link', behavior
.selfLink
+ (behavior
.hubLink
? `, ${behavior.hubLink}` : ''));
47 res
.statusCode
= behavior
.statusCode
;
48 res
.end(behavior
.content
);
49 this.logger
.info({ method: req
.method
, statusCode: res
.statusCode
, url: req
.url
});
52 async
putId(req
, res
, ctx
) {
53 const id
= ctx
.params
.id
;
54 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
56 statusCode: ctx
.queryParams
.statusCode
|| 200,
57 ...(ctx
.queryParams
.contentType
&& { contentType: ctx
.queryParams
.contentType
}),
58 content: ctx
.queryParams
.content
,
59 selfLink: `<http://${listenAddress}:${topicPort}/${id}>; rel="self"`,
60 ...(ctx
.queryParams
.hubUrl
&& { hubLink: `<${ctx.queryParams.hubUrl}>; rel="hub"` }),
62 this.topicBehaviors
.set(id
, behavior
);
67 async
deleteId(req
, res
, ctx
) {
68 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
69 this.topicBehaviors
.delete(ctx
.params
.id
);
76 class SubscriberFake
extends Dingus
{
79 ignoreTrailingSlash: true,
81 this.verifyBehaviors
= new Map();
82 this.contentBehaviors
= new Map();
83 this.on(['GET'], '/subscriber/:id', this.getId
.bind(this));
84 this.on(['POST'], '/subscriber/:id', this.postId
.bind(this));
86 this.on(['PUT'], '/subscriber/:id/verify', this.putVerify
.bind(this));
87 this.on(['PUT'], '/subscriber/:id/content', this.putContent
.bind(this));
88 this.on(['DELETE'], '/subscriber/:id', this.deleteId
.bind(this));
91 // eslint-disable-next-line class-methods-use-this
93 // do not parse, just ingest
96 async
getId(req
, res
, ctx
) {
97 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
98 const behavior
= this.verifyBehaviors
.get(ctx
.params
.id
);
99 res
.statusCode
= behavior
? behavior
.statusCode : 404;
100 const response
= (behavior
&& behavior
.matchChallenge
) ? ctx
.queryParams
['hub.challenge'] : (behavior
&& behavior
.response
);
102 this.logger
.info({ method: req
.method
, statusCode: res
.statusCode
, matchChallenge: !!(behavior
&& behavior
.matchChallenge
), url: req
.url
});
105 async
postId(req
, res
, ctx
) {
106 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
107 await
this.ingestBody(req
, res
, ctx
);
108 const behavior
= this.contentBehaviors
.get(ctx
.params
.id
);
109 res
.statusCode
= behavior
? behavior
.statusCode : 404;
111 behavior
.updated
= new Date();
112 behavior
.content
= ctx
.rawBody
;
115 this.logger
.info({ content: behavior
&& behavior
.content
, method: req
.method
, statusCode: res
.statusCode
, matchChallenge: !!(behavior
&& behavior
.matchChallenge
), url: req
.url
});
118 async
putVerify(req
, res
, ctx
) {
119 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
121 matchChallenge: ctx
.queryParams
.matchChallenge
=== 'true',
122 statusCode: ctx
.queryParams
.statusCode
|| 200,
124 this.verifyBehaviors
.set(ctx
.params
.id
, behavior
);
125 if (!this.contentBehaviors
.get(ctx
.params
.id
)) {
126 this.contentBehaviors
.set(ctx
.params
.id
, {
130 res
.statusCode
= 200;
134 async
putContent(req
, res
, ctx
) {
135 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
137 statusCode: ctx
.queryParams
.statusCode
|| 200,
139 this.contentBehaviors
.set(ctx
.params
.id
, behavior
);
140 res
.statusCode
= 200;
144 async
deleteId(req
, res
, ctx
) {
145 this.setResponseType(this.responseTypes
, req
, res
, ctx
);
146 this.contentBehaviors
.delete(ctx
.params
.id
);
147 this.verifyBehaviors
.delete(ctx
.params
.id
);
148 res
.statusCode
= 200;
154 const subscriberService
= new SubscriberFake();
155 http
.createServer((req
, res
) => {
156 subscriberService
.dispatch(req
, res
);
157 }).listen(subscriberPort
, listenAddress
, (err
) => {
162 console
.log(`Fake Subscriber Server started on ${listenAddress}:${subscriberPort}`);
165 const topicService
= new TopicFake();
166 http
.createServer((req
, res
) => {
167 topicService
.dispatch(req
, res
);
168 }).listen(topicPort
, listenAddress
, (err
) => {
173 console
.log(`Fake Topic Server started on ${listenAddress}:${topicPort}`);