Skip to content

Commit 2fc494e

Browse files
committed
Merge branch 'devDocker_v2' into reademe
2 parents 41ecd9a + dbf493c commit 2fc494e

File tree

89 files changed

+8171
-669
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+8171
-669
lines changed

__backend-tests__/alert.test.js

Lines changed: 0 additions & 37 deletions
This file was deleted.

__backend-tests__/chronosMethods.test.js

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jest.mock('../chronos_npm_package/controllers/mongo.js', () => ({
2424
health: jest.fn(config => config),
2525
communications: jest.fn(config => config),
2626
serverQuery: jest.fn(config => config),
27+
storeGrafanaAPIKey: jest.fn(config => config),
2728
}));
2829

2930
jest.mock('../chronos_npm_package/controllers/postgres.js', () => ({
@@ -144,7 +145,7 @@ describe('Chronos Config', () => {
144145
});
145146
});
146147
describe('kafka', () => {
147-
test('should check if kafka is functional', async () => {
148+
test('should check if kafka with MongoDB functional', async () => {
148149
const config = {
149150
microservice: 'test',
150151
interval: 300,
@@ -166,6 +167,25 @@ describe('Chronos Config', () => {
166167
expect(mongo.connect).toHaveBeenCalledWith(config);
167168
expect(mongo.serverQuery).toHaveBeenCalledWith(config);
168169
}
170+
});
171+
test('should check if kafka with PostgreSQL is functional', async () => {
172+
const config = {
173+
microservice: 'test',
174+
interval: 300,
175+
mode: 'micro',
176+
dockerized: true,
177+
database: {
178+
connection: 'REST',
179+
type: 'PostgreSQL',
180+
URI: process.env.CHRONOS_URI,
181+
},
182+
notifications: [],
183+
};
184+
const { database, dockerized } = config;
185+
const falseDock = { dockerized: false };
186+
const chronos = new Chronos(config);
187+
chronos.kafka();
188+
await helpers.testMetricsQuery(config);
169189
if (database.type === 'PostgreSQL') {
170190
expect(postgres.connect).toHaveBeenCalledWith(config);
171191
expect(postgres.serverQuery).toHaveBeenCalledWith(config);
@@ -174,11 +194,11 @@ describe('Chronos Config', () => {
174194
});
175195

176196
describe('kubernetes', () => {
177-
test('should check if kubernetes is functional', async () => {
197+
test('should check if kubernetes with mongodb is functional', async () => {
178198
const config = {
179199
microservice: 'test',
180200
interval: 300,
181-
mode: 'micro',
201+
mode: 'kubernetes',
182202
dockerized: true,
183203
database: {
184204
connection: 'REST',
@@ -193,9 +213,33 @@ describe('Chronos Config', () => {
193213
chronos.kubernetes();
194214
await helpers.testMetricsQuery(config);
195215
if (database.type === 'MongoDB') {
196-
expect(mongo.connect).toHaveBeenCalledWith(config);
216+
await expect(mongo.connect).toHaveBeenCalledWith(config);
217+
await expect(mongo.storeGrafanaAPIKey).toHaveBeenCalledWith(config);
197218
expect(mongo.serverQuery).toHaveBeenCalledWith(config);
198219
}
220+
if (database.type === 'PostgreSQL') {
221+
expect(postgres.connect).toHaveBeenCalledWith(config2);
222+
expect(postgres.serverQuery).toHaveBeenCalledWith(config2);
223+
}
224+
});
225+
test('should check if kubernetes with PostGres is functional', async () => {
226+
const config = {
227+
microservice: 'test',
228+
interval: 300,
229+
mode: 'kubernetes',
230+
dockerized: true,
231+
database: {
232+
connection: 'REST',
233+
type: 'PostgreSQL',
234+
URI: process.env.CHRONOS_URI,
235+
},
236+
notifications: [],
237+
};
238+
const { database, dockerized } = config;
239+
const falseDock = { dockerized: false };
240+
const chronos = new Chronos(config);
241+
chronos.kubernetes();
242+
await helpers.testMetricsQuery(config);
199243
if (database.type === 'PostgreSQL') {
200244
expect(postgres.connect).toHaveBeenCalledWith(config);
201245
expect(postgres.serverQuery).toHaveBeenCalledWith(config);

__backend-tests__/dockerHelper.test.js

Whitespace-only changes.

__backend-tests__/healthHelpers.test.js

Whitespace-only changes.

__backend-tests__/jest.config.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
module.exports = {
2-
// testEnvironment: 'node', // Use the Node.js environment for testing
3-
// roots: ['<rootDir>/controllers'], // Set the root directory for test files
4-
5-
// testRegex: '(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
6-
7-
// // Code coverage settings
8-
// collectCoverage: true,
9-
// coverageDirectory: 'coverage',
2+
// testEnvironment: 'node', // Use the Node.js environment for testing
3+
// roots: ['<rootDir>/controllers'], // Set the root directory for test files
104

11-
// // Specify the test path patterns to ignore frontend tests
12-
// testPathIgnorePatterns: ['/node_modules/', '/__tests__/'],
13-
// };
5+
// testRegex: '(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
146

15-
// =======
7+
// // Code coverage settings
8+
// collectCoverage: true,
9+
// coverageDirectory: 'coverage',
10+
11+
// // Specify the test path patterns to ignore frontend tests
12+
// testPathIgnorePatterns: ['/node_modules/', '/__tests__/'],
13+
// };
14+
15+
// =======
1616
roots: ['<rootDir>'], // Set the root directory for test files (adjust this path to your test folder)
1717

1818
testRegex: '(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
1919

2020
// Code coverage settings
2121
collectCoverage: true,
2222
coverageDirectory: 'coverage',
23-
2423
// Specify the test path patterns to ignore (frontend tests)
2524
testPathIgnorePatterns: ['/node_modules/', '/__tests__/'],
2625
};
27-

__backend-tests__/postgres.test.js

Whitespace-only changes.

__backend-tests__/utilities.test.js

Whitespace-only changes.
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import React, { useEffect, useState, useContext } from 'react';
2+
import { HealthContext } from '../context/HealthContext';
3+
import { QueryContext } from '../context/QueryContext';
4+
import GrafanaEventChart from '../charts/GrafanaEventChart';
5+
import { Button } from '@material-ui/core';
6+
import { useParams } from 'react-router-dom';
7+
8+
interface HealthContainerProps {
9+
sizing: string;
10+
colourGenerator: Function;
11+
category: string;
12+
//currentService: string;
13+
}
14+
15+
interface Params {
16+
service: string;
17+
}
18+
19+
interface DataObject {
20+
[key: string]: {
21+
value: string[],
22+
time: string[],
23+
id: string,
24+
token: string
25+
};
26+
}
27+
interface DockerDataObject {
28+
[key: string]: DataObject
29+
}
30+
31+
const DockerHealthContainer: React.FC<HealthContainerProps> = React.memo(props => {
32+
const { healthData } = useContext(HealthContext);
33+
const { selectedMetrics } = useContext(QueryContext);
34+
const { service } = useParams<keyof Params>() as Params;
35+
const [healthChartsArr, setHealthChartsArr] = useState<JSX.Element[]>([]);
36+
const { sizing, colourGenerator, category } = props;
37+
const [currIndex, setCurrIndex] = useState(0);
38+
const [currChunk, setCurrChunk] = useState<JSX.Element[]>([]);
39+
const chunkSize = 7;
40+
let [isGrafana, setIsGrafana] = useState(false);
41+
/**
42+
* This function filters the selectedMetrics array down to only metrics that match the category of this instance of HealthContainer.
43+
* Once that has finished, it then filters the healthData down to the current category and the filteredMetrics.
44+
*/
45+
46+
function nextChunk() {
47+
const nextChunk = healthChartsArr.slice(currIndex, currIndex + chunkSize);
48+
setCurrChunk(nextChunk);
49+
setCurrIndex(currIndex + chunkSize);
50+
}
51+
function prevChunk() {
52+
const prevChunk = healthChartsArr.slice(currIndex - 2 * chunkSize, currIndex - chunkSize);
53+
setCurrChunk(prevChunk);
54+
setCurrIndex(currIndex - chunkSize);
55+
}
56+
57+
const filterSelectedMetricsAndHealthData = (): DockerDataObject => {
58+
// define a filtered health data object for output
59+
// define an array of filteredMetricNames for later use
60+
const filteredHealthData = {};
61+
const filteredMetricNames: string[] = [];
62+
// iterate over the selectedMetrics from QueryContext
63+
selectedMetrics.forEach(metricObj => {
64+
// due to the way the data is stored, each metricObj has a key of category, and an array of selected metrics as a value
65+
const metricCategory = Object.keys(metricObj)[0];
66+
const metricValuesArray = metricObj[metricCategory];
67+
// if the current metricObj's category matches our instance's current category, iterate through its array of values
68+
if (metricCategory === category) {
69+
metricValuesArray.forEach(metricName => {
70+
filteredMetricNames.push(metricName); // add the metricNames to the filteredMetricNames array
71+
});
72+
}
73+
});
74+
/*
75+
Now that we've defined which of the user's selected metrics belong in this category, iterate over the healthData object
76+
and filter it down to the selected category and metrics.
77+
*/
78+
for (const service in healthData) {
79+
filteredHealthData[service] = {};
80+
const categoryObjects = healthData[service];
81+
for (const categoryName in categoryObjects) {
82+
// if the category in healthData matches the category passed down to this HealthContainer, iterate over the related metrics
83+
if (categoryName === category) {
84+
const metricObjects = categoryObjects[categoryName];
85+
for (const metric in metricObjects) {
86+
// if the metric title matches any element in the filtered metrics array, add the metric serviceName to the filteredHealthData object, then add the metrics for that service
87+
if (filteredMetricNames.includes(metric)) {
88+
filteredHealthData[service][metric] = metricObjects[metric];
89+
}
90+
}
91+
}
92+
}
93+
}
94+
return filteredHealthData;
95+
};
96+
97+
// helper function for geting only the names of the metrics
98+
const getIndex = (str: string, substr: string, ind: number): number => {
99+
let Len = str.length,
100+
i = -1;
101+
while (ind-- && i++ < Len) {
102+
i = str.indexOf(substr, i);
103+
if (i < 0) break;
104+
}
105+
return i;
106+
}
107+
108+
// function to generate charts using the type-sorted data
109+
const generateHealthCharts = (sortedData: DockerDataObject): void => {
110+
//onst chartsArray: JSX.Element[] = [];
111+
const grafanaChartsArray: JSX.Element[] = [];
112+
//let parsedName: string = '';
113+
const keymaker = () => {
114+
return Math.floor(Math.random() * 1000);
115+
};
116+
// iterate over the sortedData and create a chart for each data type and each service of that data
117+
for (const dataType in sortedData) {
118+
const metricObjects = sortedData[service];
119+
for (const metricName in metricObjects) {
120+
// pass down the value of the current data type and service
121+
const chartData = metricObjects[metricName];
122+
const token = chartData.token;
123+
// chartsArray.push(
124+
// <HealthChart
125+
// key={'H' + keymaker()}
126+
// dataType={dataType}
127+
// serviceName={serviceName}
128+
// chartData={chartData}
129+
// categoryName={category}
130+
// sizing={sizing}
131+
// colourGenerator={colourGenerator}
132+
// />
133+
// );
134+
console.log("plotting grafana")
135+
grafanaChartsArray.push(
136+
<GrafanaEventChart metricName={metricName} token={token} />);
137+
138+
}
139+
}
140+
console.log(grafanaChartsArray)
141+
setHealthChartsArr(grafanaChartsArray);
142+
setCurrChunk(grafanaChartsArray.slice(currIndex, currIndex + chunkSize));
143+
setCurrIndex(currIndex + chunkSize);
144+
};
145+
146+
useEffect(() => {
147+
// returns an object containing only the healthData for the current category and the metrics the User selected
148+
const filteredHealthData = filterSelectedMetricsAndHealthData();
149+
// returns an object containing the filtered data sorted by data type
150+
//const typeSortedHealthData = healthDataGroupedByDataType(filteredHealthData);
151+
// invoking generateCharts with the sorted data will update healthChartsArr in state with the list of charts to be rendered
152+
generateHealthCharts(filteredHealthData);
153+
}, [category]);
154+
155+
// JJ-ADDITION
156+
return (
157+
<div>
158+
{/* <div id="grafana" onClick={() => { setIsGrafana(!isGrafana) }}>Grafana</div> */}
159+
{service.includes('kafkametrics') || service.includes('kubernetesmetrics') || service.includes('books') || service.includes('customers') || service.includes('frontend') || service.includes('orders')? currChunk : []}
160+
{healthChartsArr.length > chunkSize && (
161+
<>
162+
<Button id="prevCharts" onClick={prevChunk} variant="contained" color="primary" disabled={currIndex <= chunkSize}>
163+
Prev
164+
</Button>
165+
<Button id="nextCharts" onClick={nextChunk} variant="contained" color="primary" disabled={currIndex >= healthChartsArr.length}>
166+
Next
167+
</Button>
168+
</>
169+
)}
170+
</div>
171+
);
172+
});
173+
174+
export default DockerHealthContainer;

app/containers/EventContainer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useEffect, useState, useContext } from 'react';
22
import { useParams } from 'react-router-dom';
33
import { EventContext } from '../context/EventContext';
4+
import { HealthContext } from '../context/HealthContext';
45
import { QueryContext } from '../context/QueryContext';
56
import EventChart from '../charts/EventChart';
67
import { Button } from '@material-ui/core';

app/containers/GraphsContainer.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import HealthContainer from './HealthContainer';
2020
import ModifyMetrics from './ModifyMetricsContainer';
2121
import * as DashboardContext from '../context/DashboardContext';
2222
import lightAndDark from '../components/Styling';
23+
import DockerHealthContainer from './DockerHealthContainer';
2324

2425
import '../stylesheets/GraphsContainer.scss';
2526
import { Link } from 'react-router-dom';
@@ -133,7 +134,14 @@ const GraphsContainer: React.FC = React.memo(props => {
133134
if (selectedMetrics) {
134135
selectedMetrics.forEach((element, id) => {
135136
const categoryName = Object.keys(element)[0];
136-
const prefix = categoryName === 'Event' ? 'event_' : 'health_';
137+
let prefix;
138+
if (categoryName === 'Event') {
139+
prefix = 'event_';
140+
} else if (categoryName === 'books' || categoryName === 'customers' || categoryName === 'frontend' || categoryName === 'orders'){
141+
prefix = 'docker_';
142+
} else {
143+
prefix = 'health_';
144+
}
137145
buttonList.push(
138146
<button
139147
id={`${prefix}${categoryName}-button`}
@@ -242,6 +250,12 @@ const GraphsContainer: React.FC = React.memo(props => {
242250
<EventContainer colourGenerator={stringToColour} sizing="solo" />
243251
</>
244252

253+
)}
254+
{chart.startsWith('docker_') && (
255+
<>
256+
<DockerHealthContainer colourGenerator={stringToColour} sizing="solo" category={chart.substring(7)} />
257+
</>
258+
245259
)}
246260
{chart === 'docker' && <DockerChart />}
247261
{chart === 'modifyMetrics' && <ModifyMetrics />}

0 commit comments

Comments
 (0)