Исходный код edutesting.bparallel.bparallel

# -*- coding: utf-8 -*-

import os
import re
import time
import datetime
import Queue

from multiprocessing import Process, Manager
from subprocess import call, Popen
from django.conf import settings


[документация]class ParallelRunner(object): u""" Класс для параллельного запуска тестов написанных на фреймворке behave. Параллельный запуск осущ. на уровне feature файлов. """ features_queue = Manager().JoinableQueue() test_result = Manager().list() def __init__(self, processes_amount, features_list, behave_options, spath, fpath): self.procs = processes_amount self.f_list = features_list self.behave_options = behave_options self.fpath = fpath self.spath = spath self.logs_path = os.path.join(settings.LOG_PATH, 'test_logs') if not os.path.exists(self.logs_path): os.mkdir(self.logs_path)
[документация] def call_behave(self, feature_path, port_number): """ Запускает behave для выполнения тестов в файле feature_path. :param feature_path: Полное имя feature файла :param port_number: Номер порта селениум сервера к которму будет подключаться webdriver. :return: Результат выполнения комманды. """ log_file = os.path.join(self.logs_path, feature_path.split('/')[-1]) log = open(log_file, 'w+') behave_command = ['behave', feature_path] + self.behave_options behave_command.append('-D port={}'.format(port_number)) res = call(behave_command, stdout=log) log.close() return 'passed' if res == 0 else 'failed'
[документация] def worker(self, port_number): """ Подпроцес который будет запускать behave для выполения тестов пока очередь self.features_queue не пуста. :param port_number: Номер порта селениум сервера к которму будет подключаться webdriver. """ while True: try: feature = self.features_queue.get_nowait() except Queue.Empty: break start_time = time.time() result = self.call_behave(feature, port_number) self.test_result.append(result) end_time = time.time() print "Scenario {0} is complite. Took: {1}. Feature is {2}".format( feature.split('/')[-1], str( datetime.timedelta(seconds=end_time - start_time)), result)
[документация] def run(self): u""" Метод для запуска процессов. Запускает кол-во процессов равное self.procs и после их завершения выводит отчет. :return: Возвращает 0 если все feature файлы успешно выполнены иначе 1. """ for f in self.get_feature_files(): self.features_queue.put(f) main_start_time = time.time() print "Begin scenarios execution at {0}".format( time.strftime('%H:%M:%S')) workers = [] port_number = 3333 sel_servers = [] for i in xrange(0, self.procs): sel_servers.append(self.set_up_selenium_servers( str(port_number+i))) time.sleep(1.5) # Даем время для инициализации селениум сервера. p = Process(target=self.worker, args=(port_number+i,)) workers.append(p) p.start() [i.join() for i in workers] main_end_time = time.time() print "End scenarios execution at {0}".format( time.strftime('%H:%M:%S')) result = main_end_time - main_start_time print "Took: " + str(datetime.timedelta(seconds=result)) for p in sel_servers: p.kill() return_code = 0 if any([r == 'failed' for r in self.test_result]): return_code = 1 return return_code
[документация] def set_up_selenium_servers(self, port_number): """ Запуск селениум сервера в "бесшумном" режиме (вывод будет осущ. на виртуальный дисплей). """ null = open(os.devnull, 'w') fpath = '-Dwebdriver.firefox.bin="{}/firefox-bin"'.format(self.fpath) spath = '{0}/selenium-server-standalone-2.45.0.jar'.format(self.spath) port = '-port {}'.format(port_number) selenium_cmd = ' '.join( ['xvfb-run -s "-screen 0, 1280x1024x8" --listen-tcp -a java -jar', spath, port, fpath]) return Popen(selenium_cmd, shell=True, stdout=null)
[документация] def get_feature_files(self): """ На основе self.f_list формируем список features файлов для выполнения. self.f_list список который может содержать как имена feature файлов, так и директории с ними. :return: Список с полными именами feature файлов. """ features_files = [] base_dir = os.getcwd() for f in self.f_list: if not os.path.isabs(f): f = os.path.join(base_dir, f) if os.path.isfile(f): features_files.append(f) else: pattern = re.compile("^[\w.]+.feature$") files = os.listdir(f) features_files += ( [os.path.join(f, i) for i in files if pattern.match(i)]) features_files.sort() return features_files