Skip to content

Commit 3f35ae5

Browse files
committed
[Task] #43 code cleanup
1 parent 4ff8857 commit 3f35ae5

8 files changed

Lines changed: 328 additions & 318 deletions

File tree

.github/workflows/main.yml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,28 @@ on:
1010
jobs:
1111
build:
1212
runs-on: ubuntu-latest
13-
14-
13+
environment: dev
14+
env:
15+
NODE_ENV: ${{ vars.NODE_ENV }}
16+
1517
steps:
1618
- uses: actions/checkout@v3
1719
- name: Use Node.js ${{ matrix.node-version }}
1820
uses: actions/setup-node@v3
1921
with:
2022
node-version: '20'
2123
cache: 'npm'
24+
- run: echo "NODE_ENV = $NODE_ENV"
2225
- run: npm ci
2326
- run: npm run build --if-present
2427
- name: Start server
2528
run: |
2629
sudo npm start &
27-
sleep 8 # Give server some time to start
30+
sleep 15 # Give server some time to start
2831
- name: Check if server is running
2932
run: |
3033
curl --fail http://localhost:80 || exit 1
31-
- name: Run tests
32-
run: npm run test
34+
- name: Run app tests
35+
run: npm run test:app
36+
37+

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
"dev:static": "nodemon --config nodemon-static.json",
1515
"lint": "eslint . --fix",
1616
"lint:client": "eslint httpdocs/js/ --fix",
17-
"test": "jest"
17+
"test": "jest",
18+
"test:app": "jest src/tests/app.test.ts",
19+
"test:login": "jest src/tests/login.test.ts",
20+
"test:unit": "jest src/tests/unit.test.ts",
21+
"test:integration": "jest src/tests/integration.test.ts"
1822
},
1923
"keywords": [],
2024
"author": "Type-Style",

src/app.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ app.use((req, res, next) => { // limit body for specific http methods
5252
// routes
5353
app.get('/', (req, res) => {
5454
logger.log(req.ip + " - " + res.locals.ip, true);
55-
console.count();
56-
res.send('Hello World, via TypeScript and Node.js! ' + res.locals.ip);
55+
res.send('Hello World, via TypeScript and Node.js! ' + `ENV: ${process.env.NODE_ENV}`);
5756
});
5857

5958
app.use('/write', writeRouter);

src/controller/read.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ router.get("/login/", baseSlowDown, baseRateLimiter, async function login(req: R
4444

4545
router.post("/login/", loginSlowDown, async function postLogin(req: Request, res: Response, next: NextFunction) {
4646
logger.log(req.body);
47-
res.locals.text = "post recieved";
4847
loginLimiter(req, res, async () => {
4948
let validLogin = false;
5049
const user = req.body.user;

src/tests/integration.test.ts

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
import axios, { AxiosError } from 'axios';
2+
import qs from 'qs';
3+
import fs from "fs";
4+
import path from "path";
5+
6+
async function callServer(timestamp = new Date().getTime(), query: string, expectStatus: number = 200, method: string = "HEAD") {
7+
const url = new URL("http://localhost:80/write?");
8+
url.search = "?" + query;
9+
const params = new URLSearchParams(url.search);
10+
params.set("timestamp", timestamp.toString());
11+
url.search = params.toString();
12+
13+
14+
let response;
15+
if (expectStatus == 200) {
16+
if (method == "GET") {
17+
response = await axios.get(url.toString());
18+
} else {
19+
response = await axios.head(url.toString());
20+
}
21+
expect(response.status).toBe(expectStatus);
22+
} else {
23+
try {
24+
await axios.head(url.toString());
25+
} catch (error) {
26+
const axiosError = error as AxiosError;
27+
if (axiosError.response) {
28+
expect(axiosError.response.status).toBe(expectStatus);
29+
} else {
30+
console.error(axiosError);
31+
}
32+
}
33+
}
34+
}
35+
36+
37+
function getData(filePath: string) {
38+
const data = fs.readFileSync(filePath);
39+
return JSON.parse(data.toString());
40+
}
41+
42+
function isInRange(actual: string | number, expected: number, range: number) {
43+
return Math.abs(Number(actual) - expected) <= range;
44+
}
45+
46+
async function verifiedRequest(url: string, token: string) {
47+
const response = await axios({
48+
method: 'get',
49+
url: url,
50+
headers: {
51+
'Authorization': `Bearer ${token}`,
52+
}
53+
});
54+
return response;
55+
}
56+
57+
58+
59+
describe('HEAD /write', () => {
60+
// eslint-disable-next-line jest/expect-expect
61+
it('with all parameters correctly set it should succeed', async () => {
62+
await callServer(undefined, "user=xx&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=150.000&heading=180.0&key=test", 200);
63+
});
64+
65+
// eslint-disable-next-line jest/expect-expect
66+
it('without key it sends 403', async () => {
67+
await callServer(undefined, "user=xx&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=150.000&heading=180.0", 403);
68+
});
69+
70+
// eslint-disable-next-line jest/expect-expect
71+
it('with user length not equal to 2 it sends 422', async () => {
72+
await callServer(undefined, "user=x&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=150.000&heading=180.0&key=test", 422);
73+
});
74+
75+
// eslint-disable-next-line jest/expect-expect
76+
it('with lat not between -90 and 90 it sends 422', async () => {
77+
await callServer(undefined, "user=xx&lat=91.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=150.000&heading=180.0&key=test", 422);
78+
});
79+
80+
// eslint-disable-next-line jest/expect-expect
81+
it('with lon not between -180 and 180 it sends 422', async () => {
82+
await callServer(undefined, "user=xx&lat=45.000&lon=181.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=150.000&heading=180.0&key=test", 422);
83+
});
84+
85+
// eslint-disable-next-line jest/expect-expect
86+
it('with timestamp to old sends 422', async () => {
87+
const timestamp = new Date().getTime() - 24 * 60 * 60 * 1000 * 2; // two days ago
88+
await callServer(timestamp, "user=xx&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=150.000&heading=180.0&key=test", 422);
89+
})
90+
91+
// eslint-disable-next-line jest/expect-expect
92+
it('with hdop not between 0 and 100 it sends 422', async () => {
93+
await callServer(undefined, "user=xx&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=101.0&altitude=5000.000&speed=150.000&heading=180.0&key=test", 422);
94+
});
95+
96+
// eslint-disable-next-line jest/expect-expect
97+
it('with altitude not between 0 and 10000 it sends 422', async () => {
98+
await callServer(undefined, "user=xx&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=10001.000&speed=150.000&heading=180.0&key=test", 422);
99+
});
100+
101+
// eslint-disable-next-line jest/expect-expect
102+
it('with speed not between 0 and 300 it sends 422', async () => {
103+
await callServer(undefined, "user=xx&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=301.000&heading=180.0&key=test", 422);
104+
});
105+
106+
// eslint-disable-next-line jest/expect-expect
107+
it('with heading not between 0 and 360 it sends 422', async () => {
108+
await callServer(undefined, "user=xx&lat=45.000&lon=90.000&timestamp=R3Pl4C3&hdop=50.0&altitude=5000.000&speed=150.000&heading=361.0&key=test", 422);
109+
});
110+
});
111+
112+
113+
// describe("GET /write", () => {
114+
// const date = new Date();
115+
// const formattedDate = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
116+
// const dirPath = path.resolve(__dirname, '../../dist/data/');
117+
// const filePath = path.resolve(dirPath, `data-${formattedDate}.json`);
118+
119+
// it('there should a file of the current date', async () => {
120+
// await await callServer(undefined, "user=xx&lat=52.51451&lon=13.35105&timestamp=R3Pl4C3&hdop=20.0&altitude=5000.000&speed=150.000&heading=180.0&key=test", 200, "GET");
121+
122+
// fs.access(filePath, fs.constants.F_OK, (err) => {
123+
// expect(err).toBeFalsy();
124+
// });
125+
// });
126+
127+
// it('the file contains valid JSON', async () => {
128+
// fs.readFile(filePath, 'utf8', (err, data) => {
129+
// expect(err).toBeFalsy();
130+
// try {
131+
// JSON.parse(data);
132+
// } catch (e) {
133+
// expect(e).toBeFalsy();
134+
// }
135+
// });
136+
// });
137+
138+
// it('after second call and the JSON entries length is 2', () => {
139+
// return new Promise<void>(done => {
140+
// setTimeout(async () => {
141+
// await await callServer(undefined, "user=xx&lat=52.51627&lon=13.37770&timestamp=R3Pl4C3&hdop=50&altitude=4000.000&speed=150.000&heading=180.0&key=test", 200, "GET");
142+
// const jsonData = getData(filePath);
143+
144+
// expect(jsonData.entries.length).toBe(2);
145+
146+
// done();
147+
// }, 3500);
148+
// })
149+
// });
150+
151+
// it('the time is correct', () => {
152+
// const jsonData = getData(filePath);
153+
// const entry = jsonData.entries.at(-1)
154+
155+
// expect(entry.time.created).toBeGreaterThan(date.getTime());
156+
// expect(entry.time.diff).toBeGreaterThan(3.5);
157+
// expect(entry.time.diff).toBeLessThan(4.6);
158+
159+
160+
// const germanDayPattern = "(Montag|Dienstag|Mittwoch|Donnerstag|Freitag|Samstag|Sonntag)";
161+
// const dayOfMonthPattern = "(0?[1-9]|[12][0-9]|3[01])";
162+
// const germanMonthPattern = "(Januar|Februar|März|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember)";
163+
// const yearPattern = "(\\d{4})";
164+
// const timePattern = "([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]";
165+
// const pattern = new RegExp(`^${germanDayPattern}, ${dayOfMonthPattern}. ${germanMonthPattern} ${yearPattern} um ${timePattern}$`);
166+
// const string = entry.time.createdString;
167+
// expect(pattern.test(string)).toBeTruthy();
168+
169+
// });
170+
171+
// it('the distance is correct', () => {
172+
// const jsonData = getData(filePath);
173+
// const entry = jsonData.entries.at(-1)
174+
175+
// expect(entry.distance.horizontal).toBeCloseTo(1813.926);
176+
// expect(entry.distance.vertical).toBe(-1000);
177+
// expect(entry.distance.total).toBeCloseTo(2071.311);
178+
// });
179+
180+
// it('the angle is correct', () => {
181+
// const jsonData = getData(filePath);
182+
// const entry = jsonData.entries.at(-1)
183+
184+
// expect(entry.angle).toBeCloseTo(83.795775);
185+
// });
186+
187+
// it('the speed is correct', () => {
188+
// const jsonData = getData(filePath);
189+
// const entry = jsonData.entries.at(-1)
190+
191+
// expect(isInRange(entry.speed.horizontal, 515, 10)).toBe(true);
192+
// expect(isInRange(entry.speed.vertical, -284, 10)).toBe(true);
193+
// expect(isInRange(entry.speed.total, 588, 15)).toBe(true);
194+
// });
195+
196+
// it('check ignore', async () => {
197+
// let jsonData = getData(filePath);
198+
// let entry = jsonData.entries[1];
199+
// const lastEntry = jsonData.entries[0];
200+
201+
// expect(entry.ignore).toBe(false); // current one to be false allways
202+
// expect(lastEntry.ignore).toBe(true); // last one to high hdop to be true
203+
204+
// await await callServer(undefined, "user=xx&lat=52.51627&lon=13.37770&timestamp=R3Pl4C3&hdop=50&altitude=4000.000&speed=150.000&heading=180.0&key=test", 200, "GET");
205+
// jsonData = getData(filePath);
206+
// entry = jsonData.entries[1]; // same data point, but not last now therefore ignore true
207+
// expect(entry.ignore).toBe(true);
208+
// });
209+
// });
210+
211+
212+
// describe('API calls', () => {
213+
// test(`1000 api calls`, async () => {
214+
// for (let i = 0; i < 1000; i++) {
215+
// const url = `http://localhost:80/write?user=xx&lat=${(52 + Math.random()).toFixed(3)}&lon=${(13 + Math.random()).toFixed(3)}&timestamp=${new Date().getTime()}&hdop=${(25 * Math.random()).toFixed(3)}&altitude=${i}&speed=88.888&heading=${(360 * Math.random()).toFixed(3)}&key=test`;
216+
// const response = await axios.get(url);
217+
// expect(response.status).toBe(200);
218+
// }
219+
// }, 20000); // adjust this to to fit your setup
220+
221+
// test(`length of json should not exceed 1000`, async () => {
222+
// const date = new Date();
223+
// const formattedDate = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
224+
// const dirPath = path.resolve(__dirname, '../../dist/data/');
225+
// const filePath = path.resolve(dirPath, `data-${formattedDate}.json`);
226+
// const jsonData = getData(filePath);
227+
// expect(jsonData.entries.length).toBeLessThanOrEqual(1000);
228+
// });
229+
// });
230+
231+
232+
// describe('read and login', () => {
233+
// let token = "";
234+
// const testData = qs.stringify({
235+
// user: "test",
236+
// password: "test",
237+
// });
238+
// test(`redirect without logged in`, async () => {
239+
// try {
240+
// await axios.get("http://localhost:80/read/");
241+
// } catch (error) {
242+
// const axiosError = error as AxiosError;
243+
// if (axiosError.response) {
244+
// expect(axiosError.response.status).toBe(401);
245+
// } else {
246+
// console.error(axiosError);
247+
// }
248+
// }
249+
// });
250+
251+
// it('test user can login', async () => {
252+
// const response = await axios.post('http://localhost:80/read/login', testData);
253+
254+
// expect(response.status).toBe(200);
255+
// expect(response.headers['content-type']).toEqual(expect.stringContaining('application/json'));
256+
// expect(response).toHaveProperty('data.token');
257+
// expect(response.data.token).not.toBeNull();
258+
// token = response.data.token;
259+
// })
260+
261+
// test('wrong token get error', async () => {
262+
// try {
263+
// await verifiedRequest("http://localhost:80/read?index=0", "justWrongValue");
264+
// } catch (error) {
265+
// const axiosError = error as AxiosError;
266+
// if (axiosError.response) {
267+
// expect(axiosError.response.status).toBe(403);
268+
// } else {
269+
// console.error(axiosError);
270+
// }
271+
// }
272+
// });
273+
274+
// test('verified request returns json', async () => {
275+
// const response = await verifiedRequest("http://localhost:80/read?index=0", token);
276+
// expect(response.status).toBe(200);
277+
// expect(response.headers['content-type']).toEqual(expect.stringContaining('application/json'));
278+
// });
279+
280+
// test(`index parameter to long`, async () => {
281+
// try {
282+
// await verifiedRequest("http://localhost:80/read?index=1234", token);
283+
// } catch (error) {
284+
// const axiosError = error as AxiosError;
285+
// if (axiosError.response) {
286+
// expect(axiosError.response.status).toBe(400);
287+
// } else {
288+
// console.error(axiosError);
289+
// }
290+
// }
291+
// });
292+
293+
// test(`index parameter to be a number`, async () => {
294+
// try {
295+
// await verifiedRequest("http://localhost:80/read?index=a9", token);
296+
// } catch (error) {
297+
// const axiosError = error as AxiosError;
298+
// if (axiosError.response) {
299+
// expect(axiosError.response.status).toBe(400);
300+
// } else {
301+
// console.error(axiosError);
302+
// }
303+
// }
304+
// });
305+
// test(`index parameter reduces length of json`, async () => {
306+
// const response = await verifiedRequest("http://localhost:80/read?index=999", token);
307+
// expect(response.status).toBe(200);
308+
// expect(response.data.entries.length).toBe(1);
309+
// });
310+
// });

0 commit comments

Comments
 (0)