-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathapi-setup.ts
309 lines (283 loc) · 10.2 KB
/
api-setup.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
import { request, type APIRequestContext, type APIResponse } from '@playwright/test';
import { v4 as uuidv4 } from 'uuid';
import type {
ElectricalProfileSet,
GetProjectsApiResponse,
GetProjectsByProjectIdStudiesApiResponse,
GetProjectsByProjectIdStudiesAndStudyIdScenariosApiResponse,
GetLightRollingStockApiResponse,
LightElectricalProfileSet,
GetInfraApiResponse,
InfraWithState,
ProjectWithStudies,
StudyWithScenarios,
ScenarioWithDetails,
LightRollingStockWithLiveries,
Project,
Infra,
Study,
Scenario,
LightRollingStock,
StdcmSearchEnvironment,
TowedRollingStock,
GetTowedRollingStockApiResponse,
} from 'common/api/osrdEditoastApi';
import electricalProfileSet from '../assets/operationStudies/simulationSettings/electricalProfiles/electricalProfile.json';
import { globalProjectName, globalStudyName, infrastructureName } from '../assets/project-const';
import towedRollingStockData from '../assets/stdcm/towedRollingStock/towedRollingStock.json';
import { logger } from '../test-logger';
/**
* Initialize a new API request context with the base URL.
*
* @returns {Promise<APIRequestContext>} - The API request context.
*/
export const getApiContext = async (): Promise<APIRequestContext> =>
request.newContext({
baseURL: 'http://localhost:4000',
});
/**
* Send a GET request to the specified API endpoint with optional query parameters.
*
* @param url - The API endpoint URL.
* @param params - Optional query parameters to include in the request.
*/
export const getApiRequest = async (
url: string,
params?: { [key: string]: string | number | boolean }
) => {
const apiContext = await getApiContext();
const response = await apiContext.get(url, { params });
return response.json();
};
/**
* Handle API error responses by checking the status and throwing an error if the request failed.
*
* @param response - The response object from the API request.
* @param errorMessage - Optional. The error message to throw if the request fails.
* @throws {Error} - Throws an error if the response status is not OK.
*/
export function handleErrorResponse(response: APIResponse, errorMessage = 'API Request Failed') {
if (response.ok()) return;
throw new Error(`${errorMessage}: ${response.status()} ${response.statusText()}`);
}
/**
* Send a POST request to the specified API endpoint with optional data and query parameters.
*
* @template T
* @param url - The API endpoint URL.
* @param data - Optional. The payload to send in the request body.
* @param params - Optional query parameters to include in the request.
* @param errorMessage - Optional. Custom error message for failed requests.
*/
export const postApiRequest = async <T>(
url: string,
data?: T,
params?: { [key: string]: string | number | boolean },
errorMessage?: string
) => {
const apiContext = await getApiContext();
const response = await apiContext.post(url, { data, params });
handleErrorResponse(response, errorMessage);
return response.json();
};
/**
* Send a DELETE request to the specified API endpoint.
*
* @param url - The API endpoint URL.
* @returns {Promise<APIResponse>} - The response from the API.
*/
export const deleteApiRequest = async (
url: string,
errorMessage?: string
): Promise<APIResponse> => {
const apiContext = await getApiContext();
const response = await apiContext.delete(url);
handleErrorResponse(response, errorMessage);
return response;
};
/**
* Retrieve infrastructure data by name.
*
* @param infraName - The name of the infrastructure to retrieve.
* @returns {Promise<Infra>} - The matching infrastructure data.
*/
export const getInfra = async (infraName = infrastructureName): Promise<Infra> => {
const infras: GetInfraApiResponse = await getApiRequest('/api/infra');
const infra = infras.results.find((i: InfraWithState) => i.name === infraName);
return infra as Infra;
};
/**
* Retrieve infrastructure data by ID.
*
* @param infraId - The ID of the infrastructure to retrieve.
* @returns {Promise<InfraWithState>} - The matching infrastructure data.
*/
export const getInfraById = async (infraId: number): Promise<InfraWithState> => {
try {
const response = await getApiRequest(`/api/infra/${infraId}`);
return response as InfraWithState;
} catch (error) {
throw new Error(`Failed to retrieve infrastructure with ID ${infraId}: ${error}`);
}
};
/**
* Retrieve project data by name.
*
* @param projectName - The name of the project to retrieve.
* @returns {Promise<Project>} - The matching project data.
*/
export const getProject = async (projectName = globalProjectName): Promise<Project> => {
const projects: GetProjectsApiResponse = await getApiRequest('/api/projects');
const project = projects.results.find((p: ProjectWithStudies) => p.name === projectName);
return project as Project;
};
/**
* Retrieve study data by project ID and study name.
*
* @param projectId - The ID of the project.
* @param studyName - The name of the study to retrieve.
* @returns {Promise<Study>} - The matching study data.
*/
export const getStudy = async (projectId: number, studyName = globalStudyName): Promise<Study> => {
const studies: GetProjectsByProjectIdStudiesApiResponse = await getApiRequest(
`/api/projects/${projectId}/studies`
);
const study = studies.results.find((s: StudyWithScenarios) => s.name === studyName);
return study as Study;
};
/**
* Retrieve scenario data by project ID, study ID, and scenario name.
*
* @param projectId - The ID of the project.
* @param studyId - The ID of the study.
* @param scenarioName - The name of the scenario to retrieve.
* @returns {Promise<Scenario>} - The matching scenario data.
*/
export const getScenario = async (
projectId: number,
studyId: number,
scenarioName: string
): Promise<Scenario> => {
const scenarios: GetProjectsByProjectIdStudiesAndStudyIdScenariosApiResponse =
await getApiRequest(`/api/projects/${projectId}/studies/${studyId}/scenarios`);
const scenario = scenarios.results.find((s: ScenarioWithDetails) => s.name === scenarioName);
return scenario as Scenario;
};
/**
* Retrieve rolling stock data by name.
*
* @param rollingStockName - The name of the rolling stock to retrieve.
* @returns {Promise<RollingStock>} - The matching rolling stock data.
*/
export const getRollingStock = async (rollingStockName: string): Promise<LightRollingStock> => {
const rollingStocks: GetLightRollingStockApiResponse = await getApiRequest(
'/api/light_rolling_stock',
{ page_size: 500 }
);
const rollingStock = rollingStocks.results.find(
(r: LightRollingStockWithLiveries) => r.name === rollingStockName
);
return rollingStock as LightRollingStock;
};
/**
* Retrieve electrical profile data by name.
*
* @param electricalProfileName - The name of the electrical profile to retrieve.
* @returns {Promise<ElectricalProfileSet>} - The matching electrical profile data.
*/
export const getElectricalProfile = async (
electricalProfileName: string
): Promise<LightElectricalProfileSet> => {
const electricalProfiles: LightElectricalProfileSet[] = await getApiRequest(
`/api/electrical_profile_set`
);
const electricalProfile = electricalProfiles.find(
(e: LightElectricalProfileSet) => e.name === electricalProfileName
);
return electricalProfile as LightElectricalProfileSet;
};
/**
* Set a new electrical profile.
*/
export const setElectricalProfile = async (): Promise<ElectricalProfileSet> => {
const electricalProfile = await postApiRequest(
`/api/electrical_profile_set`,
{
...electricalProfileSet,
},
{ name: `small infra ${uuidv4()}` }
);
return electricalProfile as ElectricalProfileSet;
};
/**
* Fetch the STDCM environment if not in CI mode.
*/
export async function getStdcmEnvironment(): Promise<StdcmSearchEnvironment | null> {
if (process.env.CI) return null; // Skip in CI mode.
try {
const apiContext = await getApiContext();
const response = await apiContext.get('api/stdcm/search_environment');
if (response.status() === 200) {
return (await response.json()) as StdcmSearchEnvironment;
}
logger.warn(`STDCM environment not configured. HTTP status: ${response.status()}`);
return null;
} catch (error) {
logger.error('Failed to fetch STDCM environment:', error);
return null;
}
}
/**
* Set the STDCM environment with the provided data.
*
* @param stdcmEnvironment -The stdcm search environment to use.
*/
export async function setStdcmEnvironment(stdcmEnvironment: StdcmSearchEnvironment): Promise<void> {
// Remove the `id` field to match the StdcmSearchEnvironmentCreateForm schema
const { id: _id, ...stdcmEnvironmentWithoutId } = stdcmEnvironment;
await postApiRequest(
'/api/stdcm/search_environment',
stdcmEnvironmentWithoutId,
undefined,
'Failed to update STDCM configuration environment'
);
}
/**
* Retrieve a towed rolling stock by name.
*
* @param towedRollingStockName - The name of the towed rolling stock to retrieve.
* @returns {Promise<TowedRollingStock >} - The matching towed rolling stock data .
*/
export const getTowedRollingStockByName = async (
towedRollingStockName: string
): Promise<TowedRollingStock | undefined> => {
const towedRollingStocks: GetTowedRollingStockApiResponse = await getApiRequest(
'/api/towed_rolling_stock',
{ page_size: 50 }
);
const towedRollingStock = towedRollingStocks.results.find(
(t: TowedRollingStock) => t.name === towedRollingStockName
);
return towedRollingStock;
};
/**
* Create a towed rolling stock using predefined data from the imported JSON file.
*
* @returns {Promise<TowedRollingStock>} - The created towed rolling stock.
*/
export async function setTowedRollingStock(): Promise<TowedRollingStock> {
// Check if the towed rolling stock already exists
const existingTowedRollingStock = await getTowedRollingStockByName(towedRollingStockData.name);
if (existingTowedRollingStock) {
logger.info(`Towed rolling stock with name "${towedRollingStockData.name}" already exists.`);
return existingTowedRollingStock;
}
// Create the towed rolling stock
const createdTowedRollingStock = await postApiRequest(
'/api/towed_rolling_stock',
towedRollingStockData,
undefined,
'Failed to create towed rolling stock'
);
return createdTowedRollingStock as TowedRollingStock;
}