Exemplo n.º 1
0
        protected async Task <RunSolutionResult> CheckSolution(string courseId, ExerciseSlide exerciseSlide, string userCode, string userId, string userName, bool waitUntilChecked, bool saveSubmissionOnCompileErrors)
        {
            var exerciseMetricId = GetExerciseMetricId(courseId, exerciseSlide);

            metricSender.SendCount("exercise.try");
            metricSender.SendCount($"exercise.{courseId.ToLower(CultureInfo.InvariantCulture)}.try");
            metricSender.SendCount($"exercise.{exerciseMetricId}.try");

            var course        = courseManager.GetCourse(courseId);
            var exerciseBlock = exerciseSlide.Exercise;
            var buildResult   = exerciseBlock.BuildSolution(userCode);

            if (buildResult.HasErrors)
            {
                metricSender.SendCount($"exercise.{exerciseMetricId}.CompilationError");
            }
            if (buildResult.HasStyleErrors)
            {
                metricSender.SendCount($"exercise.{exerciseMetricId}.StyleViolation");
            }

            if (!saveSubmissionOnCompileErrors)
            {
                if (buildResult.HasErrors)
                {
                    return new RunSolutionResult {
                               IsCompileError = true, ErrorMessage = buildResult.ErrorMessage, ExecutionServiceName = "uLearn"
                    }
                }
                ;
            }

            var compilationErrorMessage = buildResult.HasErrors ? buildResult.ErrorMessage : null;
            var dontRunSubmission       = buildResult.HasErrors;
            var submissionLanguage      = exerciseBlock.Language.Value;
            var submissionSandbox       = (exerciseBlock as UniversalExerciseBlock)?.DockerImageName;
            var submission = await userSolutionsRepo.AddUserExerciseSubmission(
                courseId, exerciseSlide.Id,
                userCode, compilationErrorMessage, null,
                userId, "uLearn", GenerateSubmissionName(exerciseSlide, userName),
                submissionLanguage,
                submissionSandbox,
                dontRunSubmission?AutomaticExerciseCheckingStatus.Done : AutomaticExerciseCheckingStatus.Waiting
                );

            if (buildResult.HasErrors)
            {
                return new RunSolutionResult {
                           IsCompileError = true, ErrorMessage = buildResult.ErrorMessage, SubmissionId = submission.Id, ExecutionServiceName = "uLearn"
                }
            }
            ;

            var hasAutomaticChecking = exerciseBlock.HasAutomaticChecking();
            var executionTimeout     = TimeSpan.FromSeconds(exerciseBlock.TimeLimit * 2 + 5);

            try
            {
                if (hasAutomaticChecking)
                {
                    await userSolutionsRepo.RunAutomaticChecking(submission, executionTimeout, waitUntilChecked);
                }
            }
            catch (SubmissionCheckingTimeout)
            {
                log.Error($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})");

                errorsBot.PostToChannel($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})\n\nhttps://ulearn.me/Sandbox");
                return(new RunSolutionResult
                {
                    IsCompillerFailure = true,
                    ErrorMessage = "К сожалению, из-за большой нагрузки мы не смогли оперативно проверить ваше решение. " +
                                   "Мы попробуем проверить его позже, просто подождите и обновите страницу. ",
                    ExecutionServiceName = "ulearn"
                });
            }

            if (!waitUntilChecked)
            {
                metricSender.SendCount($"exercise.{exerciseMetricId}.dont_wait_result");
                return(new RunSolutionResult {
                    SubmissionId = submission.Id
                });
            }

            /* Update the submission */
            submission = userSolutionsRepo.FindNoTrackingSubmission(submission.Id);

            if (submission.AutomaticCheckingIsRightAnswer)
            {
                await CreateStyleErrorsReviewsForSubmission(submission, buildResult.StyleErrors, exerciseMetricId);
            }

            var  automaticChecking = submission.AutomaticChecking;
            bool sentToReview;

            if (!hasAutomaticChecking)
            {
                sentToReview = await SendToReviewAndUpdateScore(submission, courseManager, slideCheckingsRepo, groupsRepo, visitsRepo, metricSender, true).ConfigureAwait(false);
            }
            else
            {
                sentToReview = slideCheckingsRepo.HasManualExerciseChecking(courseId, exerciseSlide.Id, userId, submission.Id);
            }

            var result = new RunSolutionResult
            {
                IsCompileError       = automaticChecking?.IsCompilationError ?? false,
                ErrorMessage         = automaticChecking?.CompilationError.Text ?? "",
                IsRightAnswer        = submission.AutomaticCheckingIsRightAnswer,
                ExpectedOutput       = exerciseBlock.HideExpectedOutputOnError ? null : exerciseSlide.Exercise.ExpectedOutput?.NormalizeEoln(),
                ActualOutput         = automaticChecking?.Output.Text ?? "",
                ExecutionServiceName = automaticChecking?.ExecutionServiceName ?? "ulearn",
                SentToReview         = sentToReview,
                SubmissionId         = submission.Id,
            };

            if (buildResult.HasStyleErrors)
            {
                result.IsStyleViolation = true;
                result.StyleMessage     = string.Join("\n", buildResult.StyleErrors.Select(e => e.GetMessageWithPositions()));
            }

            return(result);
        }