Skip to content

Commit 37af38c

Browse files
Merge pull request #1 from vitalii-codefresh/develop
Develop
2 parents 289454c + 64260b7 commit 37af38c

24 files changed

+1234
-1
lines changed

.github/workflows/blank.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,7 @@ jobs:
2828
# Runs a set of commands using the runners shell
2929
- name: Run a multi-line script
3030
run: |
31-
yarn test,
31+
cd app1
32+
yarn install
33+
yarn test
3234
echo test, and deploy your project.

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules
2+
build
3+
npm-debug.log
4+
.nyc
5+
.env
6+
.DS_Store
7+
.idea
8+
configmap
9+
app3
10+
11+
/gitops/single-service/other/

app1/.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.env
2+
node_modules
3+
build
4+
data/*

app1/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ARG BUILD_VAR="buildVar"
2+
FROM node:20.18.0-alpine3.20
3+
LABEL authors="vitalii-codefresh"
4+
WORKDIR app/
5+
COPY . .
6+
EXPOSE 8002
7+
VOLUME /myvol
8+
RUN yarn install && npm -g uninstall npm
9+
10+
ENTRYPOINT ["node", "index.js"]

app1/index.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
const { log } = require('console');
2+
const express = require('express');
3+
const crypto = require(`crypto`);
4+
const { appendFile, readFile } = require("fs/promises");
5+
const { readdirSync } = require("fs");
6+
const { resolve } = require("path");
7+
require('dotenv').config();
8+
9+
const router = express.Router();
10+
const port = process.env.PORT || 8000;
11+
const serviceId = crypto.randomBytes(5).toString("hex");
12+
const resultFile = "./data/results.csv";
13+
14+
const app = express(); // Експортуємо цей екземпляр
15+
16+
17+
router.get('/', (req, res) => {
18+
res.statusCode = 200;
19+
res.header("Content-Type", "application/json");
20+
res.json({ result: "hello", serviceId });
21+
});
22+
23+
router.get('/add', express.json(), async (req, res) => {
24+
const body = req.body;
25+
if (!body || typeof body.firstValue === 'undefined' || typeof body.secondValue === 'undefined') {
26+
res.statusCode = 400;
27+
res.send("body is required");
28+
return;
29+
}
30+
const firstValue = body.firstValue;
31+
const secondValue = body.secondValue;
32+
const result = firstValue + secondValue;
33+
await writeResult(result, serviceId);
34+
res.send({ result, serviceId });
35+
});
36+
37+
router.get('/getResults', async (req, res) => {
38+
try {
39+
const results = await readResults();
40+
res.json({ results, serviceId });
41+
} catch (e) {
42+
res.statusCode = 500;
43+
res.send("internal error");
44+
}
45+
});
46+
47+
router.get('/getDir', async (req, res) => {
48+
try {
49+
const myPath = resolve();
50+
const files = readdirSync("./");
51+
const dataContent = readdirSync("./data");
52+
res.json({ files, dataContent, myPath, serviceId });
53+
} catch (e) {
54+
res.statusCode = 500;
55+
res.send("internal error");
56+
}
57+
});
58+
59+
app.use("/app1", router);
60+
61+
module.exports = { app };
62+
63+
if (require.main === module) {
64+
app.listen(port, () => {
65+
log(`server starts at port ${port}`, `id is - ${serviceId}`);
66+
});
67+
}
68+
69+
70+
async function writeResult(result, serviceId) {
71+
await appendFile(resultFile, `${result};SERVICE_ID-${serviceId};` + "\n");
72+
}
73+
74+
async function readResults() {
75+
return readFile(resultFile, { encoding: "utf-8" });
76+
}

app1/package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "simple-server",
3+
"version": "1.0.0",
4+
"description": "To make it easy for you to get started with GitLab, here's a list of recommended next steps.",
5+
"main": "app1/index.js",
6+
"scripts": {
7+
"test": "npx jest "
8+
},
9+
"keywords": [],
10+
"author": "",
11+
"license": "ISC",
12+
"dependencies": {
13+
"dotenv": "^16.4.1",
14+
"express": "^4.18.2",
15+
"jest": "27.5.1",
16+
"ip": "2.0.1"
17+
},
18+
"devDependencies": {
19+
"supertest": "^7.1.4"
20+
},
21+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
22+
}

app1/test/app1.test.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
const request = require('supertest');
2+
const { app } = require('../index');
3+
4+
jest.mock('fs/promises', () => ({
5+
appendFile: jest.fn(() => Promise.resolve()),
6+
readFile: jest.fn(() => Promise.resolve('10;SERVICE_ID-abcde;\n20;SERVICE_ID-fghij;\n')),
7+
}));
8+
9+
jest.mock('fs', () => ({
10+
readdirSync: jest.fn((path) => {
11+
if (path === './') return ['app.js', 'package.json', 'data'];
12+
if (path === './data') return ['results.csv'];
13+
return [];
14+
}),
15+
}));
16+
17+
describe('Express App Tests', () => {
18+
let server;
19+
20+
beforeAll((done) => {
21+
server = app.listen(0, done);
22+
});
23+
afterAll((done) =>{
24+
server.close(done);
25+
});
26+
27+
test('GET /app1/ should return hello and serviceId', async () => {
28+
const res = await request(server).get('/app1/');
29+
expect(res.statusCode).toEqual(200);
30+
expect(res.headers['content-type']).toMatch(/application\/json/);
31+
expect(res.body.result).toEqual('hello');
32+
expect(res.body).toHaveProperty('serviceId');
33+
});
34+
35+
test('GET /app1/add with valid body should return sum and serviceId', async () => {
36+
const res = await request(server)
37+
.get('/app1/add')
38+
.send({ firstValue: 5, secondValue: 3 })
39+
.set('Content-Type', 'application/json');
40+
41+
expect(res.statusCode).toEqual(200);
42+
expect(res.body.result).toEqual(8);
43+
expect(res.body).toHaveProperty('serviceId');
44+
expect(require('fs/promises').appendFile).toHaveBeenCalledWith(
45+
'./data/results.csv',
46+
expect.stringContaining('8;SERVICE_ID-'),
47+
);
48+
});
49+
50+
test('GET /app1/add without body should return 400', async () => {
51+
const res = await request(server).get('/app1/add'); // Без .send()
52+
expect(res.statusCode).toEqual(400);
53+
expect(res.text).toEqual('body is required');
54+
});
55+
56+
test('GET /app1/add with missing firstValue should return 400', async () => {
57+
const res = await request(server)
58+
.get('/app1/add')
59+
.send({ secondValue: 3 })
60+
.set('Content-Type', 'application/json');
61+
expect(res.statusCode).toEqual(400);
62+
expect(res.text).toEqual('body is required');
63+
});
64+
65+
test('GET /app1/getResults should return results from file', async () => {
66+
const res = await request(server).get('/app1/getResults');
67+
expect(res.statusCode).toEqual(200);
68+
expect(res.body.results).toEqual('10;SERVICE_ID-abcde;\n20;SERVICE_ID-fghij;\n');
69+
expect(res.body).toHaveProperty('serviceId');
70+
// Перевіряємо, що readFile був викликаний
71+
expect(require('fs/promises').readFile).toHaveBeenCalledWith(
72+
'./data/results.csv',
73+
{ encoding: 'utf-8' }
74+
);
75+
});
76+
77+
test('GET /app1/getDir should return directory contents and path', async () => {
78+
const res = await request(server).get('/app1/getDir');
79+
expect(res.statusCode).toEqual(200);
80+
expect(res.body.files).toEqual(['app.js', 'package.json', 'data']);
81+
expect(res.body.dataContent).toEqual(['results.csv']);
82+
expect(res.body).toHaveProperty('myPath');
83+
expect(res.body).toHaveProperty('serviceId');
84+
});
85+
});

app2/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.env
2+
node_modules
3+
build

app2/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ARG BUILD_VAR="buildVar"
2+
FROM node:20.11-alpine3.18
3+
LABEL authors="vitalii-codefresh"
4+
WORKDIR app/
5+
COPY . .
6+
EXPOSE 8010
7+
VOLUME /myvol
8+
RUN ["npm", "i"]
9+
10+
ENTRYPOINT ["node", "index2.js"]

app2/index2.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const {log} = require('console');
2+
const express = require('express')
3+
const crypto = require(`crypto`);
4+
require('dotenv').config();
5+
const app1Host = process.env.APP1_HOST;
6+
const router = express.Router();
7+
const port = 8010;
8+
const serviceId = crypto.randomBytes(5).toString("hex");
9+
const app = express();
10+
11+
router.get('/', (req, res) => {
12+
res.statusCode = 200;
13+
res.header("Content-Type", "application/json");
14+
res.json({result: "hello", serviceId});
15+
})
16+
17+
router.get('/getRes', express.json(), async (req, res) => {
18+
if (!app1Host) {
19+
res.statusCode = 500;
20+
res.send("APP1_HOST - variable was not set");
21+
return;
22+
}
23+
try {
24+
const results = await (await fetch(`${app1Host}/getResults`)).json();
25+
res.send({results, serviceId});
26+
} catch (e) {
27+
console.error(e)
28+
res.statusCode = 500;
29+
res.send("Internal error");
30+
}
31+
});
32+
33+
app.use("/app2", router);
34+
35+
app.listen(port, () => {
36+
log(`server starts at port ${port}`, `id is - ${serviceId}`);
37+
console.log("app1Host is :"+ app1Host);
38+
})

0 commit comments

Comments
 (0)