From 681a88ea83f7419feee2a196715e933eac698bc0 Mon Sep 17 00:00:00 2001 From: virusdefender Date: Wed, 25 Jan 2017 23:01:33 +0800 Subject: [PATCH] add upload test case zip test --- conf/tests.py | 1 + problem/tests.py | 50 ++++++++++++++++++++++++++++++++++++++++++ problem/views/admin.py | 42 ++++++++++++++++++++++++++++++----- 3 files changed, 88 insertions(+), 5 deletions(-) diff --git a/conf/tests.py b/conf/tests.py index 85a15070..fd05b439 100644 --- a/conf/tests.py +++ b/conf/tests.py @@ -1,6 +1,7 @@ import hashlib from django.utils import timezone + from utils.api.tests import APITestCase from .models import JudgeServer, JudgeServerToken, SMTPConfig diff --git a/problem/tests.py b/problem/tests.py index 8dfdb0e3..32525c2b 100644 --- a/problem/tests.py +++ b/problem/tests.py @@ -1,3 +1,9 @@ +import os +import shutil +from zipfile import ZipFile + +from django.conf import settings + from utils.api.tests import APITestCase from .models import ProblemTag @@ -16,6 +22,8 @@ class ProblemTagListAPITest(APITestCase): class TestCaseUploadAPITest(APITestCase): def setUp(self): self.api = TestCaseUploadAPI() + self.url = self.reverse("test_case_upload_api") + self.create_super_admin() def test_filter_file_name(self): self.assertEqual(self.api.filter_name_list(["1.in", "1.out", "2.in", ".DS_Store"], spj=False), ["1.in", "1.out"]) @@ -23,3 +31,45 @@ class TestCaseUploadAPITest(APITestCase): self.assertEqual(self.api.filter_name_list(["1.in", "1.out", "2.in"], spj=True), ["1.in", "2.in"]) self.assertEqual(self.api.filter_name_list(["2.in", "3.in"], spj=True), []) + + def make_test_case_zip(self): + base_dir = os.path.join("/tmp", "test_case") + shutil.rmtree(base_dir, ignore_errors=True) + os.mkdir(base_dir) + file_names = ["1.in", "1.out", "2.in", ".DS_Store"] + for item in file_names: + with open(os.path.join(base_dir, item), "w", encoding="utf-8") as f: + f.write(item + "\n" + item + "\r\n" + "end") + zip_file = os.path.join(base_dir, "test_case.zip") + with ZipFile(os.path.join(base_dir, "test_case.zip"), "w") as f: + for item in file_names: + f.write(os.path.join(base_dir, item), item) + return zip_file + + def test_upload_spj_test_case_zip(self): + with open(self.make_test_case_zip(), "rb") as f: + resp = self.client.post(self.url, + data={"spj": "true", "file": f}, format="multipart") + self.assertSuccess(resp) + data = resp.data["data"] + self.assertEqual(data["spj"], True) + test_case_dir = os.path.join(settings.TEST_CASE_DIR, data["id"]) + self.assertTrue(os.path.exists(test_case_dir)) + for item in data["info"]: + name = item["input_name"] + with open(os.path.join(test_case_dir, name), "r", encoding="utf-8") as f: + self.assertEqual(f.read(), name + "\n" + name + "\n" + "end") + + def test_upload_test_case_zip(self): + with open(self.make_test_case_zip(), "rb") as f: + resp = self.client.post(self.url, + data={"spj": "false", "file": f}, format="multipart") + self.assertSuccess(resp) + data = resp.data["data"] + self.assertEqual(data["spj"], False) + test_case_dir = os.path.join(settings.TEST_CASE_DIR, data["id"]) + self.assertTrue(os.path.exists(test_case_dir)) + for item in data["info"]: + name = item["input_name"] + with open(os.path.join(test_case_dir, name), "r", encoding="utf-8") as f: + self.assertEqual(f.read(), name + "\n" + name + "\n" + "end") diff --git a/problem/views/admin.py b/problem/views/admin.py index aea91dd2..859fde76 100644 --- a/problem/views/admin.py +++ b/problem/views/admin.py @@ -1,12 +1,13 @@ +import hashlib +import json import os import zipfile from django.conf import settings -from utils.api import CSRFExemptAPIView from account.decorators import admin_required +from utils.api import CSRFExemptAPIView from utils.shortcuts import rand_str - from ..serializers import TestCaseUploadForm @@ -51,7 +52,7 @@ class TestCaseUploadAPI(CSRFExemptAPIView): f.write(chunk) try: zip_file = zipfile.ZipFile(tmp_file) - except zipfile.BadZipfile: + except zipfile.BadZipFile: return self.error("Bad zip file") name_list = zip_file.namelist() test_case_list = self.filter_name_list(name_list, spj=spj) @@ -62,11 +63,42 @@ class TestCaseUploadAPI(CSRFExemptAPIView): test_case_dir = os.path.join(settings.TEST_CASE_DIR, test_case_id) os.mkdir(test_case_dir) + size_cache = {} + md5_cache = {} + for item in test_case_list: with open(os.path.join(test_case_dir, item), "wb") as f: - f.write(zip_file.read(item).replace(b"\r\n", b"\n")) + content = zip_file.read(item).replace(b"\r\n", b"\n") + size_cache[item] = len(content) + if item.endswith(".out"): + md5_cache[item] = hashlib.md5(content).hexdigest() + f.write(content) + test_case_info = {"spj": spj, "test_cases": {}} + hint = None diff = set(name_list).difference(set(test_case_list)) if diff: hint = ", ".join(diff) + " are ignored" - return self.success({"id": test_case_id, "file_list": test_case_list, "hint": hint, "spj": spj}) + + ret = [] + + if spj: + for index, item in enumerate(test_case_list): + data = {"input_name": item, "input_size": size_cache[item]} + ret.append(data) + test_case_info["test_cases"][str(index + 1)] = data + else: + # ["1.in", "1.out", "2.in", "2.out"] => [("1.in", "1.out"), ("2.in", "2.out")] + test_case_list = zip(*[test_case_list[i::2] for i in range(2)]) + for index, item in enumerate(test_case_list): + data = {"stripped_output_md5": md5_cache[item[1]], + "input_size": size_cache[item[0]], + "output_size": size_cache[item[1]], + "input_name": item[0], + "output_name": item[1]} + ret.append(data) + test_case_info["test_cases"][str(index + 1)] = data + + with open(os.path.join(test_case_dir, "info"), "w", encoding="utf-8") as f: + f.write(json.dumps(test_case_info, indent=4)) + return self.success({"id": test_case_id, "info": ret, "hint": hint, "spj": spj})