Source code for univention.testing.ucsschool.exam

"""
**Class Exam**

.. module:: exam
    :platform: Unix

.. moduleauthor:: Ammar Najjar <najjar@univention.de>
"""
from __future__ import print_function

import glob
import os
import re
import subprocess

import univention.testing.strings as uts
import univention.testing.utils as utils
from univention.testing.ucs_samba import wait_for_s4connector
from univention.testing.umc import Client, ClientSaml


[docs]def get_dir_files(dir_path, recursive=True): result = [] for f in glob.glob("%s/*" % dir_path): if os.path.isfile(f): result.append(os.path.basename(f)) if os.path.isdir(f) and recursive: result.extend(get_dir_files(f)) return result
[docs]def get_s4_rejected(): cmd = ["univention-s4connector-list-rejected"] out, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() out, err = out.decode("UTF-8"), err.decode("UTF-8") print("rejected Objects:", out, err) found = re.findall(r"DN:\s\w{2,4}=.*", out) return set(found)
[docs]def check_s4_rejected(existing_rejects): new_rejects = get_s4_rejected() fail = [x for x in new_rejects if x not in existing_rejects] assert not fail, "There is at least one new rejected object: %r" % (fail,)
[docs]def check_proof_uniqueMember(): cmd = ["/usr/share/univention-directory-manager-tools/proof_uniqueMembers"] popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = popen.communicate() out, err = out.decode("UTF-8"), err.decode("UTF-8") returncode = popen.returncode print(out, err, returncode) assert returncode == 0, "Proof unique members failed"
[docs]def wait_replications_check_rejected_uniqueMember(existing_rejects): utils.wait_for_replication() wait_for_s4connector() check_s4_rejected(existing_rejects)
# TODO uncomment next line after fixing bug #36251 # check_proof_uniqueMember()
[docs]class Exam(object): """Contains the needed functionality for exam module.\n :param school: name of the school :type school: str :param room: name of room of the exam :type room: str :param examEndTime: exam end time :type examEndTime: str in format "HH:mm" :param name: name of the exam to be created later :type name: str :param recipients: names of the classes to make the exam :type recipients: list of str :param directory: name of the directory for the exam, default=name :type directory: str :param files: list of files to be uploaded to the exam directory :type files: list of str :param sharemode: sharemode :type sharemode: str either "home" or "all" :param internetRule: name of the internet Rule to be applied in the exam :type internetRule: str :param customRule: cutom internet rule :type customRule: str :param connection: :type connection: UMC connection object """ def __init__( self, school, room, # room dn examEndTime, # in format "HH:mm" recipients, # list of classes dns name=None, directory=None, files=[], shareMode="home", internetRule="none", customRule="", connection=None, ): self.school = school self.room = room self.examEndTime = examEndTime self.recipients = recipients self.name = name if name else uts.random_name() self.directory = directory if directory else self.name self.files = files self.shareMode = shareMode self.internetRule = internetRule self.customRule = customRule if connection: self.client = connection else: self.client = Client.get_test_connection()
[docs] def start(self): """Starts an exam""" param = { "school": self.school, "name": self.name, "room": self.room, "examEndTime": self.examEndTime, "recipients": self.recipients, "directory": self.directory, "files": self.files, "shareMode": self.shareMode, "internetRule": self.internetRule, "customRule": self.customRule, } print("Starting exam %s in room %s" % (self.name, self.room)) print("param = %s" % param) reqResult = self.client.umc_command("schoolexam/exam/start", param).result print("Start exam response = ", reqResult) assert reqResult["success"], "Unable to start exam (%r)" % (param,)
[docs] def save(self, update=False, fields=None): """Saves an exam. If fields is a list only the given values are set in the request""" param = { "school": "", "name": "", "room": "", "examEndTime": "", "recipients": [], "directory": "", "files": [], "shareMode": "", "internetRule": "", "customRule": "", } if fields is None: param = { "school": self.school, "name": self.name, "room": self.room, "examEndTime": self.examEndTime, "recipients": self.recipients, "directory": self.directory, "files": self.files, "shareMode": self.shareMode, "internetRule": self.internetRule, "customRule": self.customRule, } else: for field in fields: param[field] = getattr(self, field, "") print("Saving exam {}".format(self.name)) command = "put" if update else "add" reqResult = self.client.umc_command("schoolexam/exam/{}".format(command), param).result print("Save exam response = {}".format(reqResult)) assert reqResult, "Unable to {} exam {!r}".format(command, param)
[docs] def get(self): """Gets an exam and returns result""" reqResult = self.client.umc_command("schoolexam/exam/get", [self.name]).result return reqResult
[docs] def delete(self): """Deletes an exam and returns result""" reqResult = self.client.umc_command("schoolexam/exam/delete", {"exams": [self.name]}).result return reqResult
[docs] def finish(self): """Finish an exam""" param = {"exam": self.name, "room": self.room} print("Finishing exam %s in room %s" % (self.name, self.room)) print("param = %s" % param) reqResult = self.client.umc_command("schoolexam/exam/finish", param).result print("Finish exam response = ", reqResult) assert reqResult["success"], "Unable to finish exam (%r)" % param
[docs] def genData(self, file_name, content_type, boundary, override_file_name=None): """Generates data in the form to be sent via http POST request.\n :param file_name: file name to be uploaded :type file_name: str :param content_type: type of the content of the file :type content_type: str ('text/plain',..) :param boundary: the boundary :type boundary: str (-------123091) :param flavor: flavor of the acting user :type flavor: str """ mime_file_name = override_file_name or os.path.basename(file_name) with open(file_name, "r") as f: data = r"""--{0} Content-Disposition: form-data; name="uploadedfile"; filename="{1}" Content-Type: {2} {3} --{0} Content-Disposition: form-data; name="iframe" false --{0} Content-Disposition: form-data; name="uploadType" html5 --{0}-- """.format( boundary, mime_file_name, content_type, f.read() ) return data.replace("\n", "\r\n")
[docs] def uploadFile(self, file_name, content_type=None, override_file_name=None): """Uploads a file via http POST request.\n :param file_name: file name to be uploaded :type file_name: str :param content_type: type of the content of the file :type content_type: str ('application/octet-stream',..) """ print("Uploading file %s" % file_name) content_type = content_type or "application/octet-stream" boundary = "---------------------------12558488471903363215512784168" data = self.genData(file_name, content_type, boundary, override_file_name=override_file_name) header_content = {"Content-Type": "multipart/form-data; boundary=%s" % (boundary,)} self.client.request("POST", "upload/schoolexam/upload", data, headers=header_content)
[docs] def get_internetRules(self): """Get internet rules""" reqResult = self.client.umc_command("schoolexam/internetrules", {}).result print("InternetRules = ", reqResult) return reqResult
[docs] def fetch_internetRule(self, internetRule_name): if internetRule_name not in self.get_internetRules(): utils.fail("Exam %s was not able to fetch internet rule %s" % (self.name, internetRule_name))
[docs] def get_schools(self): """Get schools""" reqResult = self.client.umc_command("schoolexam/schools", {}).result schools = [x["label"] for x in reqResult] print("Schools = ", schools) return schools
[docs] def fetch_school(self, school): assert school in self.get_schools(), "Exam %s was not able to fetch school %s" % ( self.name, school, )
[docs] def get_groups(self): """Get groups""" reqResult = self.client.umc_command( "schoolexam/groups", {"school": self.school, "pattern": ""} ).result print("Groups response = ", reqResult) groups = [x["label"] for x in reqResult] print("Groups = ", groups) return groups
[docs] def fetch_groups(self, group): assert group in self.get_groups(), "Exam %s was not able to fetch group %s" % (self.name, group)
[docs] def get_lessonEnd(self): """Get lessonEnd""" reqResult = self.client.umc_command("schoolexam/lesson_end", {}).result print("Lesson End = ", reqResult) return reqResult
[docs] def fetch_lessonEnd(self, lessonEnd): assert lessonEnd in self.get_lessonEnd(), "Exam %s was not able to fetch lessonEnd %s" % ( self.name, lessonEnd, )
[docs] def collect(self): """Collect results""" reqResult = self.client.umc_command("schoolexam/exam/collect", {"exam": self.name}).result print("Collect respose = ", reqResult) return reqResult
[docs] def check_collect(self): username = self.client.username or utils.UCSTestDomainAdminCredentials().username path = os.path.join( os.path.expanduser("~{}".format(username)), "Klassenarbeiten/%s-Ergebnisse" % (self.name,) ) path_files = get_dir_files(path) assert set(self.files).issubset(set(path_files)), "%r were not collected to %r" % ( self.files, path, )
[docs] def check_upload(self): path = "/tmp/ucsschool-exam-upload*" path_files = get_dir_files(path) assert set(self.files).issubset(set(path_files)), "%r were not uploaded to %r" % ( self.files, path, )
[docs] def check_distribute(self): path = "/home/%s/schueler" % self.school path_files = get_dir_files(path) assert set(self.files).issubset(set(path_files)), "%r were not uploaded to %r" % ( self.files, path, )
[docs]class ExamSaml(Exam): def __init__(self, *args, **kwargs): kwargs.setdefault("connection", ClientSaml.get_test_connection()) super(ExamSaml, self).__init__(*args, **kwargs)