Beispiel #1
0
 def __init__(self):
     self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     self._group = Group()
     self._send_buffer = Queue()
     self._recv_buffer = Queue()
Beispiel #2
0
def generate_report(opts):
    logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
    group = Group() if not FAILED_IMPORT else ''

    # START OF CUSTOMIZE REPORT
    # URL or filepath of your company logo
    logo = opts.logo

    # Ignores following library keywords in metrics report
    ignore_library = IGNORE_LIBRARIES
    if opts.ignore:
        ignore_library.extend(opts.ignore)

    # Ignores following type keywords in metrics report
    ignore_type = IGNORE_TYPES
    if opts.ignoretype:
        ignore_type.extend(opts.ignoretype)

    # END OF CUSTOMIZE REPORT
    # Report to support file location as arguments
    # Source Code Contributed By : Ruud Prijs
    # input directory
    path = os.path.abspath(os.path.expanduser(opts.path))

    # output.xml files
    output_names = []
    for curr_name in opts.output.split(","):
        curr_path = os.path.join(path, curr_name)
        output_names.append(curr_path)

    # log.html file
    log_name = opts.log_name

    # copy the list of output_names onto the one of required_files; the latter may (in the future)
    # contain files that should not be processed as output_names
    required_files = list(output_names)
    missing_files = [
        filename for filename in required_files if not os.path.exists(filename)
    ]
    if missing_files:
        # We have files missing.
        exit("output.xml file is missing: {}".format(", ".join(missing_files)))

    mt_time = datetime.now().strftime('%Y%m%d-%H%M%S')

    # Output result file location
    if opts.metrics_report_name:
        result_file_name = opts.metrics_report_name
    else:
        result_file_name = 'metrics-' + mt_time + '.html'
    result_file = os.path.join(path, result_file_name)

    # Read output.xml file
    result = ExecutionResult(*output_names)
    result.configure(stat_config={
        'suite_stat_level': 2,
        'tag_stat_combine': 'tagANDanother'
    })

    logging.info("Converting .xml to .html file. This may take few minutes...")

    head_content = """
    <!doctype html><html lang="en">
    <head>
        <link rel="shortcut icon" href="https://png.icons8.com/windows/50/000000/bot.png" type="image/x-icon" />
        <title>RF Metrics</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet"/>
        <link href="https://cdn.datatables.net/buttons/1.5.2/css/buttons.dataTables.min.css" rel="stylesheet"/>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

       <script src="https://code.jquery.com/jquery-3.3.1.js" type="text/javascript"></script>

        <!-- Bootstrap core Googleccharts -->
       <script src="https://www.gstatic.com/charts/loader.js" type="text/javascript"></script>
       <script type="text/javascript">google.charts.load('current', {packages: ['corechart']});</script>

       <!-- Bootstrap core Datatable-->
        <script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/dataTables.buttons.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.flash.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.html5.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.print.min.js" type="text/javascript"></script>

        <style>
            body {
                font-family: -apple-system,sans-serif;
            }

            .sidenav {
                height: 100%;
                width: 220px;
                position: fixed;
                z-index: 1;
                top: 0;
                left: 0;
                background-color: white;
                overflow-x: hidden;
                border-style: ridge;
            }

            .sidenav a {
                padding: 12px 10px 8px 12px;
                text-decoration: none;
                font-size: 18px;
                color: Black;
                display: block;
            }

            .main {
                padding-top: 10px;
            }

            @media screen and (max-height: 450px) {
                .sidenav {padding-top: 15px;}
                .sidenav a {font-size: 18px;}
            }

            .tile {
                width: 100%;
                float: left;
                margin: 0px;
                list-style: none;
                font-size: 30px;
                color: #FFF;
                -moz-border-radius: 5px;
                -webkit-border-radius: 5px;
                margin-bottom: 5px;
                position: relative;
                text-align: center;
                color: white!important;
            }

            .tile.tile-fail {
                background: #f44336!important;
            }
            .tile.tile-pass {
                background: #4CAF50!important;
            }
            .tile.tile-info {
                background: #009688!important;
            }
            .tile.tile-head {
                background: #616161!important;
            }
            .dt-buttons {
                margin-left: 5px;
            }
            
            .loader {
                position: fixed;
                left: 0px;
                top: 0px;
                width: 100%;
                height: 100%;
                z-index: 9999;
                background: url('https://www.downgraf.com/wp-content/uploads/2014/09/02-loading-blossom-2x.gif') 
                    50% 50% no-repeat rgb(249,249,249);
            }

        </style>
    </head>
    """

    soup = BeautifulSoup(head_content, "html.parser")
    body = soup.new_tag('body')
    soup.insert(20, body)
    icons_txt = """
    <div class="loader"></div>
    <div class="sidenav">
        <a> <img src="%s" style="height:20vh;max-width:98%%;"/> </a>
        <a class="tablink" href="#" id="defaultOpen" onclick="openPage('dashboard', this, 'orange')"><i class="fa fa-dashboard"></i> Dashboard</a>
        <a class="tablink" href="#" onclick="openPage('suiteMetrics', this, 'orange'); executeDataTable('#sm',5)"><i class="fa fa-th-large"></i> Suite Metrics</a>
        <a class="tablink" href="#" onclick="openPage('testMetrics', this, 'orange'); executeDataTable('#tm',3)"><i class="fa fa-list-alt"></i> Test Metrics</a>
        <a class="tablink" href="#" onclick="openPage('keywordMetrics', this, 'orange'); executeDataTable('#km',3)"><i class="fa fa-table"></i> Keyword Metrics</a>
        <a class="tablink" href="#" onclick="openPage('log', this, 'orange');"><i class="fa fa-wpforms"></i> Logs</a>
        <a class="tablink" href="#" onclick="openPage('statistics', this, 'orange');"><i class="fa fa-envelope-o"></i> Email</a>
    </div>
    """ % logo

    body.append(BeautifulSoup(icons_txt, 'html.parser'))

    page_content_div = soup.new_tag('div')
    page_content_div["class"] = "main col-md-9 ml-sm-auto col-lg-10 px-4"
    body.insert(50, page_content_div)

    logging.info("1 of 4: Capturing dashboard content...")
    test_stats = TestStats()
    result.visit(test_stats)

    total_suite = test_stats.total_suite
    passed_suite = test_stats.passed_suite
    failed_suite = test_stats.failed_suite

    suitepp = round(passed_suite * 100.0 / total_suite, 1)
    suitefp = round(failed_suite * 100.0 / total_suite, 1)
    elapsedtime = datetime(
        1970, 1, 1) + timedelta(milliseconds=result.suite.elapsedtime)
    elapsedtime = elapsedtime.strftime("%X")
    my_results = result.generated_by_robot

    if my_results:
        generator = "Robot"
    else:
        generator = "Rebot"

    stats = result.statistics
    total = stats.total.all.total
    passed = stats.total.all.passed
    failed = stats.total.all.failed

    testpp = round(passed * 100.0 / total, 1)
    testfp = round(failed * 100.0 / total, 1)

    kw_stats = KeywordStats(ignore_library, ignore_type)
    result.visit(kw_stats)

    total_keywords = kw_stats.total_keywords
    passed_keywords = kw_stats.passed_keywords
    failed_keywords = kw_stats.failed_keywords

    # Handling ZeroDivisionError exception when no keywords are found
    if total_keywords > 0:
        kwpp = round(passed_keywords * 100.0 / total_keywords, 1)
        kwfp = round(failed_keywords * 100.0 / total_keywords, 1)
    else:
        kwpp = 0
        kwfp = 0

    dashboard_content = """
    <div class="tabcontent" id="dashboard">
        <div id="stats_screenshot_area">
        <div class="d-flex flex-column flex-md-row align-items-center p-1 mb-3 bg-light 
            border-bottom shadow-sm">
            <h5 class="my-0 mr-md-auto font-weight-normal"><i class="fa fa-dashboard"></i> Dashboard</h5>
            <nav class="my-2 my-md-0 mr-md-3" style="color:red">
            <a class="p-2"><b style="color:black;">Execution Time: </b>%s h</a>
            <a class="p-2"><b style="color:black;cursor: pointer;" data-toggle="tooltip" title=".xml file is created by">Generated By: </b>%s</a>
            </nav>                  
        </div>

        <div class="row">
            <div class="col-md-3"  onclick="openPage('suiteMetrics', this, '')" data-toggle="tooltip" 
                title="Click to view Suite metrics" style="cursor: pointer;">                        
                <a class="tile tile-head">
                    Suite
                    <p style="font-size:12px">Statistics</p>
                </a>
            </div>
            <div class="col-md-3">                        
                <a class="tile tile-info">
                    %s
                    <p style="font-size:12px">Total</p>
                </a>
            </div>
            <div class="col-md-3">                        
                <a class="tile tile-pass">
                    %s
                    <p style="font-size:12px">Pass</p>
                </a>
            </div>						
            <div class="col-md-3">                        
                <a class="tile tile-fail">
                    %s
                    <p style="font-size:12px">Fail</p>
                </a>
            </div>
        </div>

        <div class="row">
            <div class="col-md-3"  onclick="openPage('testMetrics', this, '')" data-toggle="tooltip" 
            title="Click to view Test metrics" style="cursor: pointer;">                        
                <a class="tile tile-head">
                    Test
                    <p style="font-size:12px">Statistics</p>
                </a>
            </div>
            <div class="col-md-3">                        
                <a class="tile tile-info">
                    %s
                    <p style="font-size:12px">Total</p>
                </a>
            </div>
            <div class="col-md-3">                        
                <a class="tile tile-pass">
                    %s
                    <p style="font-size:12px">Pass</p>
                </a>
            </div>						
            <div class="col-md-3">                        
                <a class="tile tile-fail">
                    %s
                    <p style="font-size:12px">Fail</p>
                </a>
            </div>
        </div>

        <div class="row">
            <div class="col-md-3"  onclick="openPage('keywordMetrics', this, '')" data-toggle="tooltip" 
                title="Click to view Keyword metrics" style="cursor: pointer;">                        
                <a class="tile tile-head">
                    Keyword
                    <p style="font-size:12px">Statistics</p>
                </a>
            </div>
            <div class="col-md-3">                        
                <a class="tile tile-info">
                    %s
                    <p style="font-size:12px">Total</p>
                </a>
            </div>
            <div class="col-md-3">                        
                <a class="tile tile-pass">
                    %s
                    <p style="font-size:12px">Pass</p>
                </a>
            </div>						
            <div class="col-md-3">                        
                <a class="tile tile-fail">
                    %s
                    <p style="font-size:12px">Fail</p>
                </a>
            </div>
        </div>

        <hr></hr>
        <div class="row">
            <div class="col-md-4" style="background-color:white;height:280px;width:auto;border:groove;">
                <span style="font-weight:bold">Suite Status:</span>
                <div id="suiteChartID" style="height:250px;width:auto;"></div>
            </div>
            <div class="col-md-4" style="background-color:white;height:280px;width:auto;border:groove;">
                <span style="font-weight:bold">Test Status:</span>
                <div id="testChartID" style="height:250px;width:auto;"></div>
            </div>
            <div class="col-md-4" style="background-color:white;height:280px;width:auto;border:groove;">
                <span style="font-weight:bold">Keyword Status:</span>
                <div id="keywordChartID" style="height:250px;width:auto;"></div>
            </div>
        </div>
        </div>
        <hr></hr>
        <div class="row">
            <div class="col-md-12" style="background-color:white;height:450px;width:auto;border:groove;">
                <span style="font-weight:bold">Top 10 Suite Performance(sec):</span>
                <div id="suiteBarID" style="height:400px;width:auto;"></div>
            </div>
            <div class="col-md-12" style="background-color:white;height:450px;width:auto;border:groove;">
                <span style="font-weight:bold">Top 10 Test Performance(sec):</span>
                <div id="testsBarID" style="height:400px;width:auto;"></div>
            </div>
            <div class="col-md-12" style="background-color:white;height:450px;width:auto;border:groove;">
                <span style="font-weight:bold">Top 10 Keywords Performance(sec):</span>
                <div id="keywordsBarID" style="height:400px;width:auto;"></div>
            </div>
        </div>
        <div class="row">
        <div class="col-md-12" style="height:25px;width:auto;">
            <p class="text-muted" style="text-align:center;font-size:9px">
                <a target="_blank" href="https://github.com/adiralashiva8/robotframework-metrics"> robotframework-metrics </a>
            </p>
        </div>
        </div>

       <script>
        window.onload = function(){
        executeDataTable('#sm',5);
        executeDataTable('#tm',3);
        executeDataTable('#km',3);
        createPieChart(%s,%s,'suiteChartID','Suite Status:');
        createBarGraph('#sm',0,5,10,'suiteBarID','Elapsed Time (s) ','Suite');	
        createPieChart(%s,%s,'testChartID','Tests Status:');	
        createBarGraph('#tm',1,3,10,'testsBarID','Elapsed Time (s) ','Test'); 
        createPieChart(%s,%s,'keywordChartID','Keywords Status:');
        createBarGraph('#km',1,3,10,'keywordsBarID','Elapsed Time (s) ','Keyword');
        };
       </script>
       <script>
    function openInNewTab(url,element_id) {
      var element_id= element_id;
      var win = window.open(url, '_blank');
      win.focus();
      $('body').scrollTo(element_id); 
    }
    </script>
      </div>
    """ % (elapsedtime, generator, total_suite, passed_suite, failed_suite,
           total, passed, failed, total_keywords, passed_keywords,
           failed_keywords, passed_suite, failed_suite, passed, failed,
           passed_keywords, failed_keywords)

    page_content_div.append(BeautifulSoup(dashboard_content, 'html.parser'))

    ### ============================ END OF DASHBOARD ============================================ ####
    logging.info("2 of 4: Capturing suite metrics...")
    ### ============================ START OF SUITE METRICS ======================================= ####

    # Tests div
    suite_div = soup.new_tag('div')
    suite_div["id"] = "suiteMetrics"
    suite_div["class"] = "tabcontent"
    page_content_div.insert(50, suite_div)

    test_icon_txt = """
                    <h4><b><i class="fa fa-table"></i> Suite Metrics</b></h4>
                    <hr></hr>
                    """
    suite_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # Create table tag
    table = soup.new_tag('table')
    table["id"] = "sm"
    table["class"] = "table table-striped table-bordered"
    suite_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Suite Name"
    tr.insert(0, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Total"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Pass"
    tr.insert(3, th)

    th = soup.new_tag('th')
    th.string = "Fail"
    tr.insert(4, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(5, th)

    suite_tbody = soup.new_tag('tbody')
    table.insert(11, suite_tbody)

    # GET SUITE METRICS
    if group:
        group.spawn(result.visit, SuiteResults(soup, suite_tbody, log_name))
    else:
        result.visit(SuiteResults(soup, suite_tbody, log_name))

    test_icon_txt = """
    <div class="row">
    <div class="col-md-12" style="height:25px;width:auto;">
    </div>
    </div>
    """
    suite_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    ### ============================ END OF SUITE METRICS ============================================ ####
    logging.info("3 of 4: Capturing test metrics...")
    ### ============================ START OF TEST METRICS ======================================= ####

    # Tests div
    tm_div = soup.new_tag('div')
    tm_div["id"] = "testMetrics"
    tm_div["class"] = "tabcontent"
    page_content_div.insert(100, tm_div)

    test_icon_txt = """
    <h4><b><i class="fa fa-table"></i> Test Metrics</b></h4>
    <hr></hr>
    """
    tm_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # Create table tag
    table = soup.new_tag('table')
    table["id"] = "tm"
    table["class"] = "table table-striped table-bordered"
    tm_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Suite Name"
    tr.insert(0, th)

    th = soup.new_tag('th')
    th.string = "Test Case"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(3, th)

    th = soup.new_tag('th')
    th.string = "Error Message"
    tr.insert(4, th)

    test_tbody = soup.new_tag('tbody')
    table.insert(11, test_tbody)

    # GET TEST METRICS
    if group:
        group.spawn(result.visit, TestResults(soup, test_tbody, log_name))
    else:
        result.visit(TestResults(soup, test_tbody, log_name))

    test_icon_txt = """
    <div class="row">
    <div class="col-md-12" style="height:25px;width:auto;">
    </div>
    </div>
    """
    tm_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    ### ============================ END OF TEST METRICS ============================================ ####
    logging.info("4 of 4: Capturing keyword metrics...")
    ### ============================ START OF KEYWORD METRICS ======================================= ####

    # Keywords div
    km_div = soup.new_tag('div')
    km_div["id"] = "keywordMetrics"
    km_div["class"] = "tabcontent"
    page_content_div.insert(150, km_div)

    keyword_icon_txt = """
    <h4><b><i class="fa fa-table"></i> Keyword Metrics</b></h4>
      <hr></hr>
    """
    km_div.append(BeautifulSoup(keyword_icon_txt, 'html.parser'))

    # Create table tag
    # <table id="myTable">
    table = soup.new_tag('table')
    table["id"] = "km"
    table["class"] = "table table-striped table-bordered"
    km_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Test Case"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Keyword"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(3, th)

    kw_tbody = soup.new_tag('tbody')
    table.insert(1, kw_tbody)

    if group:
        group.spawn(
            result.visit,
            KeywordResults(soup, kw_tbody, ignore_library, ignore_type))
        group.join()
    else:
        result.visit(
            KeywordResults(soup, kw_tbody, ignore_library, ignore_type))

    test_icon_txt = """
    <div class="row">
    <div class="col-md-12" style="height:25px;width:auto;">
    </div>
    </div>
    """
    km_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))
    # END OF KEYWORD METRICS

    # START OF LOGS

    # Logs div
    log_div = soup.new_tag('div')
    log_div["id"] = "log"
    log_div["class"] = "tabcontent"
    page_content_div.insert(200, log_div)

    test_icon_txt = """
        <p style="text-align:right">** <b>Report.html</b> and <b>Log.html</b> need to be in current folder in 
        order to display here</p>
      <div class="embed-responsive embed-responsive-4by3">
        <iframe class="embed-responsive-item" src=%s></iframe>
      </div>
    """ % log_name
    log_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # END OF LOGS

    # EMAIL STATISTICS
    # Statistics div
    statisitcs_div = soup.new_tag('div')
    statisitcs_div["id"] = "statistics"
    statisitcs_div["class"] = "tabcontent"
    page_content_div.insert(300, statisitcs_div)

    emailStatistics = """
    <h4><b><i class="fa fa-envelope-o"></i> Email Statistics</b></h4>
    <hr></hr>
    <button id="create" class="btn btn-primary active inner" role="button" onclick="this.style.visibility= 'hidden';"><i class="fa fa-cogs"></i> Generate Statistics Email</button>
    <a download="message.eml" class="btn btn-primary active inner" role="button" id="downloadlink" style="display: none; width: 300px;"><i class="fa fa-download"></i> Click Here To Download Email</a>   
<textarea id="textbox" class="col-md-12" style="height: 400px; padding:1em;">
To: [email protected]
Subject: Automation Execution Status
X-Unsent: 1
Content-Type: text/html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test Email Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0 " />
    <style>
        body {
            background-color:#F2F2F2; 
        }
        body, html, table {
            font-family: Courier New, Arial, sans-serif;
            font-size: 1em; 
        }
        .pastdue { color: crimson; }
        table {
            padding: 5px;
            margin-left: 30px;
            width: 800px;
        }
        thead {
            text-align: center;
            font-size: 1.1em;        
            background-color: #B0C4DE;
            font-weight: bold;
            color: #2D2C2C;
        }
        tbody {
            text-align: center;
        }
        th {
            width: 25%;
            word-wrap:break-word;
        }
    </style>
</head>
<body>
    <p>Hi Team,</p>
    <p>Following are the last build execution status</p>
    <p></p>
    <table>
        <tbody>
            <tr>
                <td style="text-align:left; padding-left:5px;color:#0b6690;">
                    <h2>Test Automation Report</h2>
                </td>
                <td style="text-align:right; padding-right:10px;color:#0b6690;">
                    <h3>Duration: elapsed_time</h3>
                </td>
            </tr>
        </tbody>
    </table>
    <table>
        <tr>
            <td></td>
        </tr>
    </table>
    <table>
        <tbody>
        <tr>
            <td style="background-color:#616161; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">Suite</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Statistics</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#009688; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">suite_total</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Total</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#4CAF50; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">suite_pass</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Pass</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#f44336; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">suite_fail</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Fail</td>
                        </tr>
                    </tbody>
                </table>
            </td>
        </tr>
        <tr>
            <td style="background-color:#616161; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">Test</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Statistics</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#009688; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">test_total</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Total</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#4CAF50; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">test_pass</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Pass</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#f44336; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">test_fail</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Fail</td>
                        </tr>
                    </tbody>
                </table>
            </td>
        </tr>
        <tr>
            <td style="background-color:#616161; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">Keyword</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Statistics</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#009688; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">keyword_total</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Total</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#4CAF50; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">keyword_pass</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Pass</td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="background-color:#f44336; color:white; width:25%">
                <table style="width:100%;">
                    <tbody>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 30px;">keyword_fail</td>
                        </tr>
                        <tr>
                            <td style="text-align:center; color:white;font-size: 12px;">Fail</td>
                        </tr>
                    </tbody>
                </table>
            </td>
        </tr>
        </tbody>
    </table>
    <table>
        <tr>
            <td></td>
        </tr>
    </table>
    <table>
        <tbody>
            <tr>
                <td style="width:33%;color:#0b6690;"><h3>Suite Status</h3></td>
                <td style="width:33%;color:#0b6690;"><h3>Test Status</h3></td>
                <td style="width:33%;color:#0b6690;"><h3>Keyword Status</h3></td>
            </tr>
            <tr>
                <td>
                    <img src='https://chart.googleapis.com/chart?cht=p3&chd=t:suite-pass-perc,suite-fail-perc&chs=250x200&chco=3BB032|bc2d29&chdl=suite-pass-perc-pass|suite-fail-perc-fail'/>
                </td>
                <td>
                    <img src='https://chart.googleapis.com/chart?cht=p3&chd=t:test-pass-perc,test-fail-perc&chs=250x200&chco=3BB032|bc2d29&chdl=test-pass-perc-pass|test-fail-perc-fail'/>
                </td>
                <td>
                    <img src='https://chart.googleapis.com/chart?cht=p3&chd=t:keyword-pass-perc,keyword-fail-perc&chs=250x200&chco=3BB032|bc2d29&chdl=keyword-pass-perc-pass|keyword-fail-perc-fail'/>
                </td>
            </tr>
        </tbody>
    </table>
    <p>Please refer RF Metrics report for detailed statistics.<p>
    <strong>Team QA</strong>
</body></html></textarea>

    """

    emailStatistics = emailStatistics.replace("suite_total", str(total_suite))
    emailStatistics = emailStatistics.replace("suite_pass", str(passed_suite))
    emailStatistics = emailStatistics.replace("suite_fail", str(failed_suite))
    emailStatistics = emailStatistics.replace("test_total", str(total))
    emailStatistics = emailStatistics.replace("test_pass", str(passed))
    emailStatistics = emailStatistics.replace("test_fail", str(failed))
    emailStatistics = emailStatistics.replace("keyword_total",
                                              str(total_keywords))
    emailStatistics = emailStatistics.replace("keyword_pass",
                                              str(passed_keywords))
    emailStatistics = emailStatistics.replace("keyword_fail",
                                              str(failed_keywords))
    emailStatistics = emailStatistics.replace("elapsed_time", str(elapsedtime))
    emailStatistics = emailStatistics.replace("suite-pass-perc", str(suitepp))
    emailStatistics = emailStatistics.replace("suite-fail-perc", str(suitefp))
    emailStatistics = emailStatistics.replace("test-pass-perc", str(testpp))
    emailStatistics = emailStatistics.replace("test-fail-perc", str(testfp))
    emailStatistics = emailStatistics.replace("keyword-pass-perc", str(kwpp))
    emailStatistics = emailStatistics.replace("keyword-fail-perc", str(kwfp))

    statisitcs_div.append(BeautifulSoup(emailStatistics, 'html.parser'))

    # END OF EMAIL STATISTICS
    script_text = """
        <script>
            (function () {
            var textFile = null,
              makeTextFile = function (text) {
                var data = new Blob([text], {type: 'text/plain'});
                if (textFile !== null) {
                  window.URL.revokeObjectURL(textFile);
                }
                textFile = window.URL.createObjectURL(data);
                return textFile;
              };

              var create = document.getElementById('create'),
                textbox = document.getElementById('textbox');
              create.addEventListener('click', function () {
                var link = document.getElementById('downloadlink');
                link.href = makeTextFile(textbox.value);
                link.style.display = 'block';
              }, false);
            })();
        </script>
        <script>
            function createPieChart(passed_count,failed_count,ChartID,ChartName){
            var status = [];
            status.push(['Status', 'Percentage']);
            status.push(['PASS',parseInt(passed_count)],['FAIL',parseInt(failed_count)]);
            var data = google.visualization.arrayToDataTable(status);

            var options = {
            pieHole: 0.6,
            legend: 'none',
            chartArea: {width: "95%",height: "90%"},
            colors: ['green', 'red'],
            };

            var chart = new google.visualization.PieChart(document.getElementById(ChartID));
            chart.draw(data, options);
        }
        </script>
        <script>
           function createBarGraph(tableID,keyword_column,time_column,limit,ChartID,Label,type){
            var status = [];
            css_selector_locator = tableID + ' tbody >tr'
            var rows = $(css_selector_locator);
            var columns;
            var myColors = [
                '#4F81BC',
                '#C0504E',
                '#9BBB58',
                '#24BEAA',
                '#8064A1',
                '#4AACC5',
                '#F79647',
                '#815E86',
                '#76A032',
                '#34558B'
            ];
            status.push([type, Label,{ role: 'annotation'}, {role: 'style'}]);
            for (var i = 0; i < rows.length; i++) {
                if (i == Number(limit)){
                    break;
                }
                //status = [];
                name_value = $(rows[i]).find('td'); 

                time=($(name_value[Number(time_column)]).html()).trim();
                keyword=($(name_value[Number(keyword_column)]).html()).trim();
                status.push([keyword,parseFloat(time),parseFloat(time),myColors[i]]);
              }
              var data = google.visualization.arrayToDataTable(status);

              var options = {
                legend: 'none',
                chartArea: {width: "92%",height: "75%"},
                bar: {
                    groupWidth: '90%'
                },
                annotations: {
                    alwaysOutside: true,
                    textStyle: {
                    fontName: 'Comic Sans MS',
                    fontSize: 13,
                    bold: true,
                    italic: true,
                    color: "black",     // The color of the text.
                    },
                },
                hAxis: {
                    textStyle: {
                        fontName: 'Arial',
                        fontSize: 10,
                    }
                },
                vAxis: {
                    gridlines: { count: 10 },
                    textStyle: {                    
                        fontName: 'Comic Sans MS',
                        fontSize: 10,
                    }
                },
              };  

                // Instantiate and draw the chart.
                var chart = new google.visualization.ColumnChart(document.getElementById(ChartID));
                chart.draw(data, options);
             }

        </script>

     <script>
      function executeDataTable(tabname,sortCol) {
        var fileTitle;
        switch(tabname) {
            case "#sm":
                fileTitle = "SuiteMetrics";
                break;
            case "#tm":
                fileTitle =  "TestMetrics";
                break;
            case "#km":
                fileTitle =  "KeywordMetrics";
                break;
            default:
                fileTitle =  "metrics";
        }

        $(tabname).DataTable(
            {
                retrieve: true,
                "order": [[ Number(sortCol), "desc" ]],
                dom: 'l<".margin" B>frtip',
                buttons: [
                    'copy',
                    {
                        extend: 'csv',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        title : '',
                    },
                    {
                        extend: 'excel',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        title : '',
                    },
                    {
                        extend: 'pdf',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        title : '',
                    },
                    {
                        extend: 'print',
                        title : '',
                    },
                ],
            } 
        );
    }
     </script>
     <script>
      function openPage(pageName,elmnt,color) {
        var i, tabcontent, tablinks;
        tabcontent = document.getElementsByClassName("tabcontent");
        for (i = 0; i < tabcontent.length; i++) {
            tabcontent[i].style.display = "none";
        }
        tablinks = document.getElementsByClassName("tablink");
        for (i = 0; i < tablinks.length; i++) {
            tablinks[i].style.backgroundColor = "";
        }
        document.getElementById(pageName).style.display = "block";
        elmnt.style.backgroundColor = color;

    }
    // Get the element with id="defaultOpen" and click on it
    document.getElementById("defaultOpen").click();
     </script>
     <script>
     // Get the element with id="defaultOpen" and click on it
    document.getElementById("defaultOpen").click();
     </script>
     <script>
    $(window).on('load',function(){$('.loader').fadeOut();});
    </script>
    """

    body.append(BeautifulSoup(script_text, 'html.parser'))

    # WRITE TO RF_METRICS_REPORT.HTML

    # Write output as html file
    with open(result_file, 'w') as outfile:
        outfile.write(soup.prettify())

    logging.info(
        "Results file created successfully and can be found at {}".format(
            result_file))
Beispiel #3
0
#coding:utf-8
'''
    Created on 2016年7月25日
    @author: xiongqiao
    @attention:
'''

# 组是一个运行中greetlet的集合,集合中的greetlet像一个组一样被共同管理和调度。
# 它也兼饰了像multiporicessing库那样的平行调度器的角色。

import gevent
from gevent.pool import Group


def talk(msg):
    n = 3
    while 0 < n:
        print(msg)
        n -= 1


g1 = gevent.spawn(talk, 'bar')
g2 = gevent.spawn(talk, 'foo')
g3 = gevent.spawn(talk, 'fizz')
group = Group()
group.add(g1)
group.add(g2)
group.join()
group.add(g3)
group.join()
Beispiel #4
0
from gevent import monkey
import gevent
from gevent.pool import Group

monkey.patch_socket()


def f(n):
    for i in range(n):
        print gevent.getcurrent(), i
        gevent.sleep(0)


# g1 = gevent.spawn(f, 5)
# g2 = gevent.spawn(f, 5)
# g3 = gevent.spawn(f, 5)
# g1.join()
# g2.join()
# g3.join()
# gevent.joinall([g1, g2 ,g3])

g1 = gevent.spawn(f, 2)
g = Group()
g.add(g1)
g.join()
# x = g.map(f, xrange(2))

# print x

if __name__ == '__main__':
    pass
Beispiel #5
0
import gevent
from gevent import getcurrent
from gevent.pool import Group
"""
groups can be used to manage and schedule tasks together
mirror the python multiprocessing by working as a parallel dispatcher
"""
group = Group()


def hello_from(n):
    print('Size of group %s' % len(group))
    print('Hello from Greenlet %s' % id(getcurrent()))


group.map(hello_from, range(3))


def intensive(n):
    gevent.sleep(3 - n)
    return 'task', n


print('Ordered')

ogroup = Group()
#imap send the iterable item by item preserving the order
for i in ogroup.imap(intensive, range(3)):
    print(i)

print('Unordered')
    import simplejson as json
except ImportError:
    try:
        import json
    except ImportError:
        try:
            from django.utils import simplejson as json
        except ImportError:
            raise ImportError('You need something for json encoding! simplejson, Django, or Python >= 2.6')
try:
    from gevent import monkey
    from gevent.pool import Group
    import atexit
    monkey.patch_socket()
    monkey.patch_ssl()
    async_group = Group()
    HAS_GEVENT = True

    @atexit.register
    def _cleanup():
        async_group.join()
except ImportError:
    HAS_GEVENT = False

__all__ = ('StatHat', 'StatHatEZ', 'StatHatError',
           'ez_count', 'ez_value', 'classic_count', 'classic_value')

# We like security. :)
STATHAT_ENDPOINT = 'https://api.stathat.com'

 def spawn_imap_unordered(self):
     igroup = Group()
     result = []
     with tracer.start_active_span('test'):
         for i in igroup.imap_unordered(self.make_http_call, range(3)):
             result.append(i)
Beispiel #8
0
 def __init__(self, host, port):
     super().__init__(host, port)
     self.server = rpc.Server(self.host, self.port)
     self.slave = {}
     self.greenlet = Group()
     self.greenlet.spawn(self.slave_listener)
def generate_report(opts):
    writer = sys.stdout.write

    group = Group() if not FAILED_IMPORT else ''

    # ======================== START OF CUSTOMIZE REPORT ================================== #

    # URL or filepath of your company logo
    logo = opts.logo

    # Ignores following library keywords in metrics report
    ignore_library = IGNORE_LIBRARIES
    if opts.ignore:
        ignore_library.extend(opts.ignore)

    # Ignores following type keywords in metrics report
    ignore_type = IGNORE_TYPES
    if opts.ignoretype:
        ignore_type.extend(opts.ignoretype)

    # ======================== END OF CUSTOMIZE REPORT ================================== #

    # Report to support file location as arguments
    # Source Code Contributed By : Ruud Prijs

    # input directory
    path = os.path.abspath(os.path.expanduser(opts.path))

    # output.xml file
    output_name = os.path.join(path, opts.output)

    # report.html file
    report_name = opts.report_name

    # log.html file
    log_name = opts.log_name

    required_files = (
        output_name,
        # report_name,
        # log_name,
    )
    missing_files = [
        filename for filename in required_files if not os.path.exists(filename)
    ]
    if missing_files:
        # We have files missing.
        # writer("The following files are missing: {}\n".format(", ".join(missing_files)))
        writer("output.xml file is missing: {}".format(
            ", ".join(missing_files)))
        exit(1)

    # email status
    send_email = opts.email

    mtTime = datetime.now().strftime('%Y%m%d-%H%M%S')
    # Output result file location
    result_file_name = 'metrics-' + mtTime + '.html'
    result_file = os.path.join(path, result_file_name)

    # Read output.xml file
    result = ExecutionResult(output_name)
    result.configure(stat_config={
        'suite_stat_level': 2,
        'tag_stat_combine': 'tagANDanother'
    })

    writer("Converting .xml to .html file. This may take few minutes...")

    # ======= START OF EMAIL SETUP CONTENT ====== #
    if send_email:
        server = smtplib.SMTP('smtp.gmail.com:587')

    msg = MIMEMultipart()
    msg['Subject'] = 'Robotframework Automation Status'

    sender = opts.sender

    recipients = opts.to.split(',') if opts.to else ''

    ccrecipients = opts.cc.split(',') if opts.cc else ''

    msg['From'] = sender
    msg['To'] = ", ".join(recipients)
    msg['Cc'] = ", ".join(ccrecipients)
    password = opts.pwd
    msg.add_header('Content-Type', 'text/html')

    # ======= END OF EMAIL SETUP CONTENT ====== #

    head_content = """
    <!doctype html>
    <html lang="en">
    
    <head>
        <link rel="shortcut icon" href="https://png.icons8.com/windows/50/000000/bot.png" type="image/x-icon" />
        <title>RF Metrics Report</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    
        <link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet"/>
        <link href="https://cdn.datatables.net/buttons/1.5.2/css/buttons.dataTables.min.css" rel="stylesheet"/>
    
        <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
        
       <script src="https://code.jquery.com/jquery-3.3.1.js" type="text/javascript"></script>
       
        <!-- Bootstrap core Googleccharts -->
       <script src="https://www.gstatic.com/charts/loader.js" type="text/javascript"></script>
       <script type="text/javascript">google.charts.load('current', {packages: ['corechart']});</script>
    
       <!-- Bootstrap core Datatable-->
        <script src="https://code.jquery.com/jquery-3.3.1.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/dataTables.buttons.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.flash.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.html5.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.print.min.js" type="text/javascript"></script>
    
        <style>        
            .sidebar {
              position: fixed;
              top: 0;
              bottom: 0;
              left: 0;
              z-index: 100; /* Behind the navbar */
              box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
            }
            
            .sidebar-sticky {
              position: relative;
              top: 0;
              height: calc(100vh - 48px);
              padding-top: .5rem;
              overflow-x: hidden;
              overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
            }
            
            @supports ((position: -webkit-sticky) or (position: sticky)) {
              .sidebar-sticky {
                position: -webkit-sticky;
                position: sticky;
              }
            }
            
            .sidebar .nav-link {
              color: black;
            }
            
            .sidebar .nav-link.active {
              color: #007bff;
            }
            
            .sidebar .nav-link:hover .feather,
            .sidebar .nav-link.active .feather {
              color: inherit;
            }
    
            [role="main"] {
              padding-top: 8px;
            }
            
            /* Set height of body and the document to 100% */
            body {
                height: 100%;
                margin: 0;
                //font-family:  Comic Sans MS;
                background-color: white;
            }
    
            /* Style tab links */
            .tablinkLog {
                cursor: pointer;
            }
            
            @import url(https://fonts.googleapis.com/css?family=Droid+Sans);
            .loader {
                position: fixed;
                left: 0px;
                top: 0px;
                width: 100%;
                height: 100%;
                z-index: 9999;
                background: url('http://www.downgraf.com/wp-content/uploads/2014/09/01-progress.gif?e44397') 50% 50% no-repeat rgb(249,249,249);
            }
    
            /* TILES */
            .tile {
              width: 100%;
              float: left;
              margin: 0px;
              list-style: none;
              font-size: 30px;
              color: #FFF;
              -moz-border-radius: 5px;
              -webkit-border-radius: 5px;
              margin-bottom: 5px;
              position: relative;
              text-align: center;
              color: white!important;
            }
    
            .tile.tile-fail {
              background: #f44336!important;
            }
            .tile.tile-pass {
              background: #4CAF50!important;
            }
            .tile.tile-info {
              background: #009688!important;
            }
            .tile.tile-head {
              background: #616161!important;
            }
            .dt-buttons {
                margin-left: 5px;
            }
        </style>
    </head>
    """

    soup = BeautifulSoup(head_content, "html.parser")

    body = soup.new_tag('body')
    soup.insert(20, body)

    icons_txt = """
    <div class="loader"></div>
     <div class="container-fluid">
            <div class="row">
                <nav class="col-md-2 d-none d-md-block bg-light sidebar" style="font-size:16px;">
                    <div class="sidebar-sticky">
                        <ul class="nav flex-column">                            
                      <img src="%s" style="height:18vh!important;width:95%%;"/>
                    
                    <br>
                    
                    <h6 class="sidebar-heading d-flex justify-content-between align-items-center text-muted">
                            <span>Metrics</span>
                            <a class="d-flex align-items-center text-muted" href="#"></a>
                        </h6>
    
                            <li class="nav-item">
                                <a class="tablink nav-link" href="#" id="defaultOpen" onclick="openPage('dashboard', this, 'orange')">
                                    <i class="fa fa-dashboard"></i> Dashboard
                                </a>
                            </li>
                            <li class="nav-item">
                                <a class="tablink nav-link" href="#" onclick="openPage('suiteMetrics', this, 'orange');executeDataTable('#sm',5)" >
                                    <i class="fa fa-th-large"></i> Suite Metrics
                                </a>
                            </li>
                            <li class="nav-item">
                                <a class="tablink nav-link" href="#" onclick="openPage('testMetrics', this, 'orange');executeDataTable('#tm',3)">
                                  <i class="fa fa-list-alt"></i> Test Metrics
                                </a>
                            </li>
                            <li class="nav-item">
                                <a class="tablink nav-link" href="#" onclick="openPage('keywordMetrics', this, 'orange');executeDataTable('#km',3)">
                                  <i class="fa fa-table"></i> Keyword Metrics
                                </a>
                            </li>
                            <li class="nav-item">
                                <a class="tablink nav-link" href="#" onclick="openPage('log', this, 'orange');">
                                  <i class="fa fa-wpforms"></i> Robot Logs
                                </a>
                            </li>
                            <li class="nav-item">
                                <a class="tablink nav-link" href="#" onclick="openPage('statistics', this, 'orange');">
                                  <i class="fa fa-envelope-o"></i> Email Metrics
                                </a>
                            </li>
                        </ul>
                        <h6 class="sidebar-heading d-flex justify-content-between align-items-center text-muted">
                            <span>Project</span>
                            <a class="d-flex align-items-center text-muted" href="#"></a>
                        </h6>
                        <ul class="nav flex-column mb-2">
                            <li class="nav-item">
                                <a style="color:blue;" class="tablink nav-link" target="_blank" href="https://www.github.com">
                                  <i class="fa fa-external-link"></i> Git Hub
                                </a>
                            </li>
                            <li class="nav-item">
                                <a style="color:blue;" class="tablink nav-link" target="_blank" href="https://www.jira.com">
                                  <i class="fa fa-external-link"></i> JIRA
                                </a>
                            </li>
                        </ul>
                    </div>
                </nav>
            </div>
    """ % (logo)

    body.append(BeautifulSoup(icons_txt, 'html.parser'))

    page_content_div = soup.new_tag('div')
    page_content_div["role"] = "main"
    page_content_div["class"] = "col-md-9 ml-sm-auto col-lg-10 px-4"
    body.insert(50, page_content_div)

    writer("\n1 of 6: Capturing dashboard content...")
    ### ============================ START OF DASHBOARD ======================================= ####
    test_stats = TestStats()
    result.visit(test_stats)

    total_suite = test_stats.total_suite
    passed_suite = test_stats.passed_suite
    failed_suite = test_stats.failed_suite

    suitepp = math.ceil(passed_suite * 100.0 / total_suite)

    elapsedtime = datetime(
        1970, 1, 1) + timedelta(milliseconds=result.suite.elapsedtime)
    elapsedtime = elapsedtime.strftime("%X")

    myResult = result.generated_by_robot

    if myResult:
        generator = "Robot"
    else:
        generator = "Rebot"

    stats = result.statistics
    total = stats.total.all.total
    passed = stats.total.all.passed
    failed = stats.total.all.failed

    testpp = round(passed * 100.0 / total, 2)

    kw_stats = KeywordStats(ignore_library, ignore_type)
    result.visit(kw_stats)

    total_keywords = kw_stats.total_keywords
    passed_keywords = kw_stats.passed_keywords
    failed_keywords = kw_stats.failed_keywords

    # Handling ZeroDivisionError exception when no keywords are found
    if total_keywords > 0:
        kwpp = round(passed_keywords * 100.0 / total_keywords, 2)
    else:
        kwpp = 0

    dashboard_content = """
    <div class="tabcontent" id="dashboard">
                
                    <div class="d-flex flex-column flex-md-row align-items-center p-1 mb-3 bg-light border-bottom shadow-sm">
                      <h5 class="my-0 mr-md-auto font-weight-normal"><i class="fa fa-dashboard"></i> Dashboard</h5>
                      <nav class="my-2 my-md-0 mr-md-3" style="color:red">
                        <a class="p-2"><b style="color:black;">Execution Time: </b>%s h</a>
                        <a class="p-2"><b style="color:black;cursor: pointer;" data-toggle="tooltip" title=".xml file is created by">Generated By: </b>%s</a>
                      </nav>                  
                    </div>
                
                    <div class="row">
                        <div class="col-md-3"  onclick="openPage('suiteMetrics', this, '')" data-toggle="tooltip" title="Click to view Suite metrics" style="cursor: pointer;">                        
                            <a class="tile tile-head">
                                Suite
                                <p style="font-size:12px">Statistics</p>
                            </a>
                        </div>
                        <div class="col-md-3">                        
                            <a class="tile tile-info">
                                %s
                                <p style="font-size:12px">Total</p>
                            </a>
                        </div>
                        <div class="col-md-3">                        
                            <a class="tile tile-pass">
                                %s
                                <p style="font-size:12px">Pass</p>
                            </a>
                        </div>						
                        <div class="col-md-3">                        
                            <a class="tile tile-fail">
                                %s
                                <p style="font-size:12px">Fail</p>
                            </a>
                        </div>
                    </div>
                    
                    <div class="row">
                        <div class="col-md-3"  onclick="openPage('testMetrics', this, '')" data-toggle="tooltip" title="Click to view Test metrics" style="cursor: pointer;">                        
                            <a class="tile tile-head">
                                Test
                                <p style="font-size:12px">Statistics</p>
                            </a>
                        </div>
                        <div class="col-md-3">                        
                            <a class="tile tile-info">
                                %s
                                <p style="font-size:12px">Total</p>
                            </a>
                        </div>
                        <div class="col-md-3">                        
                            <a class="tile tile-pass">
                                %s
                                <p style="font-size:12px">Pass</p>
                            </a>
                        </div>						
                        <div class="col-md-3">                        
                            <a class="tile tile-fail">
                                %s
                                <p style="font-size:12px">Fail</p>
                            </a>
                        </div>
                    </div>
                    
                    <div class="row">
                        <div class="col-md-3"  onclick="openPage('keywordMetrics', this, '')" data-toggle="tooltip" title="Click to view Keyword metrics" style="cursor: pointer;">                        
                            <a class="tile tile-head">
                                Keyword
                                <p style="font-size:12px">Statistics</p>
                            </a>
                        </div>
                        <div class="col-md-3">                        
                            <a class="tile tile-info">
                                %s
                                <p style="font-size:12px">Total</p>
                            </a>
                        </div>
                        <div class="col-md-3">                        
                            <a class="tile tile-pass">
                                %s
                                <p style="font-size:12px">Pass</p>
                            </a>
                        </div>						
                        <div class="col-md-3">                        
                            <a class="tile tile-fail">
                                %s
                                <p style="font-size:12px">Fail</p>
                            </a>
                        </div>
                    </div>
                    
                    <hr></hr>
                    <div class="row">
                        <div class="col-md-4" style="background-color:white;height:280px;width:auto;border:groove;">
                            <span style="font-weight:bold">Suite Status:</span>
                            <div id="suiteChartID" style="height:250px;width:auto;"></div>
                        </div>
                        <div class="col-md-4" style="background-color:white;height:280px;width:auto;border:groove;">
                            <span style="font-weight:bold">Test Status:</span>
                            <div id="testChartID" style="height:250px;width:auto;"></div>
                        </div>
                        <div class="col-md-4" style="background-color:white;height:280px;width:auto;border:groove;">
                            <span style="font-weight:bold">Keyword Status:</span>
                            <div id="keywordChartID" style="height:250px;width:auto;"></div>
                        </div>
                    </div>
    
                    <hr></hr>
                    <div class="row">
                        <div class="col-md-12" style="background-color:white;height:450px;width:auto;border:groove;">
                            <span style="font-weight:bold">Top 10 Suite Performance(sec):</span>
                            <div id="suiteBarID" style="height:400px;width:auto;"></div>
                        </div>
                        <div class="col-md-12" style="background-color:white;height:450px;width:auto;border:groove;">
                            <span style="font-weight:bold">Top 10 Test Performance(sec):</span>
                            <div id="testsBarID" style="height:400px;width:auto;"></div>
                        </div>
                        <div class="col-md-12" style="background-color:white;height:450px;width:auto;border:groove;">
                            <span style="font-weight:bold">Top 10 Keywords Performance(sec):</span>
                            <div id="keywordsBarID" style="height:400px;width:auto;"></div>
                        </div>
                    </div>
                    <div class="row">
                    <div class="col-md-12" style="height:25px;width:auto;">
                        <p class="text-muted" style="text-align:center;font-size:9px">robotframework-metrics</p>
                    </div>
                    </div>
       
       <script>
        window.onload = function(){
        executeDataTable('#sm',5);
        executeDataTable('#tm',3);
        executeDataTable('#km',3);
        createPieChart(%s,%s,'suiteChartID','Suite Status:');
        createBarGraph('#sm',0,5,10,'suiteBarID','Elapsed Time(s): ','Suite');	
        createPieChart(%s,%s,'testChartID','Tests Status:');	
        createBarGraph('#tm',1,3,10,'testsBarID','Elapsed Time(s): ','Test'); 
        createPieChart(%s,%s,'keywordChartID','Keywords Status:');
        createBarGraph('#km',1,3,10,'keywordsBarID','Elapsed Time(s): ','Keyword');
        };
       </script>
       <script>
    function openInNewTab(url,element_id) {
      var element_id= element_id;
      var win = window.open(url, '_blank');
      win.focus();
      $('body').scrollTo(element_id); 
    }
    </script>
      </div>
    """ % (elapsedtime, generator, total_suite, passed_suite, failed_suite,
           total, passed, failed, total_keywords, passed_keywords,
           failed_keywords, passed_suite, failed_suite, passed, failed,
           passed_keywords, failed_keywords)
    page_content_div.append(BeautifulSoup(dashboard_content, 'html.parser'))

    ### ============================ END OF DASHBOARD ============================================ ####
    writer("\n2 of 6: Capturing suite metrics...")
    ### ============================ START OF SUITE METRICS ======================================= ####

    # Tests div
    suite_div = soup.new_tag('div')
    suite_div["id"] = "suiteMetrics"
    suite_div["class"] = "tabcontent"
    page_content_div.insert(50, suite_div)

    test_icon_txt = """
    <h4><b><i class="fa fa-table"></i> Suite Metrics</b></h4>
    <hr></hr>
    """
    suite_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # Create table tag
    table = soup.new_tag('table')
    table["id"] = "sm"
    table["class"] = "table table-striped table-bordered"
    suite_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Suite Name"
    tr.insert(0, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Total"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Pass"
    tr.insert(3, th)

    th = soup.new_tag('th')
    th.string = "Fail"
    tr.insert(4, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(5, th)

    suite_tbody = soup.new_tag('tbody')
    table.insert(11, suite_tbody)

    ### =============== GET SUITE METRICS =============== ###
    if group:
        group.spawn(result.visit, SuiteResults(soup, suite_tbody, log_name))
    else:
        result.visit(SuiteResults(soup, suite_tbody, log_name))

    test_icon_txt = """
    <div class="row">
    <div class="col-md-12" style="height:25px;width:auto;">
    </div>
    </div>
    """
    suite_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))
    ### ============================ END OF SUITE METRICS ============================================ ####
    writer("\n3 of 6: Capturing test metrics...")
    ### ============================ START OF TEST METRICS ======================================= ####
    # Tests div
    tm_div = soup.new_tag('div')
    tm_div["id"] = "testMetrics"
    tm_div["class"] = "tabcontent"
    page_content_div.insert(100, tm_div)

    test_icon_txt = """
    <h4><b><i class="fa fa-table"></i> Test Metrics</b></h4>
    <hr></hr>
    """
    tm_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # Create table tag
    table = soup.new_tag('table')
    table["id"] = "tm"
    table["class"] = "table table-striped table-bordered"
    tm_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Suite Name"
    tr.insert(0, th)

    th = soup.new_tag('th')
    th.string = "Test Case"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(3, th)

    test_tbody = soup.new_tag('tbody')
    table.insert(11, test_tbody)

    ### =============== GET TEST METRICS =============== ###
    if group:
        group.spawn(result.visit, TestResults(soup, test_tbody, log_name))
    else:
        result.visit(TestResults(soup, test_tbody, log_name))

    test_icon_txt = """
    <div class="row">
    <div class="col-md-12" style="height:25px;width:auto;">
    </div>
    </div>
    """
    tm_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))
    ### ============================ END OF TEST METRICS ============================================ ####
    writer("\n4 of 6: Capturing keyword metrics...")
    ### ============================ START OF KEYWORD METRICS ======================================= ####

    # Keywords div
    km_div = soup.new_tag('div')
    km_div["id"] = "keywordMetrics"
    km_div["class"] = "tabcontent"
    page_content_div.insert(150, km_div)

    keyword_icon_txt = """
    <h4><b><i class="fa fa-table"></i> Keyword Metrics</b></h4>
      <hr></hr>
    """
    km_div.append(BeautifulSoup(keyword_icon_txt, 'html.parser'))

    # Create table tag
    # <table id="myTable">
    table = soup.new_tag('table')
    table["id"] = "km"
    table["class"] = "table table-striped table-bordered"
    km_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Test Case"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Keyword"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(3, th)

    kw_tbody = soup.new_tag('tbody')
    table.insert(1, kw_tbody)

    if group:
        group.spawn(
            result.visit,
            KeywordResults(soup, kw_tbody, ignore_library, ignore_type))
        group.join()
    else:
        result.visit(
            KeywordResults(soup, kw_tbody, ignore_library, ignore_type))

    test_icon_txt = """
    <div class="row">
    <div class="col-md-12" style="height:25px;width:auto;">
    </div>
    </div>
    """
    km_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))
    ### ============================ END OF KEYWORD METRICS ======================================= ####

    ### ============================ START OF LOGS ====================================== ###

    # Logs div
    log_div = soup.new_tag('div')
    log_div["id"] = "log"
    log_div["class"] = "tabcontent"
    page_content_div.insert(200, log_div)

    test_icon_txt = """
        <p style="text-align:right">** <b>Report.html</b> and <b>Log.html</b> need to be in current folder in order to display here</p>
      <div class="embed-responsive embed-responsive-4by3">
        <iframe class="embed-responsive-item" src=%s></iframe>
      </div>
    """ % (log_name)
    log_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    ### ============================ END OF LOGS ======================================= ####

    ### ============================ EMAIL STATISTICS ================================== ###
    # Statistics div
    statisitcs_div = soup.new_tag('div')
    statisitcs_div["id"] = "statistics"
    statisitcs_div["class"] = "tabcontent"
    page_content_div.insert(300, statisitcs_div)

    emailStatistics = """
    <h4><b><i class="fa fa-envelope-o"></i> Email Statistics</b></h4>
    <hr></hr>
    <button id="create" class="btn btn-primary active inner" role="button" onclick="updateTextArea();this.style.visibility= 'hidden';"><i class="fa fa-cogs"></i> Generate Statistics Email</button>
    <a download="message.eml" class="btn btn-primary active inner" role="button" id="downloadlink" style="display: none; width: 300px;"><i class="fa fa-download"></i> Click Here To Download Email</a>
    <script>
    function updateTextArea() {
        var suite = "<b>Top 10 Suite Performance:</b><br><br>" + $("#suiteBarID table")[0].outerHTML;
        var test = "<b>Top 10 Test Performance:</b><br><br>" + $("#testsBarID table")[0].outerHTML;
        var keyword ="<b>Top 10 Keyword Performance:</b><br><br>" + $("#keywordsBarID table")[0].outerHTML;
        var saluation="<pre><br>Please refer RF Metrics Report for detailed statistics.<br><br>Regards,<br>QA Team</pre></body></html>";
        document.getElementById("textbox").value += "<br>" + suite + "<br>" + test + "<br>" + keyword + saluation;
        $("#create").click(function(){
        $(this).remove();
        });
    }
    </script>
    
<textarea id="textbox" class="col-md-12" style="height: 400px; padding:1em;">
To: [email protected]
Subject: Automation Execution Status
X-Unsent: 1
Content-Type: text/html


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test Email Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0 " />
        <style>
            body {
                background-color:#F2F2F2; 
            }
            body, html, table,pre,b {
                font-family: Calibri, Arial, sans-serif;
                font-size: 1em; 
            }
            .pastdue { color: crimson; }
            table {
                border: 1px solid silver;
                padding: 6px;
                margin-left: 30px;
                width: 600px;
            }
            thead {
                text-align: center;
                font-size: 1.1em;        
                background-color: #B0C4DE;
                font-weight: bold;
                color: #2D2C2C;
            }
            tbody {
            text-align: center;
            }
            th {
            width: 25%%;
            word-wrap:break-word;
            }
        </style>
    </head>
    <body><pre>Hi Team,
Following are the last build execution statistics.

<b>Metrics:<b>

</pre>
        <table>
            <thead>
            <th style="width: 25%%;">Statistics</th>
            <th style="width: 25%%;">Total</th>
            <th style="width: 25%%;">Pass</th>
            <th style="width: 25%%;">Fail</th>
            </thead>
            <tbody>
            <tr>
                <td style="text-align: left;font-weight: bold;"> SUITE </td>
                <td style="background-color: #F5DEB3;text-align: center;">%s</td>
                <td style="background-color: #90EE90;text-align: center;">%s</td>
                <td style="background-color: #F08080;text-align: center;">%s</td>
            </tr>
            <tr>
                <td style="text-align: left;font-weight: bold;"> TESTS </td>
                <td style="background-color: #F5DEB3;text-align: center;">%s</td>
                <td style="background-color: #90EE90;text-align: center;">%s</td>
                <td style="background-color: #F08080;text-align: center;">%s</td>
            </tr>
            <tr>
                <td style="text-align: left;font-weight: bold;"> KEYWORDS </td>
                <td style="background-color: #F5DEB3;text-align: center;">%s</td>
                <td style="background-color: #90EE90;text-align: center;">%s</td>
                <td style="background-color: #F08080;text-align: center;">%s</td>
            </tr>
            </tbody>
        </table>


</textarea>
    
    """ % (total_suite, passed_suite, failed_suite, total, passed, failed,
           total_keywords, passed_keywords, failed_keywords)
    statisitcs_div.append(BeautifulSoup(emailStatistics, 'html.parser'))

    ### ============================ END OF EMAIL STATISTICS ================================== ###

    script_text = """
    
        <script>
            (function () {
            var textFile = null,
              makeTextFile = function (text) {
                var data = new Blob([text], {type: 'text/plain'});
                if (textFile !== null) {
                  window.URL.revokeObjectURL(textFile);
                }
                textFile = window.URL.createObjectURL(data);
                return textFile;
              };
            
              var create = document.getElementById('create'),
                textbox = document.getElementById('textbox');
              create.addEventListener('click', function () {
                var link = document.getElementById('downloadlink');
                link.href = makeTextFile(textbox.value);
                link.style.display = 'block';
              }, false);
            })();
        </script>
        <script>
            function createPieChart(passed_count,failed_count,ChartID,ChartName){
            var status = [];
            status.push(['Status', 'Percentage']);
            status.push(['PASS',parseInt(passed_count)],['FAIL',parseInt(failed_count)]);
            var data = google.visualization.arrayToDataTable(status);
    
            var options = {
            pieHole: 0.6,
            legend: 'none',
            chartArea: {width: "95%",height: "90%"},
            colors: ['green', 'red'],
            };
    
            var chart = new google.visualization.PieChart(document.getElementById(ChartID));
            chart.draw(data, options);
        }
        </script>
        <script>
           function createBarGraph(tableID,keyword_column,time_column,limit,ChartID,Label,type){
            var status = [];
            css_selector_locator = tableID + ' tbody >tr'
            var rows = $(css_selector_locator);
            var columns;
            var myColors = [
                '#4F81BC',
                '#C0504E',
                '#9BBB58',
                '#24BEAA',
                '#8064A1',
                '#4AACC5',
                '#F79647',
                '#815E86',
                '#76A032',
                '#34558B'
            ];
            status.push([type, Label,{ role: 'annotation'}, {role: 'style'}]);
            for (var i = 0; i < rows.length; i++) {
                if (i == Number(limit)){
                    break;
                }
                //status = [];
                name_value = $(rows[i]).find('td'); 
              
                time=($(name_value[Number(time_column)]).html()).trim();
                keyword=($(name_value[Number(keyword_column)]).html()).trim();
                status.push([keyword,parseFloat(time),parseFloat(time),myColors[i]]);
              }
              var data = google.visualization.arrayToDataTable(status);
    
              var options = {
                legend: 'none',
                chartArea: {width: "92%",height: "75%"},
                bar: {
                    groupWidth: '90%'
                },
                annotations: {
                    alwaysOutside: true,
                    textStyle: {
                    fontName: 'Comic Sans MS',
                    fontSize: 13,
                    bold: true,
                    italic: true,
                    color: "black",     // The color of the text.
                    },
                },
                hAxis: {
                    textStyle: {
                        fontName: 'Arial',
                        fontSize: 10,
                    }
                },
                vAxis: {
                    gridlines: { count: 10 },
                    textStyle: {                    
                        fontName: 'Comic Sans MS',
                        fontSize: 10,
                    }
                },
              };  
    
                // Instantiate and draw the chart.
                var chart = new google.visualization.ColumnChart(document.getElementById(ChartID));
                chart.draw(data, options);
             }
    
        </script>
    
     <script>
      function executeDataTable(tabname,sortCol) {
        var fileTitle;
        switch(tabname) {
            case "#sm":
                fileTitle = "SuiteMetrics";
                break;
            case "#tm":
                fileTitle =  "TestMetrics";
                break;
            case "#km":
                fileTitle =  "KeywordMetrics";
                break;
            default:
                fileTitle =  "metrics";
        }
    
        $(tabname).DataTable(
            {
                retrieve: true,
                "order": [[ Number(sortCol), "desc" ]],
                dom: 'l<".margin" B>frtip',
                buttons: [
                    'copy',
                    {
                        extend: 'csv',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        title : '',
                    },
                    {
                        extend: 'excel',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        title : '',
                    },
                    {
                        extend: 'pdf',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        title : '',
                    },
                    {
                        extend: 'print',
                        title : '',
                    },
                ],
            } 
        );
    }
     </script>
     <script>
      function openPage(pageName,elmnt,color) {
        var i, tabcontent, tablinks;
        tabcontent = document.getElementsByClassName("tabcontent");
        for (i = 0; i < tabcontent.length; i++) {
            tabcontent[i].style.display = "none";
        }
        tablinks = document.getElementsByClassName("tablink");
        for (i = 0; i < tablinks.length; i++) {
            tablinks[i].style.backgroundColor = "";
        }
        document.getElementById(pageName).style.display = "block";
        elmnt.style.backgroundColor = color;
    
    }
    // Get the element with id="defaultOpen" and click on it
    document.getElementById("defaultOpen").click();
     </script>
     <script>
     // Get the element with id="defaultOpen" and click on it
    document.getElementById("defaultOpen").click();
     </script>
     <script>
    $(window).on('load',function(){$('.loader').fadeOut();});
    </script>
    """

    body.append(BeautifulSoup(script_text, 'html.parser'))

    ### ====== WRITE TO RF_METRICS_REPORT.HTML ===== ###

    # Write output as html file
    with open(result_file, 'w') as outfile:
        outfile.write(soup.prettify())

    # Wait for 2 seconds - File is generated
    time.sleep(2)

    # ====== EMAIL CONTENT ========== #

    email_content = """
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>Robotframework Metrics</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0 " />
          <style>
             body {
                 background-color:#F2F2F2; 
             }
             body, html, table,span,b {
                 font-family: Calibri, Arial, sans-serif;
                 font-size: 1em; 
             }
             .pastdue { color: crimson; }
             table {
                 border: 1px solid silver;
                 padding: 6px;
                 margin-left: 30px;
                 width: 600px;
             }
             thead {
                 text-align: center;
                 font-size: 1.1em;        
                 background-color: #B0C4DE;
                 font-weight: bold;
                 color: #2D2C2C;
             }
             tbody {
                text-align: center;
             }
             th {
                word-wrap:break-word;
             }
             td {
                height: 25px;
             }
            .dt-buttons {
                margin-left: 30px;
            }
          </style>
       </head>
       <body>
       <span>Hi Team,<br>Following are the last build execution status.<br><br><b>Metrics:<b><br><br></span>
          <table>
             <thead>
                <th style="width: 25vh;"> Stats </th>
                <th style="width: 20vh;"> Total </th>
                <th style="width: 20vh;"> Pass </th>
                <th style="width: 20vh;"> Fail </th>
                      <th style="width: 15vh;"> Perc (%%)</th>
             </thead>
             <tbody>
                <tr>
                   <td style="text-align: left;font-weight: bold;"> SUITE </td>
                   <td style="text-align: center;">%s</td>
                   <td style="text-align: center;">%s</td>
                   <td style="text-align: center;">%s</td>
                         <td style="text-align: center;">%s</td>
                </tr>
                <tr>
                   <td style="text-align: left;font-weight: bold;"> TESTS </td>
                   <td style="text-align: center;">%s</td>
                   <td style="text-align: center;">%s</td>
                   <td style="text-align: center;">%s</td>
                         <td style="text-align: center;">%s</td>
                </tr>
                <tr>
                   <td style="text-align: left;font-weight: bold;"> KEYWORDS </td>
                   <td style="text-align: center;">%s</td>
                   <td style="text-align: center;">%s</td>
                   <td style="text-align: center;">%s</td>
                         <td style="text-align: center;">%s</td>
                </tr>
             </tbody>
          </table>
    
    <span><br><b>Info:<b><br><br></span>
     <table>
             <tbody>
                <tr>
                   <td style="text-align: left;font-weight: normal;width: 30vh;"> Execution Time </td>
                   <td style="text-align: center;font-weight: normal;">%s h</td>
                </tr>
                <tr>
                   <td style="text-align: left;font-weight: normal;width: 50vh;"> Generated By </td>
                   <td style="text-align: center;font-weight: normal;">%s</td>
                </tr>
             </tbody>
          </table>
    
    <span style="text-align: left;font-weight: normal;"><br>Please refer robotframework-metrics report for detailed info.<br><br>Regards,<br>QA Team</span>
    
    </body></html> 
    """ % (total_suite, passed_suite, failed_suite, suitepp, total, passed,
           failed, testpp, total_keywords, passed_keywords, failed_keywords,
           kwpp, elapsedtime, generator)

    #msg.set_payload(email_content)
    msg.attach(MIMEText(email_content, 'html'))

    # Attach robotframework file
    rfmetrics = MIMEBase('application', "octet-stream")
    rfmetrics.set_payload(open(result_file, "rb").read())
    encoders.encode_base64(rfmetrics)
    attachmentName = 'attachment; filename=%s' % (result_file_name)
    rfmetrics.add_header('Content-Disposition', attachmentName)
    msg.attach(rfmetrics)

    if send_email:
        # Start server
        server.starttls()
        writer("\n5 of 6: Sending email with robotmetrics.html...")
        # Login Credentials for sending the mail
        server.login(msg['From'], password)

        server.sendmail(sender, recipients, msg.as_string())
        writer("\n6 of 6: Email sent successfully!")
    else:
        writer("\n6 of 6: Skipping step 5 (send email)!")

    writer(
        "\nResults file created successfully and can be found at {}\n".format(
            result_file))
Beispiel #10
0
 def _do_on_all(self, func):
     group = Group()
     return group.imap_unordered(func, self.s3.values())
Beispiel #11
0
 def my_task(self):
     from gevent.pool import Group
     group = Group()
     group.spawn(lambda: self.query1())
     group.spawn(lambda: self.query2())
     group.join()  # wait for greenlets to finish
Beispiel #12
0
 def __init__(self, callback_func=None):
     self.greenlet = Group()
     self.__loopOffset = 1 / 100.0  #解析数据的间隔
     self.__callback_func = callback_func
     self.logger = Glogger.getLogger()
Beispiel #13
0
def main(workers):
    queue = SubmitQueue()
    worker_group = Group()
    for _ in range(workers):
        worker_group.start(SubmitWorker(queue))
    worker_group.join()
def get_all_company():
    company_group = Group()
    for page in range(1, 500):
        company_group.add(gevent.spawn(get_company_page, page))
    company_group.join()
def generate_report(opts):
    logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
    group = Group() if not FAILED_IMPORT else ''

    # START OF CUSTOMIZE REPORT
    # URL or filepath of your company logo
    logo = opts.logo

    # Ignores following library keywords in metrics report
    ignore_library = IGNORE_LIBRARIES
    if opts.ignore:
        ignore_library.extend(opts.ignore)

    # Ignores following type keywords in metrics report
    ignore_type = IGNORE_TYPES
    if opts.ignoretype:
        ignore_type.extend(opts.ignoretype)

    # END OF CUSTOMIZE REPORT
    # Report to support file location as arguments
    # Source Code Contributed By : Ruud Prijs
    # input directory
    path = os.path.abspath(os.path.expanduser(opts.path))

    # output.xml files
    output_names = []
    # support "*.xml" of output files
    if (opts.output == "*.xml"):
        for item in os.listdir(path):
            if os.path.isfile(item) and item.endswith('.xml'):
                output_names.append(item)
    else:
        for curr_name in opts.output.split(","):
            curr_path = os.path.join(path, curr_name)
            output_names.append(curr_path)

    # log.html file
    log_name = opts.log_name

    # copy the list of output_names onto the one of required_files; the latter may (in the future)
    # contain files that should not be processed as output_names
    required_files = list(output_names)
    missing_files = [
        filename for filename in required_files if not os.path.exists(filename)
    ]
    if missing_files:
        # We have files missing.
        exit("output.xml file is missing: {}".format(", ".join(missing_files)))

    mt_time = datetime.now().strftime('%Y%m%d-%H%M%S')

    # Output result file location
    if opts.metrics_report_name:
        result_file_name = opts.metrics_report_name
    else:
        result_file_name = 'metrics-' + mt_time + '.html'
    result_file = os.path.join(path, result_file_name)

    # Read output.xml file
    result = ExecutionResult(*output_names)
    result.configure(stat_config={
        'suite_stat_level': 2,
        'tag_stat_combine': 'tagANDanother'
    })

    logging.info("Converting .xml to .html file. This may take few minutes...")

    head_content = """
    <!DOCTYPE doctype html>
    <html lang="en">

    <head>
        <link href="https://png.icons8.com/windows/50/000000/bot.png" rel="shortcut icon" type="image/x-icon" />
        <title>RF Metrics</title>
        <meta charset="utf-8" />
        <meta content="width=device-width, initial-scale=1" name="viewport" />
        <link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet" />
        <link href="https://cdn.datatables.net/buttons/1.5.2/css/buttons.dataTables.min.css" rel="stylesheet" />
        <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
        <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
        <script src="https://code.jquery.com/jquery-3.3.1.js" type="text/javascript"/>
        <!-- Bootstrap core Googleccharts -->
        <script src="https://www.gstatic.com/charts/loader.js" type="text/javascript"/>
        <script type="text/javascript">
            google.charts.load('current', {
                packages: ['corechart']
            });
        </script>
        <!-- Bootstrap core Datatable-->
        <script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/dataTables.buttons.min.js" type="text/javascript"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.html5.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.print.min.js" type="text/javascript"></script>
        <script src="https://cdn.datatables.net/buttons/1.6.1/js/buttons.colVis.min.js" type="text/javascript"></script>

        <style>
            body {
                font-family: -apple-system, sans-serif;
                background-color: #eeeeee;
            }

            .sidenav {
                height: 100%;
                width: 220px;
                position: fixed;
                z-index: 1;
                top: 0;
                left: 0;
                background-color: white;
                overflow-x: hidden;
            }

            .sidenav a {
                padding: 12px 10px 8px 12px;
                text-decoration: none;
                font-size: 18px;
                color: Black;
                display: block;
            }

            .main {
                padding-top: 10px;
            }

            @media screen and (max-height: 450px) {
                .sidenav {
                    padding-top: 15px;
                }
                .sidenav a {
                    font-size: 18px;
                }
            }

            .wrimagecard {
                margin-top: 0;
                margin-bottom: 0.6rem;
                border-radius: 10px;
                transition: all 0.3s ease;
                background-color: #f8f9fa;
            }

            .rowcard {
                padding-top: 10px;
                box-shadow: 12px 15px 20px 0px rgba(46, 61, 73, 0.15);
                border-radius: 15px;
                transition: all 0.3s ease;
                background-color: white;
            }

            .tablecard {
                background-color: white;
                font-size: 14px;
            }

            tr {
                height: 40px;
            }

            .dt-buttons {
                margin-left: 5px;
            }

            th, td, tr {
                text-align:center;
                vertical-align: middle;
            }

            .loader {
                position: fixed;
                left: 0px;
                top: 0px;
                width: 100%;
                height: 100%;
                z-index: 9999;
                background: url('https://i.ibb.co/cXnKsNR/Cube-1s-200px.gif') 50% 50% no-repeat rgb(249, 249, 249);
            }
        </style>
    </head>
    """
    if opts.ignorekeywords == "True":
        hide_keyword = "hidden"
    else:
        hide_keyword = ""

    if opts.ignorelogs == "True":
        hide_logs = "hidden"
    else:
        hide_logs = ""

    soup = BeautifulSoup(head_content, "html.parser")
    body = soup.new_tag('body')
    soup.insert(20, body)
    icons_txt = """
    <div class="loader"></div>
    <div class="sidenav">
        <a> <img class="wrimagecard" src="%s" style="height:20vh;max-width:98%%;"/> </a>
        <a class="tablink" href="#" id="defaultOpen" onclick="openPage('dashboard', this, '#fc6666')"><i class="fa fa-dashboard" style="color:CORNFLOWERBLUE"></i> Dashboard</a>
        <a class="tablink" href="#" onclick="openPage('suiteMetrics', this, '#fc6666'); executeDataTable('#sm',5)"><i class="fa fa-th-large" style="color:CADETBLUE"></i> Suite Metrics</a>
        <a class="tablink" href="#" onclick="openPage('testMetrics', this, '#fc6666'); executeDataTable('#tm',3)"><i class="fa fa-list-alt" style="color:PALEVIOLETRED"></i> Test Metrics</a>
        <a %s class="tablink" href="#" onclick="openPage('keywordMetrics', this, '#fc6666'); executeDataTable('#km',3)"><i class="fa fa-table" style="color:STEELBLUE"></i> Keyword Metrics</a>
        <a %s class="tablink" href="#" onclick="openPage('log', this, '#fc6666');"><i class="fa fa-wpforms" style="color:CHOCOLATE"></i> Logs</a>
    </div>
    """ % (logo, hide_keyword, hide_logs)

    body.append(BeautifulSoup(icons_txt, 'html.parser'))

    page_content_div = soup.new_tag('div')
    page_content_div["class"] = "main col-md-9 ml-sm-auto col-lg-10 px-4"
    body.insert(50, page_content_div)

    logging.info("1 of 4: Capturing dashboard content...")
    test_stats = TestStats()
    result.visit(test_stats)

    try:
        test_stats_obj = test_stats.all
    except:
        test_stats_obj = test_stats
    total_suite = test_stats_obj.total_suite
    passed_suite = test_stats_obj.passed_suite
    failed_suite = test_stats_obj.failed_suite
    try:
        skipped_suite = test_stats_obj.skipped_suite
    except:
        skipped_suite = 0

    #suitepp = round(passed_suite * 100.0 / total_suite, 1)
    #suitefp = round(failed_suite * 100.0 / total_suite, 1)
    elapsedtime = datetime(
        1970, 1, 1) + timedelta(milliseconds=result.suite.elapsedtime)
    elapsedtime = elapsedtime.strftime("%X")
    my_results = result.generated_by_robot

    if my_results:
        generator = "Robot"
    else:
        generator = "Rebot"

    stats = result.statistics
    try:
        stats_obj = stats.total.all
    except:
        stats_obj = stats.total
    total = stats_obj.total
    passed = stats_obj.passed
    failed = stats_obj.failed
    try:
        skipped = stats_obj.skipped
    except:
        skipped = 0

    #testpp = round(passed * 100.0 / total, 1)
    #testfp = round(failed * 100.0 / total, 1)

    kw_stats = KeywordStats(ignore_library, ignore_type)
    result.visit(kw_stats)

    total_keywords = kw_stats.total_keywords
    passed_keywords = kw_stats.passed_keywords
    failed_keywords = kw_stats.failed_keywords
    try:
        skipped_keywords = kw_stats.skipped_keywords
    except:
        skipped_keywords = 0

    # Handling ZeroDivisionError exception when no keywords are found
    # if total_keywords > 0:
    #     kwpp = round(passed_keywords * 100.0 / total_keywords, 1)
    #     kwfp = round(failed_keywords * 100.0 / total_keywords, 1)
    # else:
    #     kwpp = 0
    #     kwfp = 0

    dashboard_content = """
    <div class="tabcontent" id="dashboard">
        <div id="stats_screenshot_area">
        <div class="d-flex flex-column flex-md-row align-items-center p-1 mb-3 bg-light border-bottom shadow-sm rowcard">
            <h5 class="my-0 mr-md-auto font-weight-normal"><i class="fa fa-dashboard"></i> Dashboard</h5>
            <nav class="my-2 my-md-0 mr-md-3" style="color:#fc6666">
            <a class="p-2"><b style="color:black;">Execution Time: </b>__TIME__ h</a>
            <a class="p-2"><b style="color:black;cursor: pointer;" data-toggle="tooltip" title=".xml file is created by">Generated By: </b>__GENERATED-BY__</a>
            </nav>
        </div>

        <div class="row rowcard">

            <div class="col-md-4 border-right" onclick="openPage('suiteMetrics', this, '')" data-toggle="tooltip" 
                title="Click to view Suite metrics" style="cursor: pointer;">
                <span style="font-weight:bold; padding-left:5px;color:gray">Suite Statistics:</span>
                <table style="width:100%;height:200px;text-align: center;">
                    <tbody>
                        <tr style="height:60%">
                            <td>
                                <table style="width:100%">
                                    <tbody>
                                        <tr style="height:100%">
                                            <td style="font-size:60px; color:#2ecc71">__SPASS__</td>
                                        </tr>
                                        <tr>
                                            <td><span style="color: #999999;font-size:12px">Pass</span></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </td>
                        </tr>

                        <tr style="height:25%">
                            <td>
                                <table style="width:100%">
                                    <tbody>
                                        <tr style="height:70%;font-size:25px" align="center" valign="middle">
                                            <td style="width: 33%; color:brown">__STOTAL__</td>
                                            <td style="width: 33%; color:orange">__SSKIP__</td>
                                            <td style="width: 33%; color:#fc6666">__SFAIL__</td>
                                        </tr>
                                        <tr style="height:30%" align="center" valign="top">
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Total</span></td>
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Skip</span></td>
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Fail</span></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div class="col-md-4 borders" onclick="openPage('testMetrics', this, '')" data-toggle="tooltip" 
                            title="Click to view Test metrics" style="cursor: pointer;">
                <span style="font-weight:bold; padding-left:5px;color:gray">Test Statistics:</span>
                <table style="width:100%;height:200px;text-align: center;">
                    <tbody>
                        <tr style="height:60%">
                            <td>
                                <table style="width:100%">
                                    <tbody>
                                        <tr style="height:100%">
                                            <td style="font-size:60px; color:#2ecc71">__TPASS__</td>
                                        </tr>
                                        <tr>
                                            <td><span style="color: #999999;font-size:12px">Pass</span></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </td>
                        </tr>

                        <tr style="height:25%">
                            <td>
                                <table style="width:100%">
                                    <tbody>
                                        <tr style="height:70%;font-size:25px" align="center" valign="middle">
                                            <td style="width: 33%; color:brown">__TTOTAL__</td>
                                            <td style="width: 33%; color:orange">__TSKIP__</td>
                                            <td style="width: 33%; color:#fc6666">__TFAIL__</td>
                                        </tr>
                                        <tr style="height:30%" align="center" valign="top">
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Total</span></td>
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Skip</span></td>
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Fail</span></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div class="col-md-4 border-left" onclick="openPage('keywordMetrics', this, '')" data-toggle="tooltip" 
                            title="Click to view Keyword metrics" style="cursor: pointer;">
                <span style="font-weight:bold; padding-left:5px;color:gray">Keyword Statistics:</span>
                <table style="width:100%;height:200px;text-align: center;">
                    <tbody>
                        <tr style="height:60%">
                            <td>
                                <table style="width:100%">
                                    <tbody>
                                        <tr style="height:100%">
                                            <td style="font-size:60px; color:#2ecc71">__KPASS__</td>
                                        </tr>
                                        <tr>
                                            <td><span style="color: #999999;font-size:12px">Pass</span></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </td>
                        </tr>

                        <tr style="height:25%">
                            <td>
                                <table style="width:100%">
                                    <tbody>
                                        <tr style="height:70%;font-size:25px" align="center" valign="middle">
                                            <td style="width: 33%; color:brown">__KTOTAL__</td>
                                            <td style="width: 33%; color:orange">__KSKIP__</td>
                                            <td style="width: 33%; color:#fc6666">__KFAIL__</td>
                                        </tr>
                                        <tr style="height:30%" align="center" valign="top">
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Total</span></td>
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Skip</span></td>
                                            <td style="width: 33%"><span style="color: #999999;font-size:10px">Fail</span></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>

        </div>
        <hr/>
        <div class="row rowcard">
            <div class="col-md-4" style="height:280px;width:auto;">
                <span style="font-weight:bold;color:gray">Suite Status:</span>
                <div id="suiteChartID" style="height:250px;width:auto;"></div>
            </div>
            <div class="col-md-4" style="height:280px;width:auto;">
                <span style="font-weight:bold;color:gray">Test Status:</span>
                <div id="testChartID" style="height:250px;width:auto;"></div>
            </div>
            <div class="col-md-4" style="height:280px;width:auto;">
                <span style="font-weight:bold;color:gray">Keyword Status:</span>
                <div id="keywordChartID" style="height:250px;width:auto;"></div>
            </div>
        </div>
        <hr/>
        <div class="row rowcard">
            <div class="col-md-12" style="height:450px;width:auto;">
                <span style="font-weight:bold;color:gray">Top 10 Suite Performance(sec):</span>
                <div id="suiteBarID" style="height:400px;width:auto;"></div>
            </div>
        </div>
        <hr/>
        <div class="row rowcard">
            <div class="col-md-12" style="height:450px;width:auto;">
                <span style="font-weight:bold;color:gray">Top 10 Test Performance(sec):</span>
                <div id="testsBarID" style="height:400px;width:auto;"> </div>
            </div>
        </div>
        <hr/>
        <div class="row rowcard" __KHIDE__>
            <div class="col-md-12" style="height:450px;width:auto;">
                <span style="font-weight:bold;color:gray">Top 10 Keywords Performance(sec):</span>
                <div id="keywordsBarID" style="height:400px;width:auto;"></div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12" style="height:25px;width:auto;">
                <p class="text-muted" style="text-align:center;font-size:9px">
                    <a href="https://github.com/adiralashiva8/robotframework-metrics" target="_blank" style="color:gray">robotframework-metrics</a>
                </p>
            </div>
        </div>

       <script>
            window.onload = function(){
                executeDataTable('#sm',6);
                executeDataTable('#tm',3);
                executeDataTable('#km',3);
                createPieChart(__SPASS__,__SFAIL__,__SSKIP__,'suiteChartID','Suite Status:');
                createBarGraph('#sm',0,6,10,'suiteBarID','Elapsed Time (s) ','Suite');
                createPieChart(__TPASS__,__TFAIL__,__TSKIP__,'testChartID','Tests Status:');
                createBarGraph('#tm',1,3,10,'testsBarID','Elapsed Time (s) ','Test');
                createPieChart(__KPASS__,__KFAIL__,__KSKIP__,'keywordChartID','Keywords Status:');
                createBarGraph('#km',1,3,10,'keywordsBarID','Elapsed Time (s) ','Keyword');
            };
       </script>
       <script>
            function openInNewTab(url,element_id) {
                var element_id= element_id;
                var win = window.open(url, '_blank');
                win.focus();
                $('body').scrollTo(element_id);
            }
        </script>
    </div>
    """

    dashboard_content = dashboard_content.replace("__TIME__", str(elapsedtime))
    dashboard_content = dashboard_content.replace("__GENERATED-BY__",
                                                  str(generator))
    dashboard_content = dashboard_content.replace("__STOTAL__",
                                                  str(total_suite))
    dashboard_content = dashboard_content.replace("__SPASS__",
                                                  str(passed_suite))
    dashboard_content = dashboard_content.replace("__SFAIL__",
                                                  str(failed_suite))
    dashboard_content = dashboard_content.replace("__SSKIP__",
                                                  str(skipped_suite))
    dashboard_content = dashboard_content.replace("__TTOTAL__", str(total))
    dashboard_content = dashboard_content.replace("__TPASS__", str(passed))
    dashboard_content = dashboard_content.replace("__TFAIL__", str(failed))
    dashboard_content = dashboard_content.replace("__TSKIP__", str(skipped))
    dashboard_content = dashboard_content.replace("__KTOTAL__",
                                                  str(total_keywords))
    dashboard_content = dashboard_content.replace("__KPASS__",
                                                  str(passed_keywords))
    dashboard_content = dashboard_content.replace("__KFAIL__",
                                                  str(failed_keywords))
    dashboard_content = dashboard_content.replace("__KSKIP__",
                                                  str(skipped_keywords))
    dashboard_content = dashboard_content.replace("__KHIDE__",
                                                  str(hide_keyword))

    page_content_div.append(BeautifulSoup(dashboard_content, 'html.parser'))

    ### ============================ END OF DASHBOARD ============================================ ####
    logging.info("2 of 4: Capturing suite metrics...")
    ### ============================ START OF SUITE METRICS ======================================= ####

    # Tests div
    suite_div = soup.new_tag('div')
    suite_div["id"] = "suiteMetrics"
    suite_div["class"] = "tabcontent"
    page_content_div.insert(50, suite_div)

    test_icon_txt = """
                    <h4><b><i class="fa fa-table"></i> Suite Metrics</b></h4>
                    <hr></hr>
                    """
    suite_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # Create table tag
    table = soup.new_tag('table')
    table["id"] = "sm"
    table["class"] = "table row-border tablecard"
    suite_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Suite Name"
    tr.insert(0, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Total"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Pass"
    tr.insert(3, th)

    th = soup.new_tag('th')
    th.string = "Fail"
    tr.insert(4, th)

    th = soup.new_tag('th')
    th.string = "Fail"
    tr.insert(5, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(6, th)

    suite_tbody = soup.new_tag('tbody')
    table.insert(11, suite_tbody)

    result.visit(SuiteResults(soup, suite_tbody, log_name, opts.fullsuitename))

    test_icon_txt = """
    <div class="row">
        <div class="col-md-12" style="height:25px;width:auto;"></div>
    </div>
    """
    suite_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    ### ============================ END OF SUITE METRICS ============================================ ####
    logging.info("3 of 4: Capturing test metrics...")
    ### ============================ START OF TEST METRICS ======================================= ####

    # Tests div
    tm_div = soup.new_tag('div')
    tm_div["id"] = "testMetrics"
    tm_div["class"] = "tabcontent"
    page_content_div.insert(100, tm_div)

    test_icon_txt = """
    <h4><b><i class="fa fa-table"></i> Test Metrics</b></h4>
    <hr></hr>
    """
    tm_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # Create table tag
    table = soup.new_tag('table')
    table["id"] = "tm"
    table["class"] = "table row-border tablecard"
    tm_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Suite Name"
    tr.insert(0, th)

    th = soup.new_tag('th')
    th.string = "Test Case"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(3, th)

    th = soup.new_tag('th')
    th.string = "Error Message"
    tr.insert(4, th)

    if opts.showtags == "True":
        th = soup.new_tag('th')
        th.string = "Tags"
        tr.insert(5, th)

    test_tbody = soup.new_tag('tbody')
    table.insert(11, test_tbody)

    # GET TEST METRICS
    result.visit(
        TestResults(soup, test_tbody, log_name, opts.fullsuitename,
                    opts.showtags))

    test_icon_txt = """
    <div class="row">
        <div class="col-md-12" style="height:25px;width:auto;"></div>
    </div>
    """
    tm_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    ### ============================ END OF TEST METRICS ============================================ ####
    logging.info("4 of 4: Capturing keyword metrics...")
    ### ============================ START OF KEYWORD METRICS ======================================= ####

    # Keywords div
    km_div = soup.new_tag('div')
    km_div["id"] = "keywordMetrics"
    km_div["class"] = "tabcontent"
    page_content_div.insert(150, km_div)

    keyword_icon_txt = """
    <h4><b><i class="fa fa-table"></i> Keyword Metrics</b></h4>
      <hr></hr>
    """
    km_div.append(BeautifulSoup(keyword_icon_txt, 'html.parser'))

    # Create table tag
    # <table id="myTable">
    table = soup.new_tag('table')
    table["id"] = "km"
    table["class"] = "table row-border tablecard"
    km_div.insert(10, table)

    thead = soup.new_tag('thead')
    table.insert(0, thead)

    tr = soup.new_tag('tr')
    thead.insert(0, tr)

    th = soup.new_tag('th')
    th.string = "Test Case"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Keyword"
    tr.insert(1, th)

    th = soup.new_tag('th')
    th.string = "Status"
    tr.insert(2, th)

    th = soup.new_tag('th')
    th.string = "Time (s)"
    tr.insert(3, th)

    kw_tbody = soup.new_tag('tbody')
    table.insert(1, kw_tbody)

    if opts.ignorekeywords == "True":
        pass
    else:
        if group:
            group.spawn(
                result.visit,
                KeywordResults(soup, kw_tbody, ignore_library, ignore_type))
            group.join()
        else:
            result.visit(
                KeywordResults(soup, kw_tbody, ignore_library, ignore_type))

    test_icon_txt = """
    <div class="row">
        <div class="col-md-12" style="height:25px;width:auto;"></div>
    </div>
    """
    km_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))
    # END OF KEYWORD METRICS

    # START OF LOGS

    # Logs div
    if opts.ignorelogs == "True":
        pass
    else:
        log_div = soup.new_tag('div')
        log_div["id"] = "log"
        log_div["class"] = "tabcontent"
        page_content_div.insert(200, log_div)

        test_icon_txt = """
            <p style="text-align:right">** <b>Report.html</b> and <b>Log.html</b> need to be in current folder in 
            order to display here</p>
        <div class="embed-responsive embed-responsive-4by3">
            <iframe class="embed-responsive-item" src=%s></iframe>
        </div>
        """ % log_name
        log_div.append(BeautifulSoup(test_icon_txt, 'html.parser'))

    # END OF LOGS
    script_text = """
        <script>
            function createPieChart(passed_count, failed_count, skipped_count, ChartID, ChartName){
            var status = [];
            status.push(['Status', 'Percentage']);
            status.push(['PASS',parseInt(passed_count)],['FAIL',parseInt(failed_count)],['SKIP',parseInt(skipped_count)]);
            var data = google.visualization.arrayToDataTable(status);

            var options = {
            pieHole: 0.6,
            legend: 'none',
            chartArea: {width: "95%",height: "90%"},
            colors: ['#2ecc71', '#fc6666', '#ffa500'],
            };

            var chart = new google.visualization.PieChart(document.getElementById(ChartID));
            chart.draw(data, options);
        }
        </script>
        <script>
           function createBarGraph(tableID,keyword_column,time_column,limit,ChartID,Label,type){
            var status = [];
            css_selector_locator = tableID + ' tbody >tr'
            var rows = $(css_selector_locator);
            var columns;
            var myColors = [
                '#4F81BC',
                '#C0504E',
                '#9BBB58',
                '#24BEAA',
                '#8064A1',
                '#4AACC5',
                '#F79647',
                '#815E86',
                '#76A032',
                '#34558B'
            ];
            status.push([type, Label,{ role: 'annotation'}, {role: 'style'}]);
            for (var i = 0; i < rows.length; i++) {
                if (i == Number(limit)){
                    break;
                }
                //status = [];
                name_value = $(rows[i]).find('td');

                time=($(name_value[Number(time_column)]).html()).trim();
                keyword=($(name_value[Number(keyword_column)]).html()).trim();
                status.push([keyword,parseFloat(time),parseFloat(time),myColors[i]]);
              }
              var data = google.visualization.arrayToDataTable(status);

              var options = {
                legend: 'none',
                chartArea: {width: "92%",height: "75%"},
                bar: {
                    groupWidth: '90%'
                },
                annotations: {
                    alwaysOutside: true,
                    textStyle: {
                    fontName: 'Comic Sans MS',
                    fontSize: 12,
                    //bold: true,
                    italic: true,
                    color: "black",     // The color of the text.
                    },
                },
                hAxis: {
                    textStyle: {
                        //fontName: 'Arial',
                        fontName: 'Comic Sans MS',
                        fontSize: 10,
                    }
                },
                vAxis: {
                    gridlines: { count: 10 },
                    textStyle: {
                        fontName: 'Comic Sans MS',
                        fontSize: 10,
                    }
                },
              };

                // Instantiate and draw the chart.
                var chart = new google.visualization.ColumnChart(document.getElementById(ChartID));
                chart.draw(data, options);
             }

        </script>

     <script>
      function executeDataTable(tabname,sortCol) {
        var fileTitle;
        switch(tabname) {
            case "#sm":
                fileTitle = "SuiteMetrics";
                break;
            case "#tm":
                fileTitle =  "TestMetrics";
                break;
            case "#km":
                fileTitle =  "KeywordMetrics";
                break;
            default:
                fileTitle =  "metrics";
        }

        $(tabname).DataTable(
            {
                retrieve: true,
                "order": [[ Number(sortCol), "desc" ]],
                dom: 'l<".margin" B>frtip',
                "aoColumnDefs": [ {
                    "aTargets": [ -1, -2 ],
                    "mRender": function ( data, type, full ) {
                        return $("<div/>").html(data).text(); 
                    }
                } ],
                buttons: [
                    {
                        extend:    'copyHtml5',
                        text:      '<i class="fa fa-files-o"></i>',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        titleAttr: 'Copy',
                        exportOptions: {
                            columns: ':visible'
                        }
					},

                    {
                        extend:    'csvHtml5',
                        text:      '<i class="fa fa-file-text-o"></i>',
                        titleAttr: 'CSV',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        exportOptions: {
                            columns: ':visible'
                        }
                    },

                    {
                        extend:    'excelHtml5',
                        text:      '<i class="fa fa-file-excel-o"></i>',
                        titleAttr: 'Excel',
                        filename: function() {
                            return fileTitle + '-' + new Date().toLocaleString();
                        },
                        exportOptions: {
                            columns: ':visible'
                        }
                    },
                    {
                        extend:    'print',
                        text:      '<i class="fa fa-print"></i>',
                        titleAttr: 'Print',
                        exportOptions: {
                            columns: ':visible',
                            alignment: 'left',
                        }
                    },
                    {
                        extend:    'colvis',
                        collectionLayout: 'fixed two-column',
                        text:      '<i class="fa fa-low-vision"></i>',
                        titleAttr: 'Hide Column',
                        exportOptions: {
                            columns: ':visible'
                        },
                        postfixButtons: [ 'colvisRestore' ]
                    },
                ],
                columnDefs: [ {
                    visible: false,
                } ]
            }
        );
    }
     </script>
    <script>
      function openPage(pageName,elmnt,color) {
        var i, tabcontent, tablinks;
        tabcontent = document.getElementsByClassName("tabcontent");
        for (i = 0; i < tabcontent.length; i++) {
            tabcontent[i].style.display = "none";
        }
        tablinks = document.getElementsByClassName("tablink");
        for (i = 0; i < tablinks.length; i++) {
            tablinks[i].style.color = "";
        }
        document.getElementById(pageName).style.display = "block";
        elmnt.style.color = color;

    }
    // Get the element with id="defaultOpen" and click on it
    document.getElementById("defaultOpen").click();
     </script>
     <script>
     // Get the element with id="defaultOpen" and click on it
    document.getElementById("defaultOpen").click();
    </script>
    <script>
        $(window).on('load',function(){$('.loader').fadeOut();});
    </script>
    """

    body.append(BeautifulSoup(script_text, 'html.parser'))

    # WRITE TO RF_METRICS_REPORT.HTML

    # Write output as html file
    with open(result_file, 'w') as outfile:
        outfile.write(soup.prettify())

    logging.info(
        "Results file created successfully and can be found at {}".format(
            result_file))
Beispiel #16
0
 def __init__(self):
     Greenlet.__init__(self)
     self.subjobs = Group()
     self.pool = None
Beispiel #17
0
 def __init__(self, itercase, casefile):
     self.itercase = itercase
     self.result_set = Results()
     self.result_set.casefile = casefile
     self.runner = Group()
     self.json_mode = False
Beispiel #18
0
 def all(self):
     group = Group()
     group.spawn(self.api_calls)
     group.spawn(self.visit)
     group.join()
Beispiel #19
0
    @classmethod
    def care_reset_sensor(cls, vac):
        return {'code': vac.send('reset_consumable', ['sensor_dirty_time'])}


class InMsg(list):
    def __init__(self, data, to, **kwargs):
        super(InMsg, self).__init__(**kwargs)
        self.extend(data)
        self.to = to


class OutMsg(dict):
    def __init__(self, data, to, **kwargs):
        super(OutMsg, self).__init__(**kwargs)
        self.update(data)
        self.to = to


if __name__ == '__main__':

    server = StreamServer((args.host, args.port), socket_incoming_connection)
    logger.debug('Starting server on %s %s' % (args.host, args.port))

    services = Group()
    services.spawn(server.serve_forever)
    services.spawn(vacuum_commands_handler, args.ip, args.token, receive)
    services.spawn(socket_msg_sender, sockets, send)
    services.join()
Beispiel #20
0
    def create_connection(self, address, timeout=10):

        ip_list = dnslib.dnsQuery(address[0])

        # 尝试连接缓存
        route_list = self.get_route_order_ping(address[0], address[1], None)
        if route_list:
            try:
                route = route_list[0]
                hit_ip = route['hit_ip']

                if hit_ip in ip_list:
                    cache_timeout = route['tcp_ping']

                    if cache_timeout < 1000:
                        cache_timeout = cache_timeout * 2
                    else:
                        cache_timeout = cache_timeout + 1000
                    cache_timeout = int(math.ceil(cache_timeout / 1000.0))

                    start_time = int(time.time() * 1000)
                    sock = self._direct_create_connection(
                        address, hit_ip, cache_timeout)
                    t = int(time.time() * 1000) - start_time
                    logging.debug(
                        u'[upstream][RouteCache]%s 缓存记录 连接 %s(%s):%s 命中。time:%s'
                        % (self.get_display_name(), address[0], hit_ip,
                           address[1], t))
                    self.update_route_ping(address[0], address[1], t, hit_ip)
                    return sock
                else:
                    logging.debug(
                        u'[upstream][RouteCache]%s 缓存记录 连接 %s(%s):%s IP 不匹配,放弃缓存。'
                        % (self.get_display_name(), address[0], hit_ip,
                           address[1]))
            except:
                t = int(time.time() * 1000) - start_time
                info = traceback.format_exc()
                logging.debug(
                    u'[upstream][RouteCache]%s 缓存记录 连接 %s(%s):%s 失败。time:%s' %
                    (self.get_display_name(), address[0], hit_ip, address[1],
                     t))
                logging.debug('%s\r\n\r\n' % info)

        # 缓存失败,连接全部
        evt = Event()
        group = Group()
        aync_task = DirectAsyncTask(evt, None, group)

        for ip in ip_list:
            group.add(
                gevent.spawn(self._create_connection, aync_task, address, ip,
                             timeout))

        # 所有连接失败时发出通知
        gevent.spawn(self._create_connection_all_end, aync_task)

        evt.wait()
        if aync_task.sock:
            return aync_task.sock
        else:
            raise UpstreamConnectError()
Beispiel #21
0
def parallel_requests():
    group = Group()
    yield group
    group.join()
Beispiel #22
0
def Groupspawn():
    greenlet = Group()
    greenlet.spawn(green1, "green1", " so green")
    greenlet.spawn(green2, "green2")
    greenlet.spawn(green3, "green3")
    greenlet.join()
                        sys.stderr.write("max changes polled\n")
                        break

                    lastTransactionID = R["lastTransactionID"]
                    if lastTransactionID != self.sinceTransactionID:
                        self.sinceTransactionID = lastTransactionID
                        params = {
                            "sinceTransactionID": self.sinceTransactionID
                        }
                        r = AccountChanges(accountID=accountID, params=params)

                    gevent.sleep(15)


# manage asynchronous tasks
gr = Group()


def events_exceptionhandler(g):
    """create a new greenlet."""
    logger.info("restart greenlet %s", g.__class__.__name__)
    print("Restart {}".format(g.__class__.__name__))
    x = g.__class__(m=5)
    gr.discard(g)
    x.link_exception(events_exceptionhandler)
    x.start()
    gr.add(x)
    gr.join()


p_stream = StreamingPrices(instruments=clargs.instruments,
Beispiel #24
0
 def _run(self, *args, **kwargs):
     group = Group()
     for task in self._tasks:
         group.start(Greenlet(task))
     group.join(raise_error=True)
Beispiel #25
0
 def __init__(self, db: sql.Connection):
     self.cursor = db.cursor()
     self.fetch_one = self.cursor.fetchone
     self.fetch_all = self.cursor.fetchall
     self.fetch_many = self.cursor.fetchmany
     self.greenlet_group = Group()
Beispiel #26
0
    def exportm3u(self, hostport, _bytearray=bytearray, **params):
        '''
        Exports m3u playlist
        :params: dict with keys: path='', empty_header=False, archive=False, parse_url=True, header=None, query=None
        '''
        def line_generator(item):
            '''
            Generates EXTINF line with url
            '''
            item = item.copy(
            )  # {'group': XXX, 'tvg': XXX, 'logo': XXX, 'name': XXX, 'tvgid': XXX, 'url': XXX}
            params.update({
                'name':
                quote(
                    ensure_str(
                        item.get('name').replace('"', "'").replace(',', '.')),
                    '')
            })
            url = item['url']
            if not params.get('parse_url'):
                if params.get('path').endswith(
                        'channel'):  # For plugins  channel name maping
                    params.update({'value': url})
                    item['url'] = urlunparse(
                        u'{schema};{netloc};{path}/{value}.{ext};;{query};'.
                        format(**params).split(';'))
                elif url.startswith(('http://', 'https://')) and url.endswith(
                    ('.acelive', '.acestream', '.acemedia',
                     '.torrent')):  # For .acelive and .torrent
                    params.update({'value': quote(url, '')})
                    item['url'] = urlunparse(
                        u'{schema};{netloc};/url/{value}/{name}.{ext};;{query};'
                        .format(**params).split(';'))
                elif url.startswith('infohash://'):  # For INFOHASHes
                    params.update({'value': url.split('/')[2]})
                    item['url'] = urlunparse(
                        u'{schema};{netloc};/infohash/{value}/{name}.{ext};;{query};'
                        .format(**params).split(';'))
                elif url.startswith('acestream://'):  # For PIDs
                    params.update({'value': url.split('/')[2]})
                    item['url'] = urlunparse(
                        u'{schema};{netloc};/content_id/{value}/{name}.{ext};;{query};'
                        .format(**params).split(';'))
                elif params.get('archive') and url.isdigit(
                ):  # For archive channel id's
                    item['url'] = urlunparse(
                        u'{schema};{netloc};/archive/play?id={url};;{query};'.
                        format(**params).split(';'))
                elif not params.get('archive') and url.isdigit(
                ):  # For channel id's
                    item['url'] = urlunparse(
                        u'{schema};{netloc};/channels/play?id={url};;{query};'.
                        format(**params).split(';'))

            return self.m3uchanneltemplate.format(**item)

        params.update({
            'schema': 'http',
            'netloc': hostport
        })  # Adding ts:// after http:// for some players
        params.update(
            {'ext': parse_qs(params.get('query', '')).get('ext', ['ts'])[0]})
        header = params.get('header')
        if header is None:
            header = self.m3uemptyheader if params.get(
                'empty_header') else self.m3uheader
        return _bytearray(
            header +
            ''.join(Group().map(line_generator, self.sort(self.itemlist))),
            'utf-8')
Beispiel #27
0
    def stop_users(self, user_count, stop_rate=None):
        """
        Stop `user_count` weighted users at a rate of `stop_rate`
        """
        if user_count == 0 or stop_rate == 0:
            return

        bucket = self.weight_users(user_count)
        user_count = len(bucket)
        to_stop = []
        for user_greenlet in self.user_greenlets:
            try:
                user = user_greenlet.args[0]
            except IndexError:
                logger.error(
                    "While stopping users, we encountered a user that didnt have proper args %s",
                    user_greenlet)
                continue
            for user_class in bucket:
                if isinstance(user, user_class):
                    to_stop.append(user)
                    bucket.remove(user_class)
                    break

        if not to_stop:
            return

        if stop_rate is None or stop_rate >= user_count:
            sleep_time = 0
            logger.info("Stopping %i users" % (user_count))
        else:
            sleep_time = 1.0 / stop_rate
            logger.info("Stopping %i users at rate of %g users/s" %
                        (user_count, stop_rate))

        async_calls_to_stop = Group()
        stop_group = Group()

        while True:
            user_to_stop: User = to_stop.pop(
                random.randint(0,
                               len(to_stop) - 1))
            logger.debug("Stopping %s" % user_to_stop._greenlet.name)
            if user_to_stop._greenlet is greenlet.getcurrent():
                # User called runner.quit(), so dont block waiting for killing to finish"
                user_to_stop._group.killone(user_to_stop._greenlet,
                                            block=False)
            elif self.environment.stop_timeout:
                async_calls_to_stop.add(
                    gevent.spawn_later(0, User.stop, user_to_stop,
                                       force=False))
                stop_group.add(user_to_stop._greenlet)
            else:
                async_calls_to_stop.add(
                    gevent.spawn_later(0, User.stop, user_to_stop, force=True))
            if to_stop:
                gevent.sleep(sleep_time)
            else:
                break

        async_calls_to_stop.join()

        if not stop_group.join(timeout=self.environment.stop_timeout):
            logger.info(
                "Not all users finished their tasks & terminated in %s seconds. Stopping them..."
                % self.environment.stop_timeout)
            stop_group.kill(block=True)

        logger.info("%i Users have been stopped, %g still running" %
                    (user_count, len(self.user_greenlets)))
Beispiel #28
0
collection = db.Train


def old_new(old_document):
    try:
        tags_list = old_document.get('Tags').split()
        old_document.update({'Tags': tags_list})
        result = collection.update({'_id': old_document.get('_id')},
                                   old_document)
    except:
        pass


cursor = collection.find()

g1 = Group()

TASKS = 1000

for i, old_document in enumerate(cursor):

    work = gevent.spawn(old_new, old_document)
    g1.add(work)

    if i % TASKS == 0:
        print i
        g1.join()

g1.join()
print('work done')
Beispiel #29
0
 def __init__(self, *args):
     super().__init__(*args)
     self.callback_dict = {}
     self.greenlets = Group()
     self.greenlets.spawn(self.onMessage)
Beispiel #30
0
    def start(self, user_count: int, spawn_rate: float, **kwargs) -> None:
        num_workers = len(self.clients.ready) + len(self.clients.running) + len(self.clients.spawning)
        if not num_workers:
            logger.warning(
                "You are running in distributed mode but have no worker servers connected. "
                "Please connect workers prior to swarming."
            )
            return

        for user_class in self.user_classes:
            if self.environment.host is not None:
                user_class.host = self.environment.host

        self.target_user_classes_count = weight_users(self.user_classes, user_count)

        self.spawn_rate = spawn_rate

        logger.info(
            "Sending spawn jobs of %d users at %.2f spawn rate to %d ready clients"
            % (user_count, spawn_rate, num_workers)
        )

        worker_spawn_rate = float(spawn_rate) / (num_workers or 1)
        if worker_spawn_rate > 100:
            logger.warning(
                "Your selected spawn rate is very high (>100/worker), and this is known to sometimes cause issues. Do you really need to ramp up that fast?"
            )

        # Since https://github.com/locustio/locust/pull/1621, the master is responsible for dispatching and controlling
        # the total spawn rate which is more CPU intensive for the master. The number 200 is a little arbitrary as the computational
        # load on the master greatly depends on the number of workers and the number of user classes. For instance,
        # 5 user classes and 5 workers can easily do 200/s. However, 200/s with 50 workers and 20 user classes will likely make the
        # dispatch very slow because of the required computations. I (@mboutet) doubt that many Locust's users are
        # spawning that rapidly. If so, then they'll likely open issues on GitHub in which case I'll (@mboutet) take a look.
        if spawn_rate > 200:
            logger.warning(
                "Your selected total spawn rate is quite high (>200), and this is known to sometimes cause performance issues on the master. "
                "Do you really need to ramp up that fast? If so and if encountering performance issues on the master, free to open an issue."
            )

        if self.state != STATE_RUNNING and self.state != STATE_SPAWNING:
            self.stats.clear_all()
            self.exceptions = {}
            self.environment.events.test_start.fire(environment=self.environment)
            if self.environment.shape_class:
                self.environment.shape_class.reset_time()

        self.update_state(STATE_SPAWNING)

        try:
            for dispatched_users in UsersDispatcher(
                worker_nodes=self.clients.ready + self.clients.running + self.clients.spawning,
                user_classes_count=self.target_user_classes_count,
                spawn_rate=spawn_rate,
            ):
                dispatch_greenlets = Group()
                for worker_node_id, worker_user_classes_count in dispatched_users.items():
                    data = {
                        "timestamp": time.time(),
                        "user_classes_count": worker_user_classes_count,
                        "host": self.environment.host,
                        "stop_timeout": self.environment.stop_timeout,
                    }
                    dispatch_greenlets.add(
                        gevent.spawn_later(
                            0,
                            self.server.send_to_client,
                            Message("spawn", data, worker_node_id),
                        )
                    )
                dispatched_user_count = sum(map(sum, map(methodcaller("values"), dispatched_users.values())))
                logger.debug(
                    "Sending spawn messages for %g total users to %i client(s)",
                    dispatched_user_count,
                    len(dispatch_greenlets),
                )
                dispatch_greenlets.join()

                logger.debug(
                    "Currently spawned users: %s" % _format_user_classes_count_for_log(self.reported_user_classes_count)
                )

        except KeyboardInterrupt:
            # We need to catch keyboard interrupt. Otherwise, if KeyboardInterrupt is received while in
            # a gevent.sleep inside the dispatch_users function, locust won't gracefully shutdown.
            self.quit()

        # Wait a little for workers to report their users to the master
        # so that we can give an accurate log message below and fire the `spawning_complete` event
        # when the user count is really at the desired value.
        timeout = gevent.Timeout(self._wait_for_workers_report_after_ramp_up())
        timeout.start()
        try:
            while self.user_count != self.target_user_count:
                gevent.sleep()
        except gevent.Timeout:
            pass
        finally:
            timeout.cancel()

        self.environment.events.spawning_complete.fire(user_count=sum(self.target_user_classes_count.values()))

        logger.info("All users spawned: %s" % _format_user_classes_count_for_log(self.reported_user_classes_count))