Skip to content
This repository was archived by the owner on Jan 23, 2025. It is now read-only.

Commit ddcacfd

Browse files
Initial commit
0 parents  commit ddcacfd

File tree

17 files changed

+6585
-0
lines changed

17 files changed

+6585
-0
lines changed

ReadMe.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Topcoder - Legacy Challenge Processor
2+
3+
## Dependencies
4+
5+
- nodejs https://nodejs.org/en/ (v10+)
6+
- Kafka
7+
8+
## Configuration
9+
10+
Configuration for the legacy groups processor is at `config/default.js`.
11+
The following parameters can be set in config files or in env variables:
12+
- LOG_LEVEL: the log level; default value: 'debug'
13+
- KAFKA_URL: comma separated Kafka hosts; default value: 'localhost:9092'
14+
- KAFKA_CLIENT_CERT: Kafka connection certificate, optional; default value is undefined;
15+
if not provided, then SSL connection is not used, direct insecure connection is used;
16+
if provided, it can be either path to certificate file or certificate content
17+
- KAFKA_CLIENT_CERT_KEY: Kafka connection private key, optional; default value is undefined;
18+
if not provided, then SSL connection is not used, direct insecure connection is used;
19+
if provided, it can be either path to private key file or private key content
20+
- KAFKA_GROUP_ID: the Kafka group id, default value is 'legacy-challenge-processor'
21+
- CREATE_CHALLENGE_TOPIC: the create challenge Kafka message topic, default value is 'challenge.notification.create'
22+
- UPDATE_CHALLENGE_TOPIC: the update challenge Kafka message topic, default value is 'challenge.notification.update'
23+
- AUTH0_URL: Auth0 URL, used to get TC M2M token
24+
- AUTH0_AUDIENCE: Auth0 audience, used to get TC M2M token
25+
- TOKEN_CACHE_TIME: Auth0 token cache time, used to get TC M2M token
26+
- AUTH0_CLIENT_ID: Auth0 client id, used to get TC M2M token
27+
- AUTH0_CLIENT_SECRET: Auth0 client secret, used to get TC M2M token
28+
- AUTH0_PROXY_SERVER_URL: Proxy Auth0 URL, used to get TC M2M token
29+
- V4_CHALLENGE_API_URL: V4 challenge api url, default value is 'https://api.topcoder-dev.com/v4/challenges'
30+
- V4_PLATFORMS_API_URL: v4 platforms api url, default value is 'https://api.topcoder-dev.com/v4/platforms'
31+
- V4_TECHNOLOGIES_API_URL:v4 technologies api url, default value is 'https://api.topcoder-dev.com/v4/technologies'
32+
- V5_CHALLENGE_API_URL: v5 challenge api url, default value is 'http://localhost:4000/v5/challenges'
33+
- V5_CHALLENGE_TYPE_API_URL: v5 challenge type api url, default value is 'http://localhost:4000/v5/challengeTypes'
34+
35+
There is a `/health` endpoint that checks for the health of the app. This sets up an expressjs server and listens on the environment variable `PORT`. It's not part of the configuration file and needs to be passed as an environment variable
36+
37+
Configuration for the tests is at `config/test.js`, only add such new configurations different from `config/default.js`
38+
- MOCK_API_PORT: the mock server port, default is 4000
39+
- WAIT_TIME: wait time used in test, default is 1500 or 1.5 second
40+
- V4_CHALLENGE_API_URL: the v4 challenge api url, used mock v4 challenge api in testing
41+
42+
## Local Kafka setup
43+
44+
- `http://kafka.apache.org/quickstart` contains details to setup and manage Kafka server,
45+
below provides details to setup Kafka server in Linux/Mac, Windows will use bat commands in bin/windows instead
46+
- download kafka at `https://www.apache.org/dyn/closer.cgi?path=/kafka/1.1.0/kafka_2.11-1.1.0.tgz`
47+
- extract out the downloaded tgz file
48+
- go to extracted directory kafka_2.11-0.11.0.1
49+
- start ZooKeeper server:
50+
`bin/zookeeper-server-start.sh config/zookeeper.properties`
51+
- use another terminal, go to same directory, start the Kafka server:
52+
`bin/kafka-server-start.sh config/server.properties`
53+
- note that the zookeeper server is at localhost:2181, and Kafka server is at localhost:9092
54+
- use another terminal, go to same directory, create the needed topics:
55+
`bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic challenge.notification.create`
56+
57+
`bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic challenge.notification.update`
58+
59+
- verify that the topics are created:
60+
`bin/kafka-topics.sh --list --zookeeper localhost:2181`,
61+
it should list out the created topics
62+
- run the producer and then write some message into the console to send to the `challenge.notification.create` topic:
63+
`bin/kafka-console-producer.sh --broker-list localhost:9092 --topic challenge.notification.create`
64+
in the console, write message, one message per line:
65+
`{ "topic": "challenge.notification.create", "originator": "challenge-api", "timestamp": "2019-05-14T00:00:00.000Z", "mime-type": "application/json", "payload": { "id": "1a4ef3a8-ed35-40d1-b8a6-7371a700d011", "typeId": "2f4ef3a8-ed35-40d1-b8a6-7371a700d098", "track": "CODE", "name": "test-for-legacy-challenge-processor", "description": "<p>test</p>", "phases": [{ "id": "id-1", "name": "registration", "isActive": true, "duration": 345600000 }, { "id": "id-2", "name": "submission", "isActive": true, "duration": 345600000 }, { "id": "id-3", "name": "checkpoint", "isActive": true, "duration": 172800000 } ], "prizeSets": [{ "type": "Code", "prizes": [{ "type": "first-place", "value": 1000 }, { "type": "second-place", "value": 500 }] }, { "type": "Check Point", "prizes": [{ "type": "first-place", "value": 200 }, { "type": "second-place", "value": 200 }, { "type": "third-place", "value": 200 }] }], "reviewType": "COMMUNITY", "markdown": false, "tags": ["Node.js", "NodeJS", "MongoDB", "AWS"], "projectId": 5087, "forumId": 33059 } }`
66+
- optionally, use another terminal, go to same directory, start a consumer to view the messages:
67+
`bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic challenge.notification.create --from-beginning`
68+
- writing/reading messages to/from other topics are similar
69+
70+
## Mock V5 Challenge API
71+
Mock V5 challenge api is under `test/mock` folder. You can use command `npm run mock-api` to start the server.
72+
73+
## Local deployment
74+
1. Make sure that Kafka is running as per instructions above.
75+
2. From the project root directory, run the following command to install the dependencies
76+
```
77+
npm install
78+
```
79+
3. To run linters if required
80+
```
81+
npm run lint
82+
83+
npm run lint:fix # To fix possible lint errors
84+
```
85+
4. Start the mock server
86+
```
87+
npm run mock-api
88+
```
89+
5. Start the processor and health check dropin
90+
```
91+
npm start
92+
```
93+
94+
## Testing
95+
- Run `npm run test` to execute unit tests and generate coverage report.
96+
- RUN `npm run e2e` to execute e2e tests and generate coverage report.
97+
98+
## Verification
99+
Refer `Verification.md`

Verification.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Topcoder - Legacy Groups Processor
2+
3+
## Verification
4+
start Kafka server, start mock api server and start the processor
5+
6+
1. start kafka-console-producer to write messages to `challenge.notification.create` topic:
7+
`bin/kafka-console-producer.sh --broker-list localhost:9092 --topic challenge.notification.create`
8+
2. write message:
9+
`{ "topic": "challenge.notification.create","originator": "challenge-api","timestamp": "2019-05-14T00:00:00.000Z","mime-type": "application/json","payload": { "id": "1a4ef3a8-ed35-40d1-b8a6-7371a700d011","typeId": "2f4ef3a8-ed35-40d1-b8a6-7371a700d098","track": "CODE","name": "test-for-legacy-challenge-processor","description": "<p>test</p>","phases": [{ "id": "id-1","name": "registration","isActive": true, "duration": 345600000 }, { "id": "id-2","name": "submission","isActive": true, "duration": 345600000 }, { "id": "id-3","name": "checkpoint","isActive": true, "duration": 172800000 } ], "prizeSets": [{ "type": "Code","prizes": [{ "type": "first-place", "value": 1000 }, { "type": "second-place","value": 500 }] }, { "type": "Check Point", "prizes": [{ "type": "first-place","value": 200 }, { "type": "second-place","value": 200 }, { "type": "third-place","value": 200 }] }],"reviewType": "COMMUNITY","markdown": false,"tags": ["Node.js","NodeJS","MongoDB","AWS"],"projectId": 5087,"forumId": 33059 } }`
10+
3. Watch the app console, It will show message successfully handled. And has info log `Create challenge entity in legacy system, the legacy id is XXX`. Now mark down the legacy id.
11+
4. Wait for a short period(1 minute), Then go to `https://api.topcoder-dev.com/v4/challenges/<legacy_id>` to verify the challenge has been created in legacy system. Note CODE challenge doesn't have checkpoint prize/phase, so the checkpoint prize is 0 in the legacy system.
12+
5. start kafka-console-producer to write messages to `challenge.notification.update` topic:
13+
`bin/kafka-console-producer.sh --broker-list localhost:9092 --topic challenge.notification.update`
14+
6. write message(Use the legacy id you mark down in step 3, as a number):
15+
`{ "topic": "challenge.notification.update","originator": "challenge-api","timestamp": "2019-05-14T00:00:00.000Z","mime-type": "application/json","payload": { "legacyId": <legacy_id>, "id": "1a4ef3a8-ed35-40d1-b8a6-7371a700d011","typeId": "2f4ef3a8-ed35-40d1-b8a6-7371a700d098","track": "CODE","name": "update-for-legacy-challenge-processor","description": "#Title\n##sub title 1\ntext\n##sub title2\nanother text\n","phases": [{ "id": "id-1","name": "registration","isActive": true, "duration": 345600000 }, { "id": "id-2","name": "submission","isActive": true, "duration": 345600000 }], "prizeSets": [{ "type": "Code","prizes": [{ "type": "first-place", "value": 800 }, { "type": "second-place","value": 400 }]}],"reviewType": "COMMUNITY","markdown":true,"tags": ["Node.js","NodeJS"],"projectId": 5087,"forumId": 33059 } }`
16+
7. Wait for a short period(1 minute), Then go to `https://api.topcoder-dev.com/v4/challenges/<legacy_id>` to verify the challenge has been updated in legacy system.
17+
8. Repeat step 1 to 7, to create other type of challenge. Here is the message payload for creating a Design challenge with checkpoint prizes:
18+
`{ "topic": "challenge.notification.create","originator": "challenge-api","timestamp": "2019-05-14T00:00:00.000Z","mime-type": "application/json","payload": { "id": "1a4ef3a8-ed35-40d1-b8a6-7371a700d011","typeId": "3f4ef3a8-ed35-40d1-b8a6-7371a700d098","track": "WEB_DESIGNS","name": "test-design-demo","description": "<p>test design</p>","phases": [{ "id": "id-1","name": "registration","isActive": true, "duration": 345600000 }, { "id": "id-2","name": "submission","isActive": true, "duration": 345600000 }, { "id": "id-3","name": "checkpoint","isActive": true, "duration": 172800000 } ], "prizeSets": [{ "type": "Code","prizes": [{ "type": "first-place", "value": 1000 }, { "type": "second-place","value": 500 }] }, { "type": "Check Point", "prizes": [{ "type": "first-place","value": 200 }, { "type": "second-place","value": 200 }, { "type": "third-place","value": 200 }] }],"reviewType": "COMMUNITY","markdown": false,"tags": ["Node.js","NodeJS","MongoDB","AWS"],"projectId": 5087,"forumId": 33059 } }`
19+
20+
21+
## Unit test Coverage
22+
51 passing (23s)
23+
24+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
25+
----------------------|----------|----------|----------|----------|-------------------|
26+
All files | 94.05 | 86.21 | 96.67 | 93.75 | |
27+
config | 100 | 100 | 100 | 100 | |
28+
default.js | 100 | 100 | 100 | 100 | |
29+
test.js | 100 | 100 | 100 | 100 | |
30+
src | 100 | 100 | 100 | 100 | |
31+
bootstrap.js | 100 | 100 | 100 | 100 | |
32+
constants.js | 100 | 100 | 100 | 100 | |
33+
src/common | 87.34 | 50 | 94.74 | 87.34 | |
34+
helper.js | 73.33 | 0 | 83.33 | 73.33 | 16,17,18,20 |
35+
logger.js | 90.63 | 60 | 100 | 90.63 |32,55,60,84,98,118 |
36+
src/services | 100 | 100 | 100 | 100 | |
37+
ProcessorService.js | 100 | 100 | 100 | 100 | |
38+
39+
## E2E test Coverage
40+
41+
54 passing (2m)
42+
43+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
44+
----------------------|----------|----------|----------|----------|-------------------|
45+
All files | 95.37 | 87.88 | 97.5 | 95.17 | |
46+
config | 100 | 100 | 100 | 100 | |
47+
default.js | 100 | 100 | 100 | 100 | |
48+
test.js | 100 | 100 | 100 | 100 | |
49+
src | 94.12 | 66.67 | 90 | 94 | |
50+
app.js | 93.75 | 66.67 | 90 | 93.62 | 48,61,86 |
51+
bootstrap.js | 100 | 100 | 100 | 100 | |
52+
constants.js | 100 | 100 | 100 | 100 | |
53+
src/common | 91.14 | 66.67 | 100 | 91.14 | |
54+
helper.js | 93.33 | 50 | 100 | 93.33 | 18 |
55+
logger.js | 90.63 | 70 | 100 | 90.63 |32,55,60,84,98,118 |
56+
src/services | 100 | 100 | 100 | 100 | |
57+
ProcessorService.js | 100 | 100 | 100 | 100 | |

config/default.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* The default configuration file.
3+
*/
4+
5+
module.exports = {
6+
LOG_LEVEL: process.env.LOG_LEVEL || 'debug',
7+
8+
KAFKA_URL: process.env.KAFKA_URL || 'localhost:9092',
9+
// below are used for secure Kafka connection, they are optional
10+
// for the local Kafka, they are not needed
11+
KAFKA_CLIENT_CERT: process.env.KAFKA_CLIENT_CERT,
12+
KAFKA_CLIENT_CERT_KEY: process.env.KAFKA_CLIENT_CERT_KEY,
13+
14+
// Kafka group id
15+
KAFKA_GROUP_ID: process.env.KAFKA_GROUP_ID || 'legacy-challenge-processor',
16+
17+
CREATE_CHALLENGE_TOPIC: process.env.CREATE_CHALLENGE_TOPIC || 'challenge.notification.create',
18+
UPDATE_CHALLENGE_TOPIC: process.env.UPDATE_CHALLENGE_TOPIC || 'challenge.notification.update',
19+
20+
AUTH0_URL: process.env.AUTH0_URL || 'https://topcoder-dev.auth0.com/oauth/token',
21+
AUTH0_AUDIENCE: process.env.AUTH0_AUDIENCE || 'https://m2m.topcoder-dev.com/',
22+
TOKEN_CACHE_TIME: process.env.TOKEN_CACHE_TIME || 90,
23+
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID || 'e6oZAxnoFvjdRtjJs1Jt3tquLnNSTs0e',
24+
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET || 'OGCzOnQkhYTQpZM3NI0sD--JJ_EPcm2E7707_k6zX11m223LrRK1-QZL4Pon4y-D',
25+
AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL,
26+
27+
V4_CHALLENGE_API_URL: process.env.V4_CHALLENGE_API_URL || 'https://api.topcoder-dev.com/v4/challenges',
28+
V4_PLATFORMS_API_URL: process.env.V4_PLATFORMS_API_URL || 'https://api.topcoder-dev.com/v4/platforms',
29+
V4_TECHNOLOGIES_API_URL: process.env.V4_TECHNOLOGIES_API_URL || 'https://api.topcoder-dev.com/v4/technologies',
30+
V5_CHALLENGE_API_URL: process.env.V5_CHALLENGE_API_URL || 'http://localhost:4000/v5/challenges',
31+
V5_CHALLENGE_TYPE_API_URL: process.env.V5_CHALLENGE_TYPE_API_URL || 'http://localhost:4000/v5/challengeTypes'
32+
}

config/test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* The test configuration.
3+
*/
4+
5+
module.exports = {
6+
MOCK_API_PORT: 4000,
7+
WAIT_TIME: 1500,
8+
V4_CHALLENGE_API_URL: 'http://localhost:4000/v4/challenges'
9+
}

0 commit comments

Comments
 (0)