Execute study after check action not only for solved tasks
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / checker / StudyCheckTask.java
1 package com.jetbrains.edu.learning.checker;
2
3 import com.intellij.execution.process.CapturingProcessHandler;
4 import com.intellij.execution.process.ProcessOutput;
5 import com.intellij.ide.projectView.ProjectView;
6 import com.intellij.openapi.application.ApplicationManager;
7 import com.intellij.openapi.diagnostic.Logger;
8 import com.intellij.openapi.progress.ProgressIndicator;
9 import com.intellij.openapi.project.Project;
10 import com.intellij.openapi.ui.MessageType;
11 import com.intellij.openapi.util.Ref;
12 import com.intellij.openapi.util.text.StringUtil;
13 import com.intellij.openapi.vfs.VirtualFile;
14 import com.jetbrains.edu.learning.core.EduUtils;
15 import com.jetbrains.edu.learning.courseFormat.StudyStatus;
16 import com.jetbrains.edu.learning.courseFormat.Task;
17 import com.jetbrains.edu.learning.StudyPluginConfigurator;
18 import com.jetbrains.edu.learning.StudyState;
19 import com.jetbrains.edu.learning.StudyTaskManager;
20 import com.jetbrains.edu.learning.StudyUtils;
21 import com.jetbrains.edu.learning.actions.StudyAfterCheckAction;
22 import com.jetbrains.edu.learning.EduStepicConnector;
23 import com.jetbrains.edu.learning.stepic.StudySettings;
24 import org.jetbrains.annotations.NotNull;
25
26 public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroundable {
27
28   private static final Logger LOG = Logger.getInstance(StudyCheckTask.class);
29   private final Project myProject;
30   protected final StudyState myStudyState;
31   protected final Task myTask;
32   protected final VirtualFile myTaskDir;
33   protected final StudyTaskManager myTaskManger;
34   private final StudyStatus myStatusBeforeCheck;
35   private Ref<Boolean> myCheckInProcess;
36   private final Process myTestProcess;
37   private final String myCommandLine;
38
39   public StudyCheckTask(Project project, StudyState studyState, Ref<Boolean> checkInProcess, Process testProcess, String commandLine) {
40     super(project, "Checking Task");
41     myProject = project;
42     myStudyState = studyState;
43     myCheckInProcess = checkInProcess;
44     myTestProcess = testProcess;
45     myCommandLine = commandLine;
46     myTask = studyState.getTask();
47     myTaskDir = studyState.getTaskDir();
48     myTaskManger = StudyTaskManager.getInstance(myProject);
49     myStatusBeforeCheck = myTaskManger.getStatus(myTask);
50   }
51
52   @Override
53   public void onSuccess() {
54     StudyUtils.updateToolWindows(myProject);
55     StudyCheckUtils.drawAllPlaceholders(myProject, myTask, myTaskDir);
56     ProjectView.getInstance(myProject).refresh();
57     clearState();
58   }
59
60   protected void clearState() {
61     EduUtils.deleteWindowDescriptions(myTask, myTaskDir);
62     myCheckInProcess.set(false);
63   }
64
65   @Override
66   public void onCancel() {
67     myTaskManger.setStatus(myTask, myStatusBeforeCheck);
68     clearState();
69   }
70
71   @Override
72   public void run(@NotNull ProgressIndicator indicator) {
73     final CapturingProcessHandler handler = new CapturingProcessHandler(myTestProcess, null, myCommandLine);
74     final ProcessOutput output = handler.runProcessWithProgressIndicator(indicator);
75     if (indicator.isCanceled()) {
76       ApplicationManager.getApplication().invokeLater(
77         () -> StudyCheckUtils.showTestResultPopUp("Check cancelled", MessageType.WARNING.getPopupBackground(), myProject));
78       return;
79     }
80
81
82     final StudyTestsOutputParser.TestsOutput testsOutput = StudyTestsOutputParser.getTestsOutput(output);
83     String stderr = output.getStderr();
84     if (!stderr.isEmpty()) {
85       ApplicationManager.getApplication().invokeLater(() ->
86                                                         StudyCheckUtils.showTestResultPopUp("Failed to launch checking",
87                                                                                             MessageType.WARNING.getPopupBackground(),
88                                                                                             myProject));
89       //log error output of tests
90       LOG.info("#educational " + stderr);
91       return;
92     }
93
94     postAttemptToStepic(testsOutput);
95
96
97     if (testsOutput.isSuccess()) {
98       onTaskSolved(testsOutput);
99     }
100     else {
101       onTaskFailed(testsOutput);
102     }
103     runAfterTaskSolvedActions();
104   }
105
106   protected void onTaskFailed(StudyTestsOutputParser.TestsOutput testsOutput) {
107     myTaskManger.setStatus(myTask, StudyStatus.Failed);
108     ApplicationManager.getApplication().invokeLater(
109       () -> StudyCheckUtils.showTestResultPopUp(testsOutput.getMessage(), MessageType.ERROR.getPopupBackground(), myProject));
110   }
111
112   protected void onTaskSolved(StudyTestsOutputParser.TestsOutput testsOutput) {
113     myTaskManger.setStatus(myTask, StudyStatus.Solved);
114     ApplicationManager.getApplication().invokeLater(
115       () -> StudyCheckUtils.showTestResultPopUp(testsOutput.getMessage(), MessageType.INFO.getPopupBackground(), myProject));
116   }
117
118   private void runAfterTaskSolvedActions() {
119     StudyPluginConfigurator configurator = StudyUtils.getConfigurator(myProject);
120     if (configurator != null) {
121       StudyAfterCheckAction[] checkActions = configurator.getAfterCheckActions();
122       if (checkActions != null) {
123         for (StudyAfterCheckAction action: checkActions) {
124           action.run(myProject, myTask, myStatusBeforeCheck);
125         }
126       }
127     }
128   }
129
130   protected void postAttemptToStepic(StudyTestsOutputParser.TestsOutput testsOutput) {
131     final StudySettings studySettings = StudySettings.getInstance();
132     final String login = studySettings.getLogin();
133     final String password = StringUtil.isEmptyOrSpaces(login) ? "" : studySettings.getPassword();
134     EduStepicConnector.postAttempt(myTask, testsOutput.isSuccess(), login, password);
135   }
136 }