diff options
author | Prabhu Ramachandran | 2016-09-21 17:58:12 +0530 |
---|---|---|
committer | GitHub | 2016-09-21 17:58:12 +0530 |
commit | 8e4ead8ab4caa9366e5357840e1912cbfb8cdb85 (patch) | |
tree | a8a9b90e0df9ce0893e7741bc33309af86ea034d | |
parent | 4f384f81cbde58f5eaa616dce85f1e4d60ea2c66 (diff) | |
parent | 48f5117a0a0f7f712d3bafabf06e1c63de56e9fa (diff) | |
download | online_test-8e4ead8ab4caa9366e5357840e1912cbfb8cdb85.tar.gz online_test-8e4ead8ab4caa9366e5357840e1912cbfb8cdb85.tar.bz2 online_test-8e4ead8ab4caa9366e5357840e1912cbfb8cdb85.zip |
Merge pull request #134 from ankitjavalkar/selenium-test-with-qdemo
Selenium test with qdemo
-rw-r--r-- | .travis.yml | 5 | ||||
-rw-r--r-- | yaksh/live_server_tests/__init__.py | 0 | ||||
-rw-r--r-- | yaksh/live_server_tests/load_test.py | 77 | ||||
-rw-r--r-- | yaksh/live_server_tests/selenium_test.py | 145 | ||||
-rw-r--r-- | yaksh/tests/test_questions.json | 50 |
5 files changed, 277 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml index 8ad6c5f..3484d2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,11 +14,16 @@ install: - pip install -q Django==$DJANGO - pip install -q pytz==2016.4 - pip install -q python-social-auth==0.2.19 + - pip install selenium before_install: - sudo apt-get update -qq - sudo apt-get install -y scilab + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start" + - sleep 3 # give xvfb some time to start # command to run tests script: - python manage.py test -v 2 yaksh + - python manage.py test -v 2 yaksh.live_server_tests diff --git a/yaksh/live_server_tests/__init__.py b/yaksh/live_server_tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/yaksh/live_server_tests/__init__.py diff --git a/yaksh/live_server_tests/load_test.py b/yaksh/live_server_tests/load_test.py new file mode 100644 index 0000000..17934d4 --- /dev/null +++ b/yaksh/live_server_tests/load_test.py @@ -0,0 +1,77 @@ +import os +import signal +import subprocess +from datetime import datetime +import pytz +from threading import Thread +from selenium.webdriver.firefox.webdriver import WebDriver + +from django.contrib.staticfiles.testing import StaticLiveServerTestCase + +from yaksh.models import User, Profile, Question, Quiz, Course, QuestionPaper, TestCase +from selenium_test import SeleniumTest + +from yaksh.code_server import ServerPool +from yaksh import settings + + +class YakshSeleniumTests(StaticLiveServerTestCase): + @classmethod + def setUpClass(cls): + super(YakshSeleniumTests, cls).setUpClass() + # setup a demo code server + settings.code_evaluators['python']['standardtestcase'] = \ + "yaksh.python_assertion_evaluator.PythonAssertionEvaluator" + settings.code_evaluators['c']['standardtestcase'] = \ + "yaksh.cpp_code_evaluator.CppCodeEvaluator" + settings.code_evaluators['bash']['standardtestcase'] = \ + "yaksh.bash_code_evaluator.BashCodeEvaluator" + settings.SERVER_POOL_PORT = 53578 + code_server_pool = ServerPool(ports=settings.SERVER_PORTS, pool_port=settings.SERVER_POOL_PORT) + cls.code_server_pool = code_server_pool + cls.code_server_thread = t = Thread(target=code_server_pool.run) + t.start() + + demo_student = User.objects.create_user(username='demo_student', + password='demo_student', + email='demo_student@test.com' + ) + demo_student_profile = Profile.objects.create(user=demo_student, + roll_number=3, institute='IIT', + department='Chemical', position='Student' + ) + + demo_mod = User.objects.create_user(username='demo_mod', + password='demo_mod', + email='demo_mod@test.com' + ) + demo_mod_profile = Profile.objects.create(user=demo_mod, + roll_number=0, institute='IIT', + department='Chemical', position='Moderator' + ) + + course_obj = Course() + course_obj.create_demo(demo_mod) + demo_course = Course.objects.get(id=1) + + demo_course.students.add(demo_student) + + @classmethod + def tearDownClass(cls): + User.objects.all().delete() + Question.objects.all().delete() + Quiz.objects.all().delete() + Course.objects.all().delete() + + settings.SERVER_POOL_PORT = 53579 + + cls.code_server_pool.stop() + cls.code_server_thread.join() + + super(YakshSeleniumTests, cls).tearDownClass() + + def test_load(self): + url = '%s%s' % (self.live_server_url, '/exam/login/') + quiz_name = "Yaksh Demo quiz" + selenium_test = SeleniumTest(url=url, quiz_name=quiz_name) + selenium_test.run_load_test(url=url, username='demo_student', password='demo_student') diff --git a/yaksh/live_server_tests/selenium_test.py b/yaksh/live_server_tests/selenium_test.py new file mode 100644 index 0000000..01ccc96 --- /dev/null +++ b/yaksh/live_server_tests/selenium_test.py @@ -0,0 +1,145 @@ +from selenium import webdriver +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import WebDriverException + +import multiprocessing +import argparse + +class SeleniumTest(): + def __init__(self, url, quiz_name): + self.driver = webdriver.Firefox() + self.quiz_name = quiz_name + self.url = url + + def run_load_test(self, url, username, password): + try: + self.driver.delete_all_cookies() + self.driver.get(self.url) + self.login(username, password) + self.open_quiz() + self.close_quiz() + self.logout() + self.driver.close() + except Exception as e: + with open("/tmp/yaksh_load_test_log.txt", "ab") as f: + f.write('Username: {0}\nError: {1}\n'.format(username, e)) + self.driver.close() + + def login(self, username, password): + # get the username, password and submit form elements + username_elem = self.driver.find_element_by_id("id_username") + password_elem = self.driver.find_element_by_id("id_password") + submit_login_elem = self.driver.find_element_by_css_selector('button.btn') + + # Type in the username, password and submit form + username_elem.send_keys(username) + password_elem.send_keys(password) + submit_login_elem.click() + + def submit_answer(self, question_label, answer, loop_count=1): + self.driver.implicitly_wait(2) + for count in range(loop_count): + self.driver.find_element_by_link_text(question_label).click() + submit_answer_elem = self.driver.find_element_by_id("check") + self.driver.execute_script('editor.setValue({})'.format(answer)) + submit_answer_elem.click() + + def test_c_question(self, question_label): + # Incorrect Answer + loop_count = 10 + answer = '\"int add(int a, int b, int c)\\n{return;}\"' + self.submit_answer(question_label, answer, loop_count) + + # Infinite Loop + loop_count = 3 + answer = '\"int add(int a, int b, int c)\\n{while(1){}}\"' + self.submit_answer(question_label, answer, loop_count) + + # Correct Answer + loop_count = 1 + answer = '\"int add(int a, int b, int c)\\n{return a + b + c;}\"' + self.submit_answer(question_label, answer, loop_count) + + def test_python_question(self, question_label): + # Incorrect Answer + loop_count = 10 + answer = '\"def is_palindrome(s):\\n return s\"' + self.submit_answer(question_label, answer, loop_count) + + # Infinite Loop + loop_count = 3 + answer = '\"while True:\\n pass"' + self.submit_answer(question_label, answer, loop_count) + + # Correct Answer + loop_count = 1 + answer = '\"def is_palindrome(s):\\n return s[::-1] == s\"' + self.submit_answer(question_label, answer, loop_count) + + def test_bash_question(self, question_label): + # Incorrect Answer + loop_count = 10 + answer = '\"#!/bin/bash\\nls\"' + self.submit_answer(question_label, answer, loop_count) + + # Infinite Loop + loop_count = 3 + answer = '\"#!/bin/bash\\nwhile [ 1 ]; do : ; done\"' + self.submit_answer(question_label, answer, loop_count) + + # Correct Answer + loop_count = 1 + answer = '\"#!/bin/bash\\ncat $1 | cut -d: -f2 | paste -d: $3 - $2\"' + self.submit_answer(question_label, answer, loop_count) + + def open_quiz(self): + # open quiz link + quiz_link_elem = self.driver.find_element_by_link_text(self.quiz_name).click() + + # Get page elements + start_exam_elem = WebDriverWait(self.driver, 5).until( + EC.presence_of_element_located((By.NAME, "start")) + ) + start_exam_elem.click() + + self.test_c_question(question_label=1) + self.test_python_question(question_label=3) + self.test_bash_question(question_label=2) + + def close_quiz(self): + quit_link_elem = WebDriverWait(self.driver, 5).until( + EC.presence_of_element_located((By.ID, "login_again")) + ) + quit_link_elem.click() + + def logout(self): + logout_link_elem = WebDriverWait(self.driver, 5).until( + EC.presence_of_element_located((By.ID, "logout")) + ) + logout_link_elem.click() + +def user_gen(url, ids): + return [(url, 'User%d'%x, 'User%d'%x) for x in ids] + +def wrap_run_load_test(args): + url = "http://yaksh.fossee.aero.iitb.ac.in/exam/" + selenium_test = SeleniumTest(url=url, quiz_name=quiz_name) + return selenium_test.run_load_test(*args) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('url', type=str, help="url of the website being tested") + parser.add_argument('start', type=int, help="Starting user id") + parser.add_argument("-n", "--number", type=int, default=10, help="number of users") + opts = parser.parse_args() + + quiz_name = "Demo quiz" + selenium_test = SeleniumTest(url=opts.url, quiz_name=quiz_name) + pool = multiprocessing.Pool(opts.number) + pool.map(wrap_run_load_test, user_gen(opts.url, range(opts.start, opts.start + opts.number))) + pool.close() + pool.join() + diff --git a/yaksh/tests/test_questions.json b/yaksh/tests/test_questions.json new file mode 100644 index 0000000..d617f22 --- /dev/null +++ b/yaksh/tests/test_questions.json @@ -0,0 +1,50 @@ +[ + { + "snippet": "", + "testcase": [ + { + "test_case": "assert is_palindrome(\"hello\") == False" + }, + { + "test_case": "assert is_palindrome(\"nitin\") == True" + } + ], + "points": 3.0, + "test_case_type": "standardtestcase", + "description": "Write a function <code>is_palindrome(arg)</code> which will take one string argument. Return true if the argument is palindrome & false otherwise.\r\n<br><br>\r\nFor Example:\r\n<br>\r\n<code>is_palindrome(\"Hello\")</code> should return <code>False</code>\r\n<br>\r\n<br><br>", + "language": "python", + "active": true, + "type": "code", + "summary": "Python, check palindrome (Code)" + }, + { + "snippet": "#!/bin/bash", + "testcase": [ + { + "test_case": "bash_files/sample.sh, bash_files/sample.args" + } + ], + "points": 1.0, + "test_case_type": "standardtestcase", + "description": "Write a bash script that takes exactly two arguments and returns the sum of the numbers", + "language": "bash", + "active": true, + "type": "code", + "summary": "Bash Question Concatenate Files(Code)" + }, + { + "snippet": "", + "testcase": [ + { + "test_case": "c_cpp_files/main2.c" + } + ], + "points": 1.0, + "test_case_type": "standardtestcase", + "description": "Write a program to add 3 nos", + "language": "c", + "active": true, + "type": "code", + "summary": "selenium test" + } +] |