Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Frontend|Backend]Be able to troubleshoot a failed email/sms inject test #1311

Merged
merged 22 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.openbas.migration;

import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.Statement;

@Component
public class V3_31__Add_Injects_tests_statuses extends BaseJavaMigration {

@Override
public void migrate(Context context) throws Exception {
Connection connection = context.getConnection();
Statement select = connection.createStatement();
// Create table
select.execute("""
CREATE TABLE injects_tests_statuses (
status_id varchar(255) NOT NULL CONSTRAINT inject_test_status_pkey PRIMARY KEY,
status_name VARCHAR(255) NOT NULL,
status_executions text,
tracking_sent_date timestamp,
tracking_ack_date timestamp,
tracking_end_date timestamp,
tracking_total_execution_time bigint,
tracking_total_count int,
tracking_total_error int,
tracking_total_success int,
status_inject VARCHAR(255) NOT NULL CONSTRAINT inject_test_status_inject_id_fkey REFERENCES injects(inject_id) ON DELETE SET NULL,
status_created_at timestamp not null default now(),
status_updated_at timestamp not null default now()
);
CREATE INDEX idx_inject_test_inject ON injects_tests_statuses(status_inject);
""");
}

}
29 changes: 1 addition & 28 deletions openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.openbas.rest.inject.service.InjectDuplicateService;
import io.openbas.service.AtomicTestingService;
import io.openbas.service.InjectService;
import io.openbas.service.InjectTestStatusService;
import io.openbas.service.ScenarioService;
import io.openbas.utils.AtomicTestingMapper;
import io.openbas.utils.pagination.SearchPaginationInput;
Expand All @@ -29,8 +30,6 @@
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
Expand All @@ -49,9 +48,6 @@
import java.util.stream.StreamSupport;

import static io.openbas.config.SessionHelper.currentUser;

import io.openbas.execution.Injector;

import static io.openbas.database.model.User.ROLE_ADMIN;
import static io.openbas.database.specification.CommunicationSpecification.fromInject;
import static io.openbas.helper.DatabaseHelper.resolveOptionalRelation;
Expand All @@ -77,7 +73,6 @@ public class InjectApi extends RestBehavior {

private final Executor executor;
private final InjectorContractRepository injectorContractRepository;
private ApplicationContext context;
private final CommunicationRepository communicationRepository;
private final ExerciseRepository exerciseRepository;
private final UserRepository userRepository;
Expand All @@ -94,11 +89,6 @@ public class InjectApi extends RestBehavior {
private final AtomicTestingService atomicTestingService;
private final InjectDuplicateService injectDuplicateService;

savacano28 marked this conversation as resolved.
Show resolved Hide resolved
@Autowired
public void setContext(ApplicationContext context) {
this.context = context;
}

// -- INJECTS --

@GetMapping(INJECT_URI + "/{injectId}")
Expand Down Expand Up @@ -169,23 +159,6 @@ public Inject tryInject(@PathVariable String injectId) {
return atomicTestingService.tryInject(injectId);
}

@GetMapping(INJECT_URI + "/test/{injectId}")
public InjectStatus testInject(@PathVariable String injectId) {
Inject inject = injectRepository.findById(injectId).orElseThrow();
User user = this.userRepository.findById(currentUser().getId()).orElseThrow();
List<ExecutionContext> userInjectContexts = List.of(
this.executionContextService.executionContext(user, inject, "Direct test")
);
Injector executor = context.getBean(
inject.getInjectorContract().map(injectorContract -> injectorContract.getInjector().getType()).orElseThrow(),
io.openbas.execution.Injector.class);
ExecutableInject injection = new ExecutableInject(false, true, inject, List.of(), inject.getAssets(),
inject.getAssetGroups(), userInjectContexts);
Execution execution = executor.executeInjection(injection);
return InjectStatus.fromExecutionTest(execution);

}

@Transactional(rollbackFor = Exception.class)
@PutMapping(INJECT_URI + "/{exerciseId}/{injectId}")
@PreAuthorize("isExercisePlanner(#exerciseId)")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.openbas.rest.inject_test_status;

import io.openbas.database.model.InjectTestStatus;
import io.openbas.rest.helper.RestBehavior;
import io.openbas.service.InjectTestStatusService;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@PreAuthorize("isAdmin()")
@RequiredArgsConstructor
public class InjectTestStatusApi extends RestBehavior {

private final InjectTestStatusService injectTestStatusService;

@GetMapping("/api/injects/{injectId}/test")
public InjectTestStatus testInject(@PathVariable @NotBlank String injectId) {
return injectTestStatusService.testInject(injectId);

Check warning on line 24 in openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java#L24

Added line #L24 was not covered by tests
savacano28 marked this conversation as resolved.
Show resolved Hide resolved
}

@GetMapping("/api/exercise/{exerciseId}/injects/test")
public List<InjectTestStatus> findAllExerciseInjectTests(@PathVariable @NotBlank String exerciseId) {
return injectTestStatusService.findAllInjectTestsByExerciseId(exerciseId);

Check warning on line 29 in openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java#L29

Added line #L29 was not covered by tests
}
savacano28 marked this conversation as resolved.
Show resolved Hide resolved

@GetMapping("/api/scenario/{scenarioId}/injects/test")
public List<InjectTestStatus> findAllScenarioInjectTests(@PathVariable @NotBlank String scenarioId) {
return injectTestStatusService.findAllInjectTestsByScenarioId(scenarioId);

Check warning on line 34 in openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java#L34

Added line #L34 was not covered by tests
johanah29 marked this conversation as resolved.
Show resolved Hide resolved
}

@GetMapping("/api/injects/test/{testId}")
public InjectTestStatus findInjectTestStatus(@PathVariable @NotBlank String testId) {
return injectTestStatusService.findInjectTestStatusById(testId);

Check warning on line 39 in openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java#L39

Added line #L39 was not covered by tests
}
savacano28 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package io.openbas.service;

import io.openbas.database.model.*;
import io.openbas.database.repository.InjectRepository;
import io.openbas.database.repository.InjectTestStatusRepository;
import io.openbas.database.repository.UserRepository;
import io.openbas.execution.ExecutableInject;
import io.openbas.execution.ExecutionContext;
import io.openbas.execution.ExecutionContextService;
import io.openbas.execution.Injector;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static io.openbas.config.SessionHelper.currentUser;

@Service
@Log
@RequiredArgsConstructor
public class InjectTestStatusService {
johanah29 marked this conversation as resolved.
Show resolved Hide resolved

private ApplicationContext context;
private final UserRepository userRepository;
private final InjectRepository injectRepository;
private final ExecutionContextService executionContextService;
private final InjectTestStatusRepository injectTestStatusRepository;

@Autowired
public void setContext(ApplicationContext context) {
this.context = context;
}

@Transactional
public InjectTestStatus testInject(String injectId) {
Inject inject = injectRepository.findById(injectId).orElseThrow();
User user = this.userRepository.findById(currentUser().getId()).orElseThrow();
List<ExecutionContext> userInjectContexts = List.of(
this.executionContextService.executionContext(user, inject, "Direct test")

Check warning on line 45 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L42-L45

Added lines #L42 - L45 were not covered by tests
);
Injector executor = context.getBean(
inject.getInjectorContract().map(injectorContract -> injectorContract.getInjector().getType()).orElseThrow(),

Check warning on line 48 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L47-L48

Added lines #L47 - L48 were not covered by tests
io.openbas.execution.Injector.class);
ExecutableInject injection = new ExecutableInject(false, true, inject, List.of(), inject.getAssets(),
inject.getAssetGroups(), userInjectContexts);
Execution execution = executor.executeInjection(injection);

Check warning on line 52 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L50-L52

Added lines #L50 - L52 were not covered by tests

//Save inject test status
Optional<InjectTestStatus> injectTestStatus = this.injectTestStatusRepository.findByInject(inject);
InjectTestStatus injectTestStatusToSave = InjectTestStatus.fromExecutionTest(execution);
injectTestStatus.ifPresent(testStatus -> {
injectTestStatusToSave.setId(testStatus.getId());
injectTestStatusToSave.setTestCreationDate(testStatus.getTestCreationDate());
});
injectTestStatusToSave.setInject(inject);
this.injectTestStatusRepository.save(injectTestStatusToSave);

Check warning on line 62 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L55-L62

Added lines #L55 - L62 were not covered by tests

return injectTestStatusToSave;

Check warning on line 64 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L64

Added line #L64 was not covered by tests
}

public List<InjectTestStatus> findAllInjectTestsByExerciseId(String exerciseId) {
return injectTestStatusRepository.findAllExerciseInjectTests(exerciseId);

Check warning on line 68 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L68

Added line #L68 was not covered by tests
}

public List<InjectTestStatus> findAllInjectTestsByScenarioId(String scenarioId) {
return injectTestStatusRepository.findAllScenarioInjectTests(scenarioId);

Check warning on line 72 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L72

Added line #L72 was not covered by tests
}

public InjectTestStatus findInjectTestStatusById(String testId) {
return injectTestStatusRepository.findById(testId).orElseThrow();

Check warning on line 76 in openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java

View check run for this annotation

Codecov / codecov/patch

openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java#L76

Added line #L76 was not covered by tests
savacano28 marked this conversation as resolved.
Show resolved Hide resolved
}

}
2 changes: 1 addition & 1 deletion openbas-api/src/test/java/io/openbas/rest/TeamApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void retrieveTeamsOnScenarioTest() throws Exception {
void addPlayerOnTeamOnScenarioTest() throws Exception {
// -- PREPARE --
User user = new User();
user.setEmail("test@gmail.com");
user.setEmail("testfiligran@gmail.com");
user = this.userRepository.save(user);
USER_ID = user.getId();
ScenarioTeamPlayersEnableInput input = new ScenarioTeamPlayersEnableInput();
Expand Down
2 changes: 1 addition & 1 deletion openbas-front/src/actions/Inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const tryInject = (injectId) => (dispatch) => {
};

export const testInject = (injectId) => {
const uri = `/api/injects/test/${injectId}`;
const uri = `/api/injects/${injectId}/test`;
return simpleCall(uri);
};

Expand Down
17 changes: 17 additions & 0 deletions openbas-front/src/actions/inject_test/inject-test-actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { simpleCall } from '../../utils/Action';

// eslint-disable-next-line import/prefer-default-export
export const searchExerciseInjectTests = (exerciseId: string) => {
const uri = `/api/exercise/${exerciseId}/injects/test`;
return simpleCall(uri);
};

export const searchScenarioInjectTests = (scenarioId: string) => {
const uri = `/api/scenario/${scenarioId}/injects/test`;
return simpleCall(uri);
};

export const fetchInjectTestStatus = (testId: string | undefined) => {
const uri = `/api/injects/test/${testId}`;
return simpleCall(uri);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
import React, { FunctionComponent, useContext, useState } from 'react';
import { Alert, Button, Dialog, DialogActions, DialogContent, DialogContentText, IconButton, Menu, MenuItem, Table, TableBody, TableCell, TableRow } from '@mui/material';
import React, { FunctionComponent, useContext, useEffect, useState } from 'react';
import {
Alert,
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
IconButton,
Menu,
MenuItem,
Table,
TableBody,
TableCell,
TableRow,
SnackbarCloseReason,
Link,
} from '@mui/material';
import { MoreVert } from '@mui/icons-material';
import { useFormatter } from '../../../../components/i18n';
import Transition from '../../../../components/common/Transition';
Expand All @@ -9,20 +25,24 @@ import type { Inject, InjectStatus, InjectStatusExecution, Tag } from '../../../
import { duplicateInjectForExercise, duplicateInjectForScenario, tryInject, testInject } from '../../../../actions/Inject';
import { useAppDispatch } from '../../../../utils/hooks';
import DialogDuplicate from '../../../../components/common/DialogDuplicate';
import { useHelper } from '../../../../store';
import type { ExercisesHelper } from '../../../../actions/exercises/exercise-helper';

interface Props {
inject: InjectStore & { inject_testable?: boolean }; // FIXME: Inject object coming from multiple endpoints with different properties
inject: InjectStore;
tagsMap: Record<string, Tag>;
setSelectedInjectId: (injectId: Inject['inject_id']) => void;
isDisabled: boolean;
canBeTested?: boolean;
exerciseOrScenarioId?: string;
}

const InjectPopover: FunctionComponent<Props> = ({
inject,
setSelectedInjectId,
isDisabled,
canBeTested = false,
exerciseOrScenarioId,
}) => {
// Standard hooks
const { t } = useFormatter();
Expand All @@ -48,6 +68,8 @@ const InjectPopover: FunctionComponent<Props> = ({
const [_injectTestResult, setInjectTestResult] = useState<InjectStatus | null>(null);
const [anchorEl, setAnchorEl] = useState<Element | null>(null);

const isExercise = useHelper((helper: ExercisesHelper) => helper.getExercisesMap()[exerciseOrScenarioId!] !== undefined);

const handlePopoverOpen = (event: React.MouseEvent<HTMLButtonElement>) => {
savacano28 marked this conversation as resolved.
Show resolved Hide resolved
event.stopPropagation();
setAnchorEl(event.currentTarget);
Expand Down Expand Up @@ -114,9 +136,36 @@ const InjectPopover: FunctionComponent<Props> = ({
setInjectTestResult(null);
};

const [openDialog, setOpenDialog] = React.useState<boolean>(false);
const handleCloseDialog = (
event?: React.SyntheticEvent | Event,
reason?: SnackbarCloseReason,
) => {
if (reason === 'clickaway') {
return;
}
setOpenDialog(false);
};
const [detailsLink, setDetailsLink] = React.useState<string>('');

useEffect(() => {
if (openDialog) {
setTimeout(() => {
handleCloseDialog();
setDetailsLink('');
}, 6000);
}
}, [openDialog]);

const submitTest = () => {
testInject(inject.inject_id).then((result: { data: InjectStatus }) => {
setInjectTestResult(result.data);
setOpenDialog(true);
if (isExercise) {
setDetailsLink(`/admin/exercises/${exerciseOrScenarioId}/tests/${result.data.status_id}`);
} else {
setDetailsLink(`/admin/scenarios/${exerciseOrScenarioId}/tests/${result.data.status_id}`);
}
});
handleCloseTest();
};
Expand Down Expand Up @@ -180,6 +229,31 @@ const InjectPopover: FunctionComponent<Props> = ({

return (
<>
<Dialog open={openDialog}
slotProps={{
backdrop: {
sx: {
backgroundColor: 'transparent',
},
},
}}
PaperProps={{
sx: {
position: 'fixed',
top: '20px',
left: '660px',
margin: 0,
},
}}
>
<Alert
onClose={handleCloseDialog}
severity="success"
sx={{ width: '100%' }}
>
{t('Inject test has been sent, you can view test logs details on ')} <Link href={detailsLink} underline="hover">{t('its dedicated page.')}</Link>
</Alert>
</Dialog>
<IconButton
onClick={handlePopoverOpen}
aria-haspopup="true"
Expand Down
Loading