def test_sessionexercise_eval(self): s_activity = SessionActivity.objects.create(user=self.user, activity=self.pltp) s_exercise = SessionExercise.objects.create( session_activity=s_activity, pl=self.pl) e = s_exercise.evaluate(R(user=self.user), {'answer': ""}) self.assertIn('grade', e[0]) self.assertIn('op1', s_exercise.context) self.assertIn('op2', s_exercise.context) broken_pl = load_file(self.dir, "invalid_value_grader.pl")[0] broken_pl.save() s_exercise = SessionExercise.objects.create( session_activity=s_activity, pl=broken_pl) s_exercise.build(R()) e = s_exercise.evaluate( R(user=self.user), {'answer': s_exercise.context['op1'] + s_exercise.context['op2']}) self.assertTrue("Sandbox error:" in e[1]) broken_pl = load_file(self.dir, "broken_grader.pl")[0] broken_pl.save() s_exercise = SessionExercise.objects.create( session_activity=s_activity, pl=broken_pl) s_exercise.build(R()) e = s_exercise.evaluate( R(user=self.user), {'answer': s_exercise.context['op1'] + s_exercise.context['op2']}) self.assertTrue( "Une erreur s'est produite lors de l'exécution du grader ", e[1])
def test_pl_option(request, filebrowser, target): """ Allwo to test a PL.""" if request.method != 'GET': return HttpResponseNotAllowed(['GET']) try: path = join(filebrowser.full_path(), target) rel_path = join(filebrowser.relative, target).replace(filebrowser.directory.name, "") pl, warnings = load_file(filebrowser.directory, rel_path) if not pl: messages.error(request, warnings) return redirect_fb(request.GET.get('relative_h', '.')) exercise = PLInstance(pl.json) request.session['exercise'] = dict(exercise.dic) preview = exercise.render(request) return render(request, 'filebrowser/test_pl.html', { 'preview': preview, }) except Exception as e: msg = "Impossible to display '" + target + "' : " + htmlprint.code( str(type(e)) + ' - ' + str(e)) if settings.FILEBROWSER_ROOT in msg: msg = msg.replace(settings.FILEBROWSER_ROOT + "/", "") messages.error(request, msg) return redirect_fb(request.GET.get('relative_h', '.'))
def setUpTestData(cls): if os.path.isdir(FAKE_FB_ROOT): shutil.rmtree(FAKE_FB_ROOT) cls.user = User.objects.create_user(username='******', password='******') cls.c = Client() cls.c.force_login(cls.user, backend=settings.AUTHENTICATION_BACKENDS[0]) cls.dir = Directory.objects.create(name='dir1', owner=cls.user) shutil.rmtree(cls.dir.root) shutil.copytree(FAKE_PL, cls.dir.root) cls.pl = load_file(cls.dir, "random_add.pl")[0] cls.pl.json['seed'] = 2 cls.pl.save() cls.pltp = load_file(cls.dir, "random_all.pltp")[0] cls.pltp.save() cls.activity = Activity.objects.create(name="test", pltp=cls.pltp, id=1)
def test_load_file(self): try: res = loader.load_file(self.dir, "working.pl") self.assertEqual(type(res[0]), models.PL) self.assertEqual(res[1], []) res = loader.load_file(self.dir, "working.pltp") self.assertEqual(type(res[0]), models.PLTP) self.assertEqual(res[1], []) res = loader.load_file(self.dir, "missing_pl.pltp") self.assertIs(res[0], None) self.assertEqual(type(res[1]), str) except AssertionError: print(res[1]) raise
def compile_pl(request): """ Used by the PL editor to compile a PL""" post = json.loads(request.body.decode()) path = post.get('path') if not path: return HttpResponseBadRequest(missing_parameter('path')) path_components = path.split('/') directory = path_components[0] response = {'compiled': True} try: path = join_fb_root(path) with open(path, 'r') as f: content = f.read() shutil.copyfile(path, path + ".bk") with open(path, 'w+') as f: # Writting editor content into the file print(content, file=f) directory = Directory.objects.get(name=directory) relative = os.path.join(*(path_components[1:])) pl, warnings = load_file(directory, relative) if not pl: response['compiled'] = False else: response['json'] = pl.json response['warnings'] = warnings except Exception: # pragma: no cover response['compiled'] = False finally: shutil.move(path + ".bk", path) return HttpResponse( json.dumps(response), content_type='application/json', status=200 )
def test_pl(request): path = request.GET.get('path') if not path: return HttpResponseBadRequest(missing_parameter('path')) try: path_components = path.split('/') directory = Directory.objects.get(name=path_components[0]) relative = os.path.join(*(path_components[1:])) pl, warnings = load_file(directory, relative) if not pl: return HttpResponseBadRequest(warnings.replace(settings.FILEBROWSER_ROOT, "")) pl.save() exercise = SessionTest.objects.create(pl=pl, user=request.user) preview = exercise.get_exercise(request) return render(request, 'filebrowser/test.html', { 'preview': preview, 'id': pl.id, }) except Exception as e: # pragma: no cover msg = ("Impossible to test '" + os.path.basename(path) + "' : " + htmlprint.code( str(type(e)) + ' - ' + str(e))) return HttpResponseBadRequest(msg.replace(settings.FILEBROWSER_ROOT, ""))
def test_pl_option(request, filebrowser, target): if request.method != 'GET': return HttpResponseNotAllowed(['GET']) try: rel_path = join(filebrowser.relative, target).replace('./' + filebrowser.directory.name, "") pl, warnings = load_file(filebrowser.directory, rel_path) if not pl: messages.error(request, "Failed to load '" + target + "': \n" + warnings) else: if warnings: for warning in warnings: messages.warning(request, warning) request.session['exercise'] = None return try_pl(request, pl, warnings) except Exception as e: msg = "Impossible to test '" + target + "' : " + str(type(e)).replace( '<', '[').replace('>', ']') + " - " + str(e) if FILEBROWSER_ROOT in msg: msg = msg.replace(FILEBROWSER_ROOT + "/", "") messages.error(request, msg) return redirect_fb(request.GET.get('relative_h', '.'))
def load_pltp_option(request, filebrowser, target): """ Load the target""" if request.method != 'GET': return HttpResponseNotAllowed(['GET']) try: rel_path = join(filebrowser.relative, target).replace('./'+filebrowser.directory.name, "") pltp, warnings = load_file(filebrowser.directory, rel_path, True) if not pltp and not warnings: messages.info(request, "This PLTP is already loaded") elif not pltp: messages.error(request, "Failed to load '"+target+"': \n"+warnings) else: if warnings: for warning in warnings: messages.warning(request, warning) url_lti = request.scheme + "://" + request.get_host()+"/playexo/activity/lti/"+pltp.name+"/"+pltp.sha1+"/" url_test = "/playexo/activity/test/"+pltp.name+"/"+pltp.sha1+"/" messages.success(request, "L'activité <b>'"+pltp.name+"'</b> a bien été créée et a pour URL LTI: \ <br>   '"+url_lti+"' <p id=\"url\" hidden>"+url_lti+"</p> \ <button style=\"height: 25px;padding: 0 5px;\" class=\"btn btn-success\" \ onclick=\"copyToClipboard('#url')\"><i class=\"far fa-copy\"></i> Copier\ </button><br>L'activité sera créée lorsqu'une personne cliquera sur le lien \ depuis un client LTI. Pour la tester en local, cliquez <a target=\"_blank\" \ href=\""+url_test+"\">ici</a>.""") except Exception as e: msg = "Impossible to load '"+target+"' : "+ str(type(e)).replace('<', '[').replace('>', ']') + " - " + str(e) msg = msg if not DEBUG else msg + ':\n' + traceback.format_exc() if FILEBROWSER_ROOT in msg: msg = msg.replace(FILEBROWSER_ROOT+"/", "") messages.error(request, msg) return redirect_fb(request.GET.get('relative_h', '.'))
def test_test_pl_failing_tests(self): pl = load_file(self.dir, "failing_tests.pl")[0] pl.save() response = self.c.get(reverse("playexo:test_pl", args=[pl.id])) self.assertEquals(response.status_code, 200) self.assertIn("Builder failed:", response.content.decode()) self.assertIn("Une erreur", response.content.decode()) self.assertIn("Invalid test format", response.content.decode())
def setUpTestData(self): self.user = User.objects.create_user(username='******', password='******') self.dir = Directory.objects.create(name='plbank', owner=self.user) self.pl = load_file(self.dir, 'plbank/python/function/carre.pl')[0] self.sandbox = Sandbox.objects.create( url="http://127.0.0.1:8000/sandbox/?action=execute", name="sanbdboxlocal", priority=200)
def test_test_pl_not_allowed(self): user = User.objects.create_user(username='******', password='******') client = Client() client.force_login(user, backend=settings.AUTHENTICATION_BACKENDS[0]) pl = load_file(self.dir, "static_add.pl")[0] pl.save() response = client.get(reverse("playexo:test_pl", args=[pl.id])) self.assertEquals(response.status_code, 403)
def preview_pl(request): """ Used by the PL editor to preview a PL and test the preview's answers""" if request.method != 'POST': return HttpResponse('405 Method Not Allowed', status=405) post = json.loads(request.body.decode()) if post['requested_action'] == 'preview': # Asking for preview try: path = settings.FILEBROWSER_ROOT + '/' + post['path'] shutil.copyfile(path, path + ".bk") with open(path, 'w+') as f: # Writting editor content into the file print(post['content'], file=f) directory = Directory.objects.get(name=post['directory']) rel_path = post['path'].replace(directory.name, "") pl, warnings = load_file(directory, rel_path) if not pl: preview = '<div class="alert alert-danger" role="alert"> Failed to load \'' + basename( rel_path) + "': \n" + warnings + "</div>" else: if warnings: [ messages.warning(request, warning) for warning in warnings ] exercise = PLInstance(pl.json) request.session['exercise'] = dict(exercise.dic) preview = exercise.render(request) except Exception as e: preview = '<div class="alert alert-danger" role="alert"> Failed to load \'' \ + basename(rel_path) + "': \n\n" \ + htmlprint.code(str(e)) + "</div>" finally: shutil.move(path + ".bk", path) return HttpResponse(json.dumps({'preview': preview}), content_type='application/json') elif post['requested_action'] == 'submit': # Answer from the preview exercise = request.session.get('exercise', None) if exercise: exercise = PLInstance(exercise) success, feedback = exercise.evaluate(post['inputs']) if (success == None): feedback_type = "info" elif success: feedback_type = "success" else: feedback_type = "failed" return HttpResponse(json.dumps({ 'feedback_type': feedback_type, 'feedback': feedback }), content_type='application/json') return HttpResponseBadRequest(content="Couldn't resolve ajax request")
def test_reload_pltp(self): pltp = load_file(self.dir, "working.pltp")[0] response = self.c.post(reverse("filebrowser:option"), { 'name': 'reload_pltp', 'path': 'Yggdrasil/working.pltp', 'activity_id': pltp.pk, }, content_type='application/json') self.assertContains(response, "recharg", status_code=200)
def setUpTestData(cls): cls.user = User.objects.create_user(username='******', password='******') cls.user.profile.role = Role.ADMINISTRATOR dir_name = os.path.join(FAKE_FB_ROOT, "dir1") if os.path.isdir(dir_name): shutil.rmtree(dir_name) cls.dir = Directory.objects.create(name='dir1', owner=cls.user) shutil.rmtree(cls.dir.root) shutil.copytree(os.path.join(FAKE_FB_ROOT, '../fake_pl'), cls.dir.root) cls.pl = load_file(cls.dir, "random_add.pl")[0] cls.pl.json['seed'] = 2 cls.pl.save() cls.pl2 = load_file(cls.dir, "random_add_eval_func.pl")[0] cls.pl2.json['seed'] = 2 cls.pl2.save() cls.pltp = load_file(cls.dir, "random_all.pltp")[0] cls.pltp.save() cls.factory = RequestFactory()
def test_download_env(self): pl = load_file(self.dir, "working.pl")[0] resp = SandboxBuild(pl.json).call() response = self.c.get(reverse("filebrowser:dlenv", args=[resp['id']]), {}, content_type='application/json') tar_name = os.path.join(self.dir.root, "tar_test.tgz") with open(tar_name, "wb") as f: f.write(response.content) self.assertEqual(response.status_code, 200) self.assertTrue(is_tarfile(tar_name))
def preview_pl(request): """ Used by the PL editor to preview a PL""" post = json.loads(request.body.decode()) exists = True path = post.get('path') if not path: exists = False path = os.path.join(HOME_DIR, str(uuid.uuid4())) path += '.pl' content = post.get('content', '') path_components = path.split('/') directory = path_components[0] try: path = os.path.join(settings.FILEBROWSER_ROOT, path) if exists: shutil.copyfile(path, path + ".bk") with open(path, 'w+') as f: # Writting editor content into the file print(content, file=f) directory = Directory.objects.get(name=directory) relative = os.path.join(*(path_components[1:])) pl, warnings = load_file(directory, relative) if not pl: preview = '<div class="alert alert-danger" role="alert"> 1 Failed to load \'' \ + os.path.basename(relative) + "': \n" + warnings + "</div>" else: if warnings: [messages.warning(request, warning) for warning in warnings] pl.save() exercise = SessionTest.objects.create(pl=pl, user=request.user) preview = exercise.get_exercise(request) except Exception as e: # pragma: no cover preview = ('<div class="alert alert-danger" role="alert"> 3 Failed to load \'' + os.path.basename(relative) + "': \n\n" + htmlprint.code(str(e))) if settings.DEBUG: preview += "\n\nDEBUG set to True:\n" + htmlprint.html_exc() preview += "</div>" finally: if exists: shutil.move(path + ".bk", path) else: os.remove(path) preview = get_template("filebrowser/preview.html").render({'preview': preview}, request) return HttpResponse( json.dumps({'preview': preview}), content_type='application/json', status=200 )
def setUpTestData(cls): if os.path.isdir(FAKE_FB_ROOT): shutil.rmtree(FAKE_FB_ROOT) cls.user = User.objects.create_user(username='******', password='******') dir_name = os.path.join(FAKE_FB_ROOT, "dir1") if os.path.isdir(dir_name): shutil.rmtree(dir_name) cls.dir = Directory.objects.create(name='dir1', owner=cls.user) shutil.rmtree(cls.dir.root) shutil.copytree(os.path.join(FAKE_FB_ROOT, '../fake_pl'), cls.dir.root) cls.pl = load_file(cls.dir, "working.pl")[0] cls.pl.json['seed'] = 2
def test_sessionexercise_build(self): s_activity = SessionActivity.objects.create(user=self.user, activity=self.pltp) s_exercise = SessionExercise.objects.create( session_activity=s_activity, pl=self.pl) s_exercise.build(R()) self.assertIn('op1', s_exercise.context.keys()) self.assertIn('op2', s_exercise.context.keys()) broken_pl = load_file(self.dir, "notworking.pl")[0] broken_pl.save() s_exercise = SessionExercise.objects.create( session_activity=s_activity, pl=broken_pl) with self.assertRaises(BuildScriptError): s_exercise.build(R(user=self.user)) broken_pl = load_file(self.dir, "no_context.pl")[0] broken_pl.save() s_exercise = SessionExercise.objects.create( session_activity=s_activity, pl=broken_pl) with self.assertRaises(SandboxError): s_exercise.build(R(user=self.user))
def test_evaluate_pl(self): pl = load_file(self.dir, "working.pl")[0] pl.save() s_test = SessionTest.objects.create(user=self.user, pl=pl) response = self.c.post(reverse("filebrowser:option"), { 'name': 'evaluate_pl', 'path': 'Yggdrasil/working.pl', 'data': { 'session_id': s_test.id, 'answers': {}, } }, content_type='application/json') self.assertContains(response, "navigation") self.assertContains(response, "Merci de rentrer un entier") self.assertContains(response, "Quentin Coumes")
def test_preview_submit(self): pl = load_file(self.dir, "working.pl")[0] pl.save() s_test = SessionTest.objects.create(user=self.user, pl=pl) response = self.c.post(reverse("filebrowser:option"), { 'name': 'preview_pl', 'path': 'Yggdrasil/working.pl', 'requested_action': 'submit', 'data': { 'session_id': s_test.id, 'answers': {}, } }, content_type='application/json') self.assertContains(response, "navigation", status_code=200) self.assertContains(response, "Merci de rentrer un entier", status_code=200) self.assertContains(response, "Quentin Coumes<", status_code=200)
def edit_pl_option(request, filebrowser, target): """ Start the editor with preview to edit a PL.""" if request.method != 'GET': return HttpResponseNotAllowed(['GET']) try: path = join(filebrowser.full_path(), target) with open(path, 'r') as f: content = f.read() rel_path = join(filebrowser.relative, target).replace(filebrowser.directory.name, "") pl, warnings = load_file(filebrowser.directory, rel_path) if not pl: preview = '<div class="alert alert-danger" role="alert"> Failed to load \'' + target + "': \n" + warnings + "</div>" else: if warnings: [messages.warning(request, warning) for warning in warnings] try: exercise = PLInstance(pl.json) request.session['exercise'] = dict(exercise.dic) preview = exercise.render(request) except Exception as e: preview = '<div class="alert alert-danger" role="alert"> Failed to load \'' \ + basename(rel_path) + "': \n\n" \ + htmlprint.code(str(e)) + "</div>" return render( request, 'filebrowser/editor_pl.html', { 'file_content': content, 'filename': basename(path), 'filepath': path.replace(settings.FILEBROWSER_ROOT + '/', ''), 'dir_name': filebrowser.directory.name, 'preview': preview, }) except Exception as e: msg = "Impossible to edit '" + target + "' : " + htmlprint.code( str(type(e)) + ' - ' + str(e)) if settings.FILEBROWSER_ROOT in msg: msg = msg.replace(settings.FILEBROWSER_ROOT + "/", "") messages.error(request, msg) return redirect_fb(request.GET.get('relative_h', '.'))
def load_pltp(request): path = request.GET.get('path') if not path: return HttpResponseBadRequest(missing_parameter('path')) try: path_components = path.split('/') directory = Directory.objects.get(name=path_components[0]) relative = os.path.join(*(path_components[1:])) pltp, warnings = load_file(directory, relative) if not pltp and not warnings: # pragma: no cover return HttpResponseBadRequest("This PLTP is already loaded") elif not pltp: # pragma: no cover return HttpResponseBadRequest("Failed to load '" + path + "': \n" + warnings) else: msg = '' if warnings: # pragma: no cover for warning in warnings: msg += str(warning) pltp.teacher.add(request.user) url_lti = request.build_absolute_uri( reverse("activity:play", args=[pltp.pk])) msg += "L'activité <b>'" + pltp.name + "'</b> a bien été créée et a pour URL LTI: \ <br>    <input id=\"copy\" style=\"width: 700px;\" value=\"" + \ url_lti + "\" readonly> \ <a target='_blank' rel='noopener noreferrer' class='btn btn-dark' href='" + \ url_lti + "'><i class='far fa-eye'></i> OPEN\ </a>" return HttpResponse(msg) except Exception as e: # pragma: no cover msg = "Impossible to load '" + path + "' : " + htmlprint.code( str(type(e)) + ' - ' + str(e)) if settings.DEBUG: msg += ("DEBUG set to True: " + htmlprint.html_exc()) return HttpResponseBadRequest(msg)
def pl_tuto(request): post = json.loads(request.body.decode()) content = post.get('student') if not content: return HttpResponseBadRequest(missing_parameter('student')) path = post.get("path") if not path: path = 'Yggdrasil/conceptexo/pltuto.pl' path_components = path.split('/') directory = path_components[0] try: path = join_fb_root(path) with open(path, 'w') as f: print(content, file=f) directory = Directory.objects.get(name=directory) relative = os.path.join(*(path_components[1:])) pl, warnings = load_file(directory, relative) response = {'compiled': True} if not pl: response['compiled'] = False response['warnings'] = warnings else: response['json'] = pl.json response['warnings'] = warnings except Exception: # pragma: no cover response['compiled'] = False finally: os.remove(path) return HttpResponse( json.dumps(response), content_type='application/json', status=200 ) return HttpResponseBadRequest(content="Couldn't resolve ajax request")
def preview_pl(request): """ Used by the PL editor to preview a PL and test the preview's answers""" post = json.loads(request.body.decode()) if post.get('requested_action', '') == 'preview': # Asking for preview path = post.get('path') if not path: return HttpResponseBadRequest("Missing parameter 'path'") path_components = path.split('/') directory = path_components[0] try: path = os.path.join(settings.FILEBROWSER_ROOT, path) shutil.copyfile(path, path + ".bk") with open(path, 'w+') as f: # Writting editor content into the file print(post.get('content', ''), file=f) directory = Directory.objects.get(name=directory) file_path = os.path.join(*(path_components[1:])) pl, warnings = load_file(directory, file_path) if not pl: preview = '<div class="alert alert-danger" role="alert"> Failed to load \'' \ + os.path.basename(file_path) + "': \n" + warnings + "</div>" else: if warnings: [ messages.warning(request, warning) for warning in warnings ] pl.save() exercise = SessionTest.objects.create(pl=pl, user=request.user) preview = exercise.get_exercise(request) except Exception as e: # pragma: no cover preview = ( '<div class="alert alert-danger" role="alert"> Failed to load \'' + os.path.basename(file_path) + "': \n\n" + htmlprint.code(str(e))) if settings.DEBUG: preview += "\n\nDEBUG set to True:\n" + htmlprint.html_exc() preview += "</div>" finally: shutil.move(path + ".bk", path) return HttpResponse(json.dumps({'preview': preview}), content_type='application/json', status=200) elif post.get('requested_action', '') == 'submit': # Answer from the preview data = post.get('data', {}) if 'session_id' not in data or not data['session_id']: return HttpResponseBadRequest( content="Couldn't resolve ajax request") exercise = SessionTest.objects.get(pk=data['session_id']) answer, feedback = exercise.evaluate(request, data['answers'], test=True) return HttpResponse(json.dumps({ "navigation": None, "exercise": exercise.get_exercise(request, answer=answer), "feedback": feedback, }), content_type='application/json') return HttpResponseBadRequest(content="Couldn't resolve ajax request")
def test_test_pl_no_tests(self): pl = load_file(self.dir, "working.pl")[0] pl.save() response = self.c.get(reverse("playexo:test_pl", args=[pl.id])) self.assertEquals(response.status_code, 200) self.assertIn("Error during testing", response.content.decode())
def test_test_pl(self): pl = load_file(self.dir, "static_add.pl")[0] pl.save() response = self.c.get(reverse("playexo:test_pl", args=[pl.id])) self.assertEquals(response.status_code, 200)
def test_load_file_debug(self, mock_logger): res = loader.load_file(self.dir, "missing_pl.pltp") self.assertIs(res[0], None) self.assertEqual(type(res[1]), str) self.assertTrue("DEBUG set to True" in res[1])