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
[Feature:Autograding] Automated output and input generation #3882
Changes from 71 commits
2297070
7b59f0d
3e20f93
a70e466
5010751
1ee749c
cb8b1d9
0049858
3dbbacd
891b5c2
f0519a5
0c15391
dafde2f
8d5ab77
e4a9785
6cb94c9
85c4b38
ad37dbc
3e34df2
e162ac5
e6c550e
3e86881
fdc88b0
2b0d0c2
b89622d
90e4de4
80ce45f
a89a778
fac1381
532136c
7e96303
7e297ab
a6d5cbc
67d12f2
6e6ca3a
8ab5249
3feac4f
9516fdd
27d7af0
b1def9b
cc86fda
f1327f0
7a3576c
133d4de
764c8f8
0efe461
b08c021
9607923
de901c2
0f35cde
7e8cd22
b27a873
5c23e93
ec2b778
a7cfbf6
7318980
5bb8c5f
f7a7c69
08d8d13
993d8ca
f8772fc
57e66da
375fce4
6b0fddd
9ef8a77
0adb22d
a01d23f
4bb3e5e
0244252
343f420
30eac44
462016b
15d04c0
9b2a2ff
068e62d
de6ad20
35ee6f3
1021580
0ac6399
3dd2867
a016f78
8a1329c
cc20733
ef0dcc8
6d9ba20
ea46b7e
53eb35b
31dd3ba
c17d690
4f14cd0
aa18c5e
199ad1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -122,15 +122,13 @@ def zip_my_directory(path,zipfilename): | |
zipf.write(os.path.join(root,my_file),os.path.join(relpath,my_file)) | ||
zipf.close() | ||
|
||
|
||
def unzip_this_file(zipfilename,path): | ||
if not os.path.exists(zipfilename): | ||
raise RuntimeError("ERROR: zip file does not exist '", zipfilename, "'") | ||
zip_ref = zipfile.ZipFile(zipfilename,'r') | ||
zip_ref.extractall(path) | ||
zip_ref.close() | ||
|
||
|
||
def allow_only_one_part(path, log_path=os.devnull): | ||
""" | ||
Given a path to a directory, iterate through the directory and detect folders that start with | ||
|
@@ -190,6 +188,14 @@ def remove_test_input_files(overall_log,test_input_path,testcase_folder): | |
print ("removing (likely) stale test_input file: ", my_file, file=f) | ||
os.remove(my_file) | ||
|
||
def add_all_permissions(folder): | ||
add_permissions_recursive(folder, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
|
||
def remove_read_permissions(top_dir): | ||
os.chmod(top_dir,os.stat(top_dir).st_mode & ~stat.S_IRGRP & ~stat.S_IWGRP & ~stat.S_IXGRP & ~stat.S_IROTH & ~stat.S_IWOTH & ~stat.S_IXOTH) | ||
|
||
def grade_from_zip(my_autograding_zip_file,my_submission_zip_file,which_untrusted): | ||
|
||
|
@@ -370,10 +376,7 @@ def grade_from_zip(my_autograding_zip_file,my_submission_zip_file,which_untruste | |
add_permissions(os.path.join(testcase_folder,"my_compile.out"), stat.S_IXUSR | stat.S_IXGRP |stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
#untrusted_grant_rwx_access(which_untrusted, tmp_compilation) | ||
untrusted_grant_rwx_access(which_untrusted, testcase_folder) | ||
add_permissions_recursive(testcase_folder, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
add_all_permissions(testcase_folder) | ||
|
||
if USE_DOCKER: | ||
try: | ||
|
@@ -431,22 +434,17 @@ def grade_from_zip(my_autograding_zip_file,my_submission_zip_file,which_untruste | |
else: | ||
print (which_machine,which_untrusted,"COMPILATION FAILURE") | ||
grade_items_logging.log_message(job_id,is_batch_job,which_untrusted,item_name,message="COMPILATION FAILURE") | ||
add_permissions_recursive(tmp_compilation, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
|
||
|
||
add_all_permissions(tmp_compilation) | ||
|
||
# return to the main tmp directory | ||
os.chdir(tmp) | ||
|
||
|
||
# -------------------------------------------------------------------- | ||
# make the runner directory | ||
|
||
# -------------------------------------------------------------------- | ||
# RUN INPUT GENERATION | ||
with open(os.path.join(tmp_logs,"overall.txt"),'a') as f: | ||
print ("====================================\nRUNNER STARTS", file=f) | ||
print ("====================================\nINPUT GENERATION STARTS", file=f) | ||
|
||
tmp_work = os.path.join(tmp,"TMP_WORK") | ||
tmp_work_test_input = os.path.join(tmp_work, "test_input") | ||
tmp_work_test_output = os.path.join(tmp_work, "test_output") | ||
|
@@ -466,6 +464,60 @@ def grade_from_zip(my_autograding_zip_file,my_submission_zip_file,which_untruste | |
|
||
os.chdir(tmp_work) | ||
|
||
#random_input_tmp_work = os.path.join(tmp_work,"random_input") | ||
#os.mkdir(random_input_tmp_work) | ||
|
||
with open(os.path.join(tmp_logs,"input_generator_log.txt"), 'w') as logfile: | ||
for testcase_num in range(1, len(my_testcases)+1): | ||
random_input_testcase_folder = os.path.join(tmp_work,"random_input", "test{:02}".format(testcase_num)) | ||
bmcutler marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
os.makedirs(random_input_testcase_folder) | ||
os.chdir(random_input_testcase_folder) | ||
|
||
# copy any instructor provided solution code files to testcase folder | ||
copy_contents_into(job_id,instructor_solution_path,random_input_testcase_folder,tmp_logs) | ||
|
||
# copy compile.out to the current directory | ||
shutil.copy (os.path.join(bin_path,"solution_runner.out"),os.path.join(random_input_testcase_folder,"my_solution_runner.out")) | ||
add_permissions(os.path.join(random_input_testcase_folder,"my_solution_runner.out"), stat.S_IXUSR | stat.S_IXGRP |stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
untrusted_grant_rwx_access(which_untrusted, random_input_testcase_folder) | ||
add_all_permissions(random_input_testcase_folder) | ||
|
||
inout_generator_success = subprocess.call([os.path.join(SUBMITTY_INSTALL_DIR, "sbin", "untrusted_execute"), | ||
which_untrusted, | ||
os.path.join(random_input_testcase_folder,"my_solution_runner.out"), | ||
queue_obj["gradeable"], | ||
queue_obj["who"], | ||
str(queue_obj["version"]), | ||
submission_string, | ||
"input", | ||
'--testcase', str(testcase_num)], | ||
stdout=logfile, | ||
cwd=random_input_testcase_folder) | ||
# remove the compilation program | ||
untrusted_grant_rwx_access(which_untrusted, random_input_testcase_folder) | ||
os.remove(os.path.join(random_input_testcase_folder,"my_solution_runner.out")) | ||
|
||
if inout_generator_success == 0: | ||
print (which_machine,which_untrusted,"INPUT GENERATOR OK") | ||
else: | ||
print (which_machine,which_untrusted,"INPUT GENERATOR FAILURE") | ||
grade_items_logging.log_message(job_id,is_batch_job,which_untrusted,item_name,message="INPUT GENERATOR FAILURE") | ||
|
||
# return to the main tmp directory | ||
os.chdir(tmp_work) | ||
subprocess.call(['ls', '-lR', '.'], stdout=open(tmp_logs + "/overall.txt", 'a')) | ||
|
||
# -------------------------------------------------------------------- | ||
|
||
# -------------------------------------------------------------------- | ||
# make the runner directory | ||
|
||
with open(os.path.join(tmp_logs,"overall.txt"),'a') as f: | ||
print ("====================================\nRUNNER STARTS", file=f) | ||
|
||
os.chdir(tmp_work) | ||
|
||
# move all executable files from the compilation directory to the main tmp directory | ||
# Note: Must preserve the directory structure of compiled files (esp for Java) | ||
|
||
|
@@ -531,14 +583,58 @@ def grade_from_zip(my_autograding_zip_file,my_submission_zip_file,which_untruste | |
print (which_machine,which_untrusted, "RUNNER FAILURE") | ||
grade_items_logging.log_message(job_id, is_batch_job, which_untrusted, item_name, message="RUNNER FAILURE") | ||
|
||
add_permissions_recursive(tmp_work, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
add_permissions_recursive(tmp_compilation, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH, | ||
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
# RUN SOLUTION RUNNER | ||
with open(os.path.join(tmp_logs,"overall.txt"),'a') as f: | ||
print ("====================================\nRUNNER SOLUTION STARTS", file=f) | ||
tmp_work_random_output = os.path.join(tmp_work,"random_output") | ||
os.mkdir(tmp_work_random_output) | ||
|
||
with open(os.path.join(tmp_logs,"output_generator_log.txt"), 'w') as logfile: | ||
for testcase_num in range(1, len(my_testcases)+1): | ||
testcase_folder = os.path.join(tmp_work_random_output, "test{:02}".format(testcase_num)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, let's add an "if no need to run output generation continue" here |
||
random_input_testcase_folder = os.path.join(tmp_work, "random_input", "test{:02}".format(testcase_num)) | ||
os.makedirs(testcase_folder) | ||
os.chdir(testcase_folder) | ||
|
||
# copy any instructor provided solution code files to testcase folder | ||
copy_contents_into(job_id,instructor_solution_path,testcase_folder,tmp_logs) | ||
|
||
# copy test input into testcase folder | ||
copy_contents_into(job_id,test_input_path,testcase_folder,tmp_logs) | ||
pattern_copy("random_input_to_runner",["*.txt"],random_input_testcase_folder,testcase_folder,tmp_logs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the random input is not a .txt file? |
||
|
||
# copy compile.out to the current directory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment isn't accurate. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changed compile.out to run.out |
||
shutil.copy (os.path.join(bin_path,"solution_runner.out"),os.path.join(testcase_folder,"my_solution_runner.out")) | ||
add_permissions(os.path.join(testcase_folder,"my_solution_runner.out"), stat.S_IXUSR | stat.S_IXGRP |stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) | ||
untrusted_grant_rwx_access(which_untrusted, testcase_folder) | ||
add_all_permissions(testcase_folder) | ||
|
||
output_generator_success = subprocess.call([os.path.join(SUBMITTY_INSTALL_DIR, "sbin", "untrusted_execute"), | ||
which_untrusted, | ||
os.path.join(testcase_folder,"my_solution_runner.out"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This solution won't work for networked gradeables. I'll handle this in the upcoming refactor. |
||
queue_obj["gradeable"], | ||
queue_obj["who"], | ||
str(queue_obj["version"]), | ||
submission_string, | ||
"output", | ||
'--testcase', str(testcase_num)], | ||
stdout=logfile, | ||
cwd=testcase_folder) | ||
# remove the compilation program | ||
untrusted_grant_rwx_access(which_untrusted, testcase_folder) | ||
os.remove(os.path.join(testcase_folder,"my_solution_runner.out")) | ||
|
||
if output_generator_success == 0: | ||
print (which_machine,which_untrusted,"OUTPUT GENERATION OK") | ||
else: | ||
print (which_machine,which_untrusted,"OUTPUT GENERATION FAILURE") | ||
grade_items_logging.log_message(job_id,is_batch_job,which_untrusted,item_name,message="OUTPUT GENERATION FAILURE") | ||
add_all_permissions(tmp_work) | ||
add_all_permissions(tmp_compilation) | ||
|
||
# return to the main tmp directory | ||
os.chdir(tmp_work) | ||
subprocess.call(['ls', '-lR', '.'], stdout=open(tmp_logs + "/overall.txt", 'a')) | ||
|
||
# -------------------------------------------------------------------- | ||
# RUN VALIDATOR | ||
|
@@ -646,14 +742,33 @@ def grade_from_zip(my_autograding_zip_file,my_submission_zip_file,which_untruste | |
# remove the test_input directory, so we don't archive it! | ||
shutil.rmtree(os.path.join(tmp_work,"test_input")) | ||
|
||
# remove the test_output directory, so we don't archive it! | ||
shutil.rmtree(os.path.join(tmp_work,"test_output")) | ||
|
||
# loop over the test case directories, and remove any files that are also in the test_input folder | ||
for testcase_num in range(1, len(my_testcases)+1): | ||
testcase_folder = os.path.join(tmp_work, "test{:02}".format(testcase_num)) | ||
random_input_testcase_folder = os.path.join(tmp_work,"random_input","test{:02}".format(testcase_num)) | ||
remove_test_input_files(os.path.join(tmp_logs,"overall.txt"),test_input_path,testcase_folder) | ||
remove_test_input_files(os.path.join(tmp_logs,"overall.txt"),random_input_testcase_folder,testcase_folder) | ||
|
||
# loop over the random output test case directories, and remove any files that are also in the test_input folder | ||
for testcase_num in range(1, len(my_testcases)+1): | ||
testcase_folder = os.path.join(tmp_work,"random_output", "test{:02}".format(testcase_num)) | ||
random_input_testcase_folder = os.path.join(tmp_work,"random_input","test{:02}".format(testcase_num)) | ||
remove_test_input_files(os.path.join(tmp_logs,"overall.txt"),test_input_path,testcase_folder) | ||
remove_test_input_files(os.path.join(tmp_logs,"overall.txt"),random_input_testcase_folder,testcase_folder) | ||
|
||
patterns_work_to_details = complete_config_obj["autograding"]["work_to_details"] | ||
pattern_copy("work_to_details",patterns_work_to_details,tmp_work,os.path.join(tmp_results,"details"),tmp_logs) | ||
|
||
try: | ||
patterns_work_to_random_output = complete_config_obj["autograding"]["work_to_random_output"] | ||
pattern_copy("work_to_random_output", patterns_work_to_random_output, tmp_results, tmp_logs) | ||
except: | ||
with open(os.path.join(tmp_logs,"overall.txt"),'a') as f: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This message isn't actually logged. Call print with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why hasn't this been resolved? |
||
print ("Sorry this is not working") | ||
|
||
if ("work_to_public" in complete_config_obj["autograding"] and | ||
len(complete_config_obj["autograding"]["work_to_public"]) > 0): | ||
# create the directory | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove these newly added, commented out lines