diff options
Diffstat (limited to 'yardstick')
17 files changed, 1764 insertions, 191 deletions
diff --git a/yardstick/benchmark/core/report.py b/yardstick/benchmark/core/report.py index a484a49f3..0bc392fe5 100644 --- a/yardstick/benchmark/core/report.py +++ b/yardstick/benchmark/core/report.py @@ -56,10 +56,10 @@ class JSTree(object): """Format the data into the required format for jsTree. The data format expected is a list of key-value pairs which represent - the data and name for each metric e.g.: + the data and label for each metric e.g.: - [{'data': [0, ], 'name': 'tg__0.DropPackets'}, - {'data': [548, ], 'name': 'tg__0.LatencyAvg.5'},] + [{'data': [0, ], 'label': 'tg__0.DropPackets'}, + {'data': [548, ], 'label': 'tg__0.LatencyAvg.5'},] This data is converted into the format required for jsTree to group and display the metrics in a hierarchial fashion, including creating a @@ -77,7 +77,7 @@ class JSTree(object): self.jstree_data = [] for item in data: - self._create_node(item["name"]) + self._create_node(item["label"]) return self.jstree_data @@ -85,7 +85,7 @@ class JSTree(object): class Report(object): """Report commands. - Set of commands to manage benchmark tasks. + Set of commands to manage reports. """ def __init__(self): @@ -124,10 +124,12 @@ class Report(object): else: raise KeyError("Task ID or Test case not found.") - @cliargs("task_id", type=str, help=" task id", nargs=1) - @cliargs("yaml_name", type=str, help=" Yaml file Name", nargs=1) - def generate(self, args): - """Start report generation.""" + def _generate_common(self, args): + """Actions that are common to both report formats. + + Create the necessary data structure for rendering + the report templates. + """ self._validate(args.yaml_name[0], args.task_id[0]) self.db_fieldkeys = self._get_fieldkeys() @@ -135,7 +137,7 @@ class Report(object): self.db_task = self._get_tasks() field_keys = [] - temp_series = [] + datasets = [] table_vals = {} field_keys = [encodeutils.to_utf8(field['fieldKey']) @@ -143,37 +145,42 @@ class Report(object): for key in field_keys: self.Timestamp = [] - series = {} values = [] for task in self.db_task: task_time = encodeutils.to_utf8(task['time']) if not isinstance(task_time, str): task_time = str(task_time, 'utf8') + if not isinstance(key, str): key = str(key, 'utf8') task_time = task_time[11:] head, _, tail = task_time.partition('.') task_time = head + "." + tail[:6] self.Timestamp.append(task_time) if task[key] is None: - values.append('') - elif isinstance(task[key], (int, float)) is True: + values.append(None) + elif isinstance(task[key], (int, float)): values.append(task[key]) else: values.append(ast.literal_eval(task[key])) + datasets.append({'label': key, 'data': values}) table_vals['Timestamp'] = self.Timestamp table_vals[key] = values - series['name'] = key - series['data'] = values - temp_series.append(series) + + return datasets, table_vals + + @cliargs("task_id", type=str, help=" task id", nargs=1) + @cliargs("yaml_name", type=str, help=" Yaml file Name", nargs=1) + def generate(self, args): + """Start report generation.""" + datasets, table_vals = self._generate_common(args) template_dir = consts.YARDSTICK_ROOT_PATH + "yardstick/common" template_environment = jinja2.Environment( autoescape=False, - loader=jinja2.FileSystemLoader(template_dir), - trim_blocks=False) + loader=jinja2.FileSystemLoader(template_dir)) context = { - "series": temp_series, + "datasets": datasets, "Timestamps": self.Timestamp, "task_id": self.task_id, "table": table_vals, @@ -184,4 +191,31 @@ class Report(object): with open(consts.DEFAULT_HTML_FILE, "w") as file_open: file_open.write(template_html.render(context)) - print("Report generated. View /tmp/yardstick.htm") + print("Report generated. View %s" % consts.DEFAULT_HTML_FILE) + + @cliargs("task_id", type=str, help=" task id", nargs=1) + @cliargs("yaml_name", type=str, help=" Yaml file Name", nargs=1) + def generate_nsb(self, args): + """Start NSB report generation.""" + datasets, table_vals = self._generate_common(args) + jstree_data = JSTree().format_for_jstree(datasets) + + template_dir = consts.YARDSTICK_ROOT_PATH + "yardstick/common" + template_environment = jinja2.Environment( + autoescape=False, + loader=jinja2.FileSystemLoader(template_dir), + lstrip_blocks=True) + + context = { + "Timestamps": self.Timestamp, + "task_id": self.task_id, + "table": table_vals, + "jstree_nodes": jstree_data, + } + + template_html = template_environment.get_template("nsb_report.html.j2") + + with open(consts.DEFAULT_HTML_FILE, "w") as file_open: + file_open.write(template_html.render(context)) + + print("Report generated. View %s" % consts.DEFAULT_HTML_FILE) diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index 1dfd6c31e..477dbcc57 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -11,6 +11,7 @@ import sys import os from collections import OrderedDict +import six import yaml import atexit import ipaddress @@ -313,7 +314,7 @@ class Task(object): # pragma: no cover return {k: self._parse_options(v) for k, v in op.items()} elif isinstance(op, list): return [self._parse_options(v) for v in op] - elif isinstance(op, str): + elif isinstance(op, six.string_types): return self.outputs.get(op[1:]) if op.startswith('$') else op else: return op diff --git a/yardstick/cmd/commands/report.py b/yardstick/cmd/commands/report.py index 47bf22a1f..4f057a05d 100644 --- a/yardstick/cmd/commands/report.py +++ b/yardstick/cmd/commands/report.py @@ -1,7 +1,7 @@ ############################################################################## -# Copyright (c) 2017 Rajesh Kudaka. +# Copyright (c) 2017 Rajesh Kudaka <4k.rajesh@gmail.com> +# Copyright (c) 2018 Intel Corporation. # -# Author: Rajesh Kudaka (4k.rajesh@gmail.com) # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at @@ -10,11 +10,7 @@ """ Handler for yardstick command 'report' """ -from __future__ import print_function - -from __future__ import absolute_import - -from yardstick.benchmark.core.report import Report +from yardstick.benchmark.core import report from yardstick.cmd.commands import change_osloobj_to_paras from yardstick.common.utils import cliargs @@ -22,12 +18,19 @@ from yardstick.common.utils import cliargs class ReportCommands(object): # pragma: no cover """Report commands. - Set of commands to manage benchmark tasks. + Set of commands to manage reports. """ @cliargs("task_id", type=str, help=" task id", nargs=1) @cliargs("yaml_name", type=str, help=" Yaml file Name", nargs=1) def do_generate(self, args): - """Start a benchmark scenario.""" + """Generate a report.""" + param = change_osloobj_to_paras(args) + report.Report().generate(param) + + @cliargs("task_id", type=str, help=" task id", nargs=1) + @cliargs("yaml_name", type=str, help=" Yaml file Name", nargs=1) + def do_generate_nsb(self, args): + """Generate a report using the NSB template.""" param = change_osloobj_to_paras(args) - Report().generate(param) + report.Report().generate_nsb(param) diff --git a/yardstick/common/nsb_report.css b/yardstick/common/nsb_report.css index 0c47791e2..2beb91c53 100644 --- a/yardstick/common/nsb_report.css +++ b/yardstick/common/nsb_report.css @@ -19,7 +19,7 @@ table { } header { - font-family: Frutiger; + font-family: Frutiger, "Helvetica Neue", Helvetica, Arial, sans-serif; clear: left; text-align: center; } diff --git a/yardstick/common/nsb_report.html.j2 b/yardstick/common/nsb_report.html.j2 index f1b4ae1c2..a3087d746 100644 --- a/yardstick/common/nsb_report.html.j2 +++ b/yardstick/common/nsb_report.html.j2 @@ -15,12 +15,17 @@ <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.5/themes/default/style.min.css"> - <link rel="stylesheet" href="{{template_dir}}/nsb_report.css"> - <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/themes/default/style.min.css"> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> - <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script> - <script src="https://code.highcharts.com/highcharts.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/jstree.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script> + <style> + {% include 'nsb_report.css' %} + </style> + <script> + {% include 'nsb_report.js' %} + </script> </head> <body> @@ -31,12 +36,12 @@ <h4>Report of {{task_id}} Generated</h4> </header> </div> - <div class="row" style="height:500px"> + <div class="row"> <div class="col-md-2 control-pane"> <div id="data_selector"></div> </div> <div class="col-md-10 data-pane"> - <div id="graph"></div> + <canvas id="cnvGraph" style="width: 100%; height: 500px"></canvas> </div> </div> <div class="row"> @@ -47,112 +52,29 @@ </div> <script> - var arr, tab, tr, td, tbody, keys, key, curr_data; + var arr, jstree_data, timestamps; arr = {{table|safe}}; - - tab = document.getElementsByTagName('table')[0]; - tbody = document.createElement('tbody'); - keys = Object.keys(arr); - // for each metric - for (var i = 0; i < keys.length; i++) { - tr = document.createElement('tr'); - td = document.createElement('td'); - key = keys[i]; - td.append(key); - tr.append(td); - curr_data = arr[key]; - // add each piece of data as its own column - for (var j = 0; j < curr_data.length; j++) { - td = document.createElement('td'); - td.append(curr_data[j]); - tr.append(td); - } - tbody.append(tr); - } - tab.appendChild(tbody); + timestamps = {{Timestamps|safe}}; + jstree_data = {{jstree_nodes|safe}}; $(function() { - $('#data_selector').jstree({ - plugins: ['checkbox'], - checkbox: { - three_state: false, - whole_node: true, - tie_selection: false, - }, - core: { - themes: { - icons: false, - stripes: true, - }, - data: {{jstree_nodes|safe}}, - }, - }); + create_table(arr); + create_tree(jstree_data); + var objGraph = create_graph($('#cnvGraph'), timestamps); $('#data_selector').on('check_node.jstree uncheck_node.jstree', function(e, data) { - var selected_leaves = []; + var selected_datasets = []; for (var i = 0; i < data.selected.length; i++) { var node = data.instance.get_node(data.selected[i]); if (node.children.length == 0) { - var point = {name: node.id, data: arr[node.id]}; - selected_leaves.push(point); - } - } - - $('#graph').highcharts({ - title: { - text: 'Yardstick Graphs', - x: -20, //center - }, - chart: { - marginLeft: 400, - zoomType: 'x', - type: 'spline', - }, - xAxis: { - crosshair: { - width: 1, - color: 'black', - }, - title: { - text: 'Timestamp', - }, - categories: {{Timestamps|safe}}, - }, - yAxis: { - crosshair: { - width: 1, - color: 'black', - }, - plotLines: [{ - value: 0, - width: 1, - color: '#808080', - }], - }, - plotOptions: { - series: { - showCheckbox: false, - visible: false, - }, - }, - tooltip: { - valueSuffix: '', - }, - legend: { - enabled: true, - }, - series: selected_leaves, - }); - - var chart = $('#graph').highcharts(); - for (var i = 0; i < chart.series.length; i++) { - var series = chart.series[i]; - if (series.visible) { - series.hide(); - } else { - series.show(); + var dataset = { + label: node.id, + data: arr[node.id], + }; + selected_datasets.push(dataset); } } + update_graph(objGraph, selected_datasets); }); }); </script> diff --git a/yardstick/common/nsb_report.js b/yardstick/common/nsb_report.js new file mode 100644 index 000000000..cc5e14ee7 --- /dev/null +++ b/yardstick/common/nsb_report.js @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2017 Rajesh Kudaka <4k.rajesh@gmail.com> + * Copyright (c) 2018 Intel Corporation. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Apache License, Version 2.0 + * which accompanies this distribution, and is available at + * http://www.apache.org/licenses/LICENSE-2.0 + ******************************************************************************/ + +var None = null; + +function create_tree(jstree_data) +{ + $('#data_selector').jstree({ + plugins: ['checkbox'], + checkbox: { + three_state: false, + whole_node: true, + tie_selection: false, + }, + core: { + themes: { + icons: false, + stripes: true, + }, + data: jstree_data, + }, + }); +} + +// may need to pass timestamps too... +function create_table(table_data) +{ + var tab, tr, td, tn, tbody, keys, key, curr_data, val; + // create table + tab = document.getElementsByTagName('table')[0]; + tbody = document.createElement('tbody'); + // for each metric + keys = Object.keys(table_data); + for (var i = 0; i < keys.length; i++) { + key = keys[i]; + tr = document.createElement('tr'); + td = document.createElement('td'); + tn = document.createTextNode(key); + td.appendChild(tn); + tr.appendChild(td); + // add each piece of data as its own column + curr_data = table_data[key]; + for (var j = 0; j < curr_data.length; j++) { + val = curr_data[j]; + td = document.createElement('td'); + tn = document.createTextNode(val === None ? '' : val); + td.appendChild(tn); + tr.appendChild(td); + } + tbody.appendChild(tr); + } + tab.appendChild(tbody); +} + +function create_graph(cnvGraph, timestamps) +{ + return new Chart(cnvGraph, { + type: 'line', + data: { + labels: timestamps, + datasets: [], + }, + options: { + elements: { + line: { + borderWidth: 2, + fill: false, + tension: 0, + }, + }, + scales: { + xAxes: [{ + type: 'category', + }], + yAxes: [{ + type: 'linear', + }], + }, + tooltips: { + mode: 'point', + intersect: true, + }, + hover: { + mode: 'index', + intersect: false, + animationDuration: 0, + }, + legend: { + position: 'bottom', + labels: { + usePointStyle: true, + }, + }, + animation: { + duration: 0, + }, + responsive: true, + responsiveAnimationDuration: 0, + maintainAspectRatio: false, + }, + }); +} + +function update_graph(objGraph, datasets) +{ + var colors = [ + '#FF0000', // Red + '#228B22', // ForestGreen + '#FF8C00', // DarkOrange + '#00008B', // DarkBlue + '#FF00FF', // Fuchsia + '#9ACD32', // YellowGreen + '#FFD700', // Gold + '#4169E1', // RoyalBlue + '#A0522D', // Sienna + '#20B2AA', // LightSeaGreen + '#8A2BE2', // BlueViolet + ]; + + var points = [ + {s: 'circle', r: 3}, + {s: 'rect', r: 4}, + {s: 'triangle', r: 4}, + {s: 'star', r: 4}, + {s: 'rectRot', r: 5}, + ]; + + datasets.forEach(function(d, i) { + var color = colors[i % colors.length]; + var point = points[i % points.length]; + d.borderColor = color; + d.backgroundColor = color; + d.pointStyle = point.s; + d.pointRadius = point.r; + d.pointHoverRadius = point.r + 1; + }); + objGraph.data.datasets = datasets; + objGraph.update(); +} diff --git a/yardstick/common/report.html.j2 b/yardstick/common/report.html.j2 index ab76510ca..1dc7b1db1 100644 --- a/yardstick/common/report.html.j2 +++ b/yardstick/common/report.html.j2 @@ -15,9 +15,9 @@ <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> - <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> - <script src="https://code.highcharts.com/highcharts.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script> <style> table { @@ -26,7 +26,7 @@ display: block; } header { - font-family: Frutiger; + font-family: Frutiger, "Helvetica Neue", Helvetica, Arial, sans-serif; clear: left; text-align: center; } @@ -47,13 +47,14 @@ </div> </div> <div class="col-md-8"> - <div id="container"></div> + <canvas id="cnvGraph" style="width: 100%; height: 500px"></canvas> </div> </div> </div> <script> - var arr, tab, th, tr, td, tn, row, col, thead, tbody; + var None = null; + var arr, tab, th, tr, td, tn, row, col, thead, tbody, val; arr = {{table|safe}}; tab = document.getElementsByTagName('table')[0]; @@ -64,16 +65,17 @@ tn = document.createTextNode(Object.keys(arr).sort()[col]); th.appendChild(tn); tr.appendChild(th); - thead.appendChild(tr); } + thead.appendChild(tr); tab.appendChild(thead); tbody = document.createElement('tbody'); for (row = 0; row < arr[Object.keys(arr)[0]].length; row++) { tr = document.createElement('tr'); for (col = 0; col < Object.keys(arr).length; col++) { + val = arr[Object.keys(arr).sort()[col]][row]; td = document.createElement('td'); - tn = document.createTextNode(arr[Object.keys(arr).sort()[col]][row]); + tn = document.createTextNode(val === None ? '' : val); td.appendChild(tn); tr.appendChild(td); } @@ -82,38 +84,99 @@ tab.appendChild(tbody); $(function() { - $('#container').highcharts({ - title: { - text: 'Yardstick test results', - x: -20, //center - }, - subtitle: { - text: 'Report of {{task_id}} Task Generated', - x: -20, + var datasets = {{datasets|safe}}; + + var colors = [ + '#FF0000', // Red + '#228B22', // ForestGreen + '#FF8C00', // DarkOrange + '#00008B', // DarkBlue + '#FF00FF', // Fuchsia + '#9ACD32', // YellowGreen + '#FFD700', // Gold + '#4169E1', // RoyalBlue + '#A0522D', // Sienna + '#20B2AA', // LightSeaGreen + '#8A2BE2', // BlueViolet + ]; + + var points = [ + {s: 'circle', r: 3}, + {s: 'rect', r: 4}, + {s: 'triangle', r: 4}, + {s: 'star', r: 4}, + {s: 'rectRot', r: 5}, + ]; + + datasets.forEach(function(d, i) { + var color = colors[i % colors.length]; + var point = points[i % points.length]; + d.borderColor = color; + d.backgroundColor = color; + d.pointStyle = point.s; + d.pointRadius = point.r; + d.pointHoverRadius = point.r + 1; + }); + + new Chart($('#cnvGraph'), { + type: 'line', + data: { + labels: {{Timestamps|safe}}, + datasets: datasets, }, - xAxis: { + options: { + elements: { + line: { + borderWidth: 2, + fill: false, + tension: 0, + }, + }, title: { - text: 'Timestamp', + text: [ + 'Yardstick test results', + 'Report of {{task_id}} Task Generated', + ], + display: true, }, - categories: {{Timestamps|safe}}, - }, - yAxis: { - plotLines: [{ - value: 0, - width: 1, - color: '#808080', - }], - }, - tooltip: { - valueSuffix: '', - }, - legend: { - layout: 'vertical', - align: 'right', - verticalAlign: 'middle', - borderWidth: 0, + scales: { + xAxes: [{ + type: 'category', + scaleLabel: { + display: true, + labelString: 'Timestamp', + }, + }], + yAxes: [{ + type: 'linear', + scaleLabel: { + display: true, + labelString: 'Values', + }, + }], + }, + tooltips: { + mode: 'point', + intersect: true, + }, + hover: { + mode: 'index', + intersect: false, + animationDuration: 0, + }, + legend: { + position: 'right', + labels: { + usePointStyle: true, + }, + }, + animation: { + duration: 0, + }, + responsive: true, + responsiveAnimationDuration: 0, + maintainAspectRatio: false, }, - series: {{series|safe}}, }); }); </script> diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py index 4e7434c68..d41dd028f 100644 --- a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py +++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py @@ -1014,3 +1014,37 @@ class IxNextgen(object): # pragma: no cover '-value', bgp_type) self.ixnet.commit() return obj + + def add_interface(self, vport, ip, mac=None, gateway=None): + """Add protocol interface to the vport""" + log.debug("add_interface: mac='%s', ip='%s', gateway='%s'", mac, ip, + gateway) + obj = self.ixnet.add(vport, 'interface') + self.ixnet.commit() + + if mac is not None: + self.ixnet.setMultiAttribute(obj + '/ethernet', '-macAddress', mac) + + ipv4 = self.ixnet.add(obj, 'ipv4') + self.ixnet.setMultiAttribute(ipv4, '-ip', ip) + + if gateway is not None: + self.ixnet.setMultiAttribute(ipv4, '-gateway', gateway) + + self.ixnet.commit() + + self.ixnet.setMultiAttribute(obj, '-enabled', 'true') + self.ixnet.commit() + + return obj + + def add_static_ipv4(self, iface, vport, start_ip, count, mask='24'): + """Add static IP range to the interface""" + log.debug("add_static_ipv4: start_ip:'%s', count:'%s'", + start_ip, count) + obj = self.ixnet.add(vport + '/protocols/static', 'ip') + + self.ixnet.setMultiAttribute(obj, '-protocolInterface', iface, + '-ipStart', start_ip, '-count', count, + '-mask', mask, '-enabled', 'true') + self.ixnet.commit() diff --git a/yardstick/network_services/traffic_profile/__init__.py b/yardstick/network_services/traffic_profile/__init__.py index 91d8a665f..72a61b6b4 100644 --- a/yardstick/network_services/traffic_profile/__init__.py +++ b/yardstick/network_services/traffic_profile/__init__.py @@ -23,6 +23,7 @@ def register_modules(): 'yardstick.network_services.traffic_profile.http_ixload', 'yardstick.network_services.traffic_profile.ixia_rfc2544', 'yardstick.network_services.traffic_profile.prox_ACL', + 'yardstick.network_services.traffic_profile.prox_irq', 'yardstick.network_services.traffic_profile.prox_binsearch', 'yardstick.network_services.traffic_profile.prox_profile', 'yardstick.network_services.traffic_profile.prox_ramp', diff --git a/yardstick/network_services/traffic_profile/prox_irq.py b/yardstick/network_services/traffic_profile/prox_irq.py new file mode 100644 index 000000000..0ea294914 --- /dev/null +++ b/yardstick/network_services/traffic_profile/prox_irq.py @@ -0,0 +1,48 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" Fixed traffic profile definitions """ + +import logging +import time + +from yardstick.network_services.traffic_profile.prox_profile import ProxProfile + +LOG = logging.getLogger(__name__) + + +class ProxIrqProfile(ProxProfile): + """ + This profile adds a single stream at the beginning of the traffic session + """ + + def __init__(self, tp_config): + super(ProxIrqProfile, self).__init__(tp_config) + + def init(self, queue): + self.queue = queue + self.queue.cancel_join_thread() + + def execute_traffic(self, traffic_generator): + LOG.debug("Prox_IRQ Execute Traffic....") + time.sleep(5) + + def is_ended(self): + return False + + def run_test(self): + """Run the test + """ + + LOG.info("Prox_IRQ ....") diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index e9d83623b..cd3035ef8 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -561,6 +561,41 @@ class ProxSocketHelper(object): tsc = int(ret[3]) return rx, tx, drop, tsc + def irq_core_stats(self, cores_tasks): + """ get IRQ stats per core""" + + stat = {} + core = 0 + task = 0 + for core, task in cores_tasks: + self.put_command("stats task.core({}).task({}).max_irq,task.core({}).task({}).irq(0)," + "task.core({}).task({}).irq(1),task.core({}).task({}).irq(2)," + "task.core({}).task({}).irq(3),task.core({}).task({}).irq(4)," + "task.core({}).task({}).irq(5),task.core({}).task({}).irq(6)," + "task.core({}).task({}).irq(7),task.core({}).task({}).irq(8)," + "task.core({}).task({}).irq(9),task.core({}).task({}).irq(10)," + "task.core({}).task({}).irq(11),task.core({}).task({}).irq(12)" + "\n".format(core, task, core, task, core, task, core, task, + core, task, core, task, core, task, core, task, + core, task, core, task, core, task, core, task, + core, task, core, task)) + in_data_str = self.get_data().split(",") + ret = [try_int(s, 0) for s in in_data_str] + key = "core_" + str(core) + try: + stat[key] = {"cpu": core, "max_irq": ret[0], "bucket_0" : ret[1], + "bucket_1" : ret[2], "bucket_2" : ret[3], + "bucket_3" : ret[4], "bucket_4" : ret[5], + "bucket_5" : ret[6], "bucket_6" : ret[7], + "bucket_7" : ret[8], "bucket_8" : ret[9], + "bucket_9" : ret[10], "bucket_10" : ret[11], + "bucket_11" : ret[12], "bucket_12" : ret[13], + "overflow": ret[10] + ret[11] + ret[12] + ret[13]} + except (KeyError, IndexError): + LOG.error("Corrupted PACKET %s", in_data_str) + + return stat + def multi_port_stats(self, ports): """get counter values from all ports at once""" @@ -754,7 +789,6 @@ class ProxSocketHelper(object): self.put_command("quit_force\n") time.sleep(3) - _LOCAL_OBJECT = object() @@ -836,6 +870,30 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): file_str[1] = self.additional_files[base_name] return '"'.join(file_str) + def _make_core_list(self, inputStr): + + my_input = inputStr.split("core ", 1)[1] + ok_list = set() + + substrs = [x.strip() for x in my_input.split(',')] + for i in substrs: + try: + ok_list.add(int(i)) + + except ValueError: + try: + substr = [int(k.strip()) for k in i.split('-')] + if len(substr) > 1: + startstr = substr[0] + endstr = substr[len(substr) - 1] + for z in range(startstr, endstr + 1): + ok_list.add(z) + except ValueError: + LOG.error("Error in cores list ... resuming ") + return ok_list + + return ok_list + def generate_prox_config_file(self, config_path): sections = [] prox_config = ConfigParser(config_path, sections) @@ -855,6 +913,18 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): if section_data[0] == "mac": section_data[1] = "hardware" + # adjust for range of cores + new_sections = [] + for section_name, section in sections: + if section_name.startswith('core') and section_name.find('$') == -1: + core_list = self._make_core_list(section_name) + for core in core_list: + new_sections.append(["core " + str(core), section]) + else: + new_sections.append([section_name, section]) + + sections = new_sections + # search for dst mac for _, section in sections: for section_data in section: @@ -2067,3 +2137,15 @@ class ProxlwAFTRProfileHelper(ProxProfileHelper): data_helper.latency = self.get_latency() return data_helper.result_tuple, data_helper.samples + + +class ProxIrqProfileHelper(ProxProfileHelper): + + __prox_profile_type__ = "IRQ Query" + + def __init__(self, resource_helper): + super(ProxIrqProfileHelper, self).__init__(resource_helper) + self._cores_tuple = None + self._ports_tuple = None + self.step_delta = 5 + self.step_time = 0.5 diff --git a/yardstick/network_services/vnf_generic/vnf/prox_irq.py b/yardstick/network_services/vnf_generic/vnf/prox_irq.py new file mode 100644 index 000000000..dda26b0fe --- /dev/null +++ b/yardstick/network_services/vnf_generic/vnf/prox_irq.py @@ -0,0 +1,200 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import errno +import logging +import copy +import time + +from yardstick.common.process import check_if_process_failed +from yardstick.network_services.utils import get_nsb_option +from yardstick.network_services.vnf_generic.vnf.prox_vnf import ProxApproxVnf +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen +from yardstick.benchmark.contexts.base import Context +from yardstick.network_services.vnf_generic.vnf.prox_helpers import CoreSocketTuple +LOG = logging.getLogger(__name__) + + +class ProxIrq(SampleVNFTrafficGen): + + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): + vnfd_cpy = copy.deepcopy(vnfd) + super(ProxIrq, self).__init__(name, vnfd_cpy, task_id) + + self._vnf_wrapper = ProxApproxVnf( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) + self.bin_path = get_nsb_option('bin_path', '') + self.name = self._vnf_wrapper.name + self.ssh_helper = self._vnf_wrapper.ssh_helper + self.setup_helper = self._vnf_wrapper.setup_helper + self.resource_helper = self._vnf_wrapper.resource_helper + self.scenario_helper = self._vnf_wrapper.scenario_helper + self.irq_cores = None + + def terminate(self): + self._vnf_wrapper.terminate() + super(ProxIrq, self).terminate() + + def instantiate(self, scenario_cfg, context_cfg): + self._vnf_wrapper.instantiate(scenario_cfg, context_cfg) + self._tg_process = self._vnf_wrapper._vnf_process + + def wait_for_instantiate(self): + self._vnf_wrapper.wait_for_instantiate() + + def get_irq_cores(self): + cores = [] + mode = "irq" + + for section_name, section in self.setup_helper.prox_config_data: + if not section_name.startswith("core"): + continue + irq_mode = task_present = False + task_present_task = 0 + for key, value in section: + if key == "mode" and value == mode: + irq_mode = True + if key == "task": + task_present = True + task_present_task = int(value) + + if irq_mode: + if not task_present: + task_present_task = 0 + core_tuple = CoreSocketTuple(section_name) + core = core_tuple.core_id + cores.append((core, task_present_task)) + + return cores + +class ProxIrqVNF(ProxIrq, SampleVNFTrafficGen): + + APP_NAME = 'ProxIrqVNF' + + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): + ProxIrq.__init__(self, name, vnfd, task_id, setup_env_helper_type, + resource_helper_type) + + self.start_test_time = None + self.end_test_time = None + + def vnf_execute(self, cmd, *args, **kwargs): + ignore_errors = kwargs.pop("_ignore_errors", False) + try: + return self.resource_helper.execute(cmd, *args, **kwargs) + except OSError as e: + if e.errno in {errno.EPIPE, errno.ESHUTDOWN, errno.ECONNRESET}: + if ignore_errors: + LOG.debug("ignoring vnf_execute exception %s for command %s", e, cmd) + else: + raise + else: + raise + + def collect_kpi(self): + # check if the tg processes have exited + physical_node = Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) + + result = {"physical_node": physical_node} + for proc in (self._tg_process, self._traffic_process): + check_if_process_failed(proc) + + if self.resource_helper is None: + return result + + if self.irq_cores is None: + self.setup_helper.build_config_file() + self.irq_cores = self.get_irq_cores() + + data = self.vnf_execute('irq_core_stats', self.irq_cores) + new_data = copy.deepcopy(data) + + self.end_test_time = time.time() + self.vnf_execute('reset_stats') + + if self.start_test_time is None: + new_data = {} + else: + test_time = self.end_test_time - self.start_test_time + for index, item in data.items(): + for counter, value in item.items(): + if counter.startswith("bucket_")or \ + counter.startswith("overflow"): + if value is 0: + del new_data[index][counter] + else: + new_data[index][counter] = float(value) / test_time + + self.start_test_time = time.time() + + result["collect_stats"] = new_data + LOG.debug("%s collect KPIs %s", self.APP_NAME, result) + + return result + +class ProxIrqGen(ProxIrq, SampleVNFTrafficGen): + + APP_NAME = 'ProxIrqGen' + + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): + ProxIrq.__init__(self, name, vnfd, task_id, setup_env_helper_type, + resource_helper_type) + self.start_test_time = None + self.end_test_time = None + + def collect_kpi(self): + # check if the tg processes have exited + physical_node = Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) + + result = {"physical_node": physical_node} + for proc in (self._tg_process, self._traffic_process): + check_if_process_failed(proc) + + if self.resource_helper is None: + return result + + if self.irq_cores is None: + self.setup_helper.build_config_file() + self.irq_cores = self.get_irq_cores() + + data = self.resource_helper.sut.irq_core_stats(self.irq_cores) + new_data = copy.deepcopy(data) + + self.end_test_time = time.time() + self.resource_helper.sut.reset_stats() + + if self.start_test_time is None: + new_data = {} + else: + test_time = self.end_test_time - self.start_test_time + for index, item in data.items(): + for counter, value in item.items(): + if counter.startswith("bucket_") or \ + counter.startswith("overflow"): + if value is 0: + del new_data[index][counter] + else: + new_data[index][counter] = float(value) / test_time + + self.start_test_time = time.time() + + result["collect_stats"] = new_data + LOG.debug("%s collect KPIs %s", self.APP_NAME, result) + + return result diff --git a/yardstick/tests/unit/benchmark/core/test_report.py b/yardstick/tests/unit/benchmark/core/test_report.py index 3e80dcc45..11d017ff0 100644 --- a/yardstick/tests/unit/benchmark/core/test_report.py +++ b/yardstick/tests/unit/benchmark/core/test_report.py @@ -20,10 +20,10 @@ GOOD_YAML_NAME = 'fake_name' GOOD_TASK_ID = str(uuid.uuid4()) GOOD_DB_FIELDKEYS = [{'fieldKey': 'fake_key'}] GOOD_DB_TASK = [{ - 'fake_key': 0.000, - 'time': '0000-00-00T00:00:00.000000Z', + 'fake_key': 1.234, + 'time': '0000-00-00T12:34:56.789012Z', }] -GOOD_TIMESTAMP = ['00:00:00.000000'] +GOOD_TIMESTAMP = ['12:34:56.789012'] BAD_YAML_NAME = 'F@KE_NAME' BAD_TASK_ID = 'aaaaaa-aaaaaaaa-aaaaaaaaaa-aaaaaa' @@ -47,23 +47,23 @@ class JSTreeTestCase(unittest.TestCase): def test_format_for_jstree(self): data = [ - {'data': [0, ], 'name': 'tg__0.DropPackets'}, - {'data': [548, ], 'name': 'tg__0.LatencyAvg.5'}, - {'data': [1172, ], 'name': 'tg__0.LatencyAvg.6'}, - {'data': [1001, ], 'name': 'tg__0.LatencyMax.5'}, - {'data': [1468, ], 'name': 'tg__0.LatencyMax.6'}, - {'data': [18.11, ], 'name': 'tg__0.RxThroughput'}, - {'data': [18.11, ], 'name': 'tg__0.TxThroughput'}, - {'data': [0, ], 'name': 'tg__1.DropPackets'}, - {'data': [548, ], 'name': 'tg__1.LatencyAvg.5'}, - {'data': [1172, ], 'name': 'tg__1.LatencyAvg.6'}, - {'data': [1001, ], 'name': 'tg__1.LatencyMax.5'}, - {'data': [1468, ], 'name': 'tg__1.LatencyMax.6'}, - {'data': [18.1132084505, ], 'name': 'tg__1.RxThroughput'}, - {'data': [18.1157260383, ], 'name': 'tg__1.TxThroughput'}, - {'data': [9057888, ], 'name': 'vnf__0.curr_packets_in'}, - {'data': [0, ], 'name': 'vnf__0.packets_dropped'}, - {'data': [617825443, ], 'name': 'vnf__0.packets_fwd'}, + {'data': [0, ], 'label': 'tg__0.DropPackets'}, + {'data': [548, ], 'label': 'tg__0.LatencyAvg.5'}, + {'data': [1172, ], 'label': 'tg__0.LatencyAvg.6'}, + {'data': [1001, ], 'label': 'tg__0.LatencyMax.5'}, + {'data': [1468, ], 'label': 'tg__0.LatencyMax.6'}, + {'data': [18.11, ], 'label': 'tg__0.RxThroughput'}, + {'data': [18.11, ], 'label': 'tg__0.TxThroughput'}, + {'data': [0, ], 'label': 'tg__1.DropPackets'}, + {'data': [548, ], 'label': 'tg__1.LatencyAvg.5'}, + {'data': [1172, ], 'label': 'tg__1.LatencyAvg.6'}, + {'data': [1001, ], 'label': 'tg__1.LatencyMax.5'}, + {'data': [1468, ], 'label': 'tg__1.LatencyMax.6'}, + {'data': [18.1132084505, ], 'label': 'tg__1.RxThroughput'}, + {'data': [18.1157260383, ], 'label': 'tg__1.TxThroughput'}, + {'data': [9057888, ], 'label': 'vnf__0.curr_packets_in'}, + {'data': [0, ], 'label': 'vnf__0.packets_dropped'}, + {'data': [617825443, ], 'label': 'vnf__0.packets_fwd'}, ] expected_output = [ @@ -168,3 +168,15 @@ class ReportTestCase(unittest.TestCase): mock_tasks.assert_called_once_with() mock_keys.assert_called_once_with() self.assertEqual(GOOD_TIMESTAMP, self.rep.Timestamp) + + @mock.patch.object(report.Report, '_get_tasks') + @mock.patch.object(report.Report, '_get_fieldkeys') + @mock.patch.object(report.Report, '_validate') + def test_generate_nsb(self, mock_valid, mock_keys, mock_tasks): + mock_tasks.return_value = GOOD_DB_TASK + mock_keys.return_value = GOOD_DB_FIELDKEYS + self.rep.generate_nsb(self.param) + mock_valid.assert_called_once_with(GOOD_YAML_NAME, GOOD_TASK_ID) + mock_tasks.assert_called_once_with() + mock_keys.assert_called_once_with() + self.assertEqual(GOOD_TIMESTAMP, self.rep.Timestamp) diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py index bf613ca52..5b32a4297 100644 --- a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py +++ b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py @@ -351,6 +351,39 @@ class TestIxNextgen(unittest.TestCase): self.ixnet_gen.ixnet.setAttribute.assert_any_call( 'attr/singleValue', '-value', 'external') + def test_add_interface(self): + self.ixnet_gen.ixnet.add.return_value = 'obj' + self.ixnet_gen.add_interface(vport='vport', + ip='10.0.0.2', + mac='00:00:00:00:00:00', + gateway='10.0.0.1') + self.ixnet_gen.ixnet.add.assert_any_call('vport', 'interface') + self.ixnet_gen.ixnet.add.assert_any_call('obj', 'ipv4') + self.ixnet_gen.ixnet.setMultiAttribute.assert_any_call( + 'obj/ethernet', '-macAddress', '00:00:00:00:00:00') + self.ixnet_gen.ixnet.setMultiAttribute.assert_any_call( + 'obj', '-ip', '10.0.0.2') + self.ixnet_gen.ixnet.setMultiAttribute.assert_any_call( + 'obj', '-gateway', '10.0.0.1') + self.ixnet_gen.ixnet.setMultiAttribute.assert_any_call( + 'obj', '-enabled', 'true') + + def test_add_static_ipv4(self): + self.ixnet_gen.ixnet.add.return_value = 'obj' + self.ixnet_gen.add_static_ipv4(iface='iface', + vport='vport', + start_ip='10.0.0.0', + count='100', + mask='32') + self.ixnet_gen.ixnet.add.assert_called_once_with( + 'vport/protocols/static', 'ip') + self.ixnet_gen.ixnet.setMultiAttribute.assert_any_call( + 'obj', '-protocolInterface', 'iface', + '-ipStart', '10.0.0.0', + '-count', '100', + '-mask', '32', + '-enabled', 'true') + @mock.patch.object(IxNetwork, 'IxNet') def test_connect(self, mock_ixnet): mock_ixnet.return_value = self.ixnet diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_prox_irq.py b/yardstick/tests/unit/network_services/traffic_profile/test_prox_irq.py new file mode 100644 index 000000000..59f37befa --- /dev/null +++ b/yardstick/tests/unit/network_services/traffic_profile/test_prox_irq.py @@ -0,0 +1,55 @@ +# Copyright (c) 2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +import mock + +from yardstick.network_services.traffic_profile import prox_irq + + +class TestProxIrqProfile(unittest.TestCase): + + def setUp(self): + self._mock_log_info = mock.patch.object(prox_irq.LOG, 'info') + self.mock_log_info = self._mock_log_info.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_log_info.stop() + + def test_execute_1(self): + tp_config = { + 'traffic_profile': { + }, + } + + traffic_generator = mock.MagicMock() + attrs1 = {'get.return_value' : 10} + traffic_generator.scenario_helper.all_options.configure_mock(**attrs1) + + attrs2 = {'__getitem__.return_value' : 10, 'get.return_value': 10} + traffic_generator.scenario_helper.scenario_cfg["runner"].configure_mock(**attrs2) + + profile_helper = mock.MagicMock() + + profile = prox_irq.ProxIrqProfile(tp_config) + profile.init(mock.MagicMock()) + profile._profile_helper = profile_helper + + profile.execute_traffic(traffic_generator) + profile.run_test() + is_ended_flag = profile.is_ended() + + self.assertFalse(is_ended_flag) + self.assertEqual(profile.lower_bound, 10.0) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py index 6d1d8c6a1..9a30fb9e9 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py @@ -590,6 +590,27 @@ class TestProxSocketHelper(unittest.TestCase): self.assertEqual(result, expected) @mock.patch.object(prox_helpers.LOG, 'error') + def test_irq_core_stats(self, *args): + mock_socket = mock.MagicMock() + prox = prox_helpers.ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(return_value=('0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3')) + + data_0 = {"cpu": 0, 'bucket_0': 1, 'bucket_1': 2, 'bucket_2': 3, 'bucket_3': 4, + 'bucket_4': 5, 'bucket_5': 0, 'bucket_6': 1, 'bucket_7': 2, 'bucket_8': 3, + 'bucket_9': 4, 'bucket_10': 5, 'bucket_11': 0, 'bucket_12': 1, + "max_irq": 0, "overflow": 10} + + data_1 = {"cpu": 1, 'bucket_0': 1, 'bucket_1': 2, 'bucket_2': 3, 'bucket_3': 4, + 'bucket_4': 5, 'bucket_5': 0, 'bucket_6': 1, 'bucket_7': 2, 'bucket_8': 3, + 'bucket_9': 4, 'bucket_10': 5, 'bucket_11': 0, 'bucket_12': 1, + "max_irq": 0, "overflow": 10} + + expected = {"core_0": data_0, "core_1": data_1} + + result = prox.irq_core_stats([[0, 1], [1, 0]]) + self.assertDictEqual(result, expected) + + @mock.patch.object(prox_helpers.LOG, 'error') def test_multi_port_stats(self, *args): mock_socket = mock.MagicMock() prox = prox_helpers.ProxSocketHelper(mock_socket) @@ -1353,6 +1374,36 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ['missing_addtional_file', 'dofile("nosuch")'], ], ], + [ + 'core 0', + [ + ['name', 'p0'] + ] + ], + [ + 'core 1-4', + [ + ['name', 'p1'] + ] + ], + [ + 'core 5,6', + [ + ['name', 'p2'] + ] + ], + [ + 'core xx', + [ + ['name', 'p3'] + ] + ], + [ + 'core $x', + [ + ['name', 'p4'] + ] + ] ] expected = [ @@ -1382,6 +1433,54 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ['missing_addtional_file', 'dofile("nosuch")'], ], ], + [ + 'core 0', + [ + ['name', 'p0'] + ] + ], + [ + 'core 1', + [ + ['name', 'p1'] + ] + ], + [ + 'core 2', + [ + ['name', 'p1'] + ] + ], + [ + 'core 3', + [ + ['name', 'p1'] + ] + ], + [ + 'core 4', + [ + ['name', 'p1'] + ] + ], + [ + 'core 5', + [ + ['name', 'p2'] + ] + ], + [ + 'core 6', + [ + ['name', 'p2'] + ] + ], + [ + 'core $x', + [ + ['name', 'p4'] + ] + ] ] result = helper.generate_prox_config_file('/c/d/e') self.assertEqual(result, expected, str(result)) @@ -2708,3 +2807,15 @@ class TestProxlwAFTRProfileHelper(unittest.TestCase): # negative pkt_size is the only way to make ratio > 1 helper.run_test(pkt_size=-1000, duration=5, value=6.5, tolerated_loss=0.0, line_speed=constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) + + +class TestProxIrqProfileHelper(unittest.TestCase): + + def test_run_test(self, *args): + resource_helper = mock.MagicMock() + helper = prox_helpers.ProxIrqProfileHelper(resource_helper) + self.assertIsNone(helper._cores_tuple) + self.assertIsNone(helper._ports_tuple) + self.assertIsNone(helper._latency_cores) + self.assertIsNone(helper._test_cores) + self.assertIsNone(helper._cpu_topology) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_irq.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_irq.py new file mode 100644 index 000000000..4eaa38c27 --- /dev/null +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_irq.py @@ -0,0 +1,828 @@ +# Copyright (c) 2017-2018 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +import mock +import errno + +from yardstick.tests import STL_MOCKS +from yardstick.common import exceptions as y_exceptions +from yardstick.network_services.vnf_generic.vnf.prox_irq import ProxIrqGen +from yardstick.network_services.vnf_generic.vnf.prox_irq import ProxIrqVNF +from yardstick.benchmark.contexts import base as ctx_base + +SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.vnf_generic.vnf import prox_vnf + from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh + +VNF_NAME = "vnf__1" + +class TestProxIrqVNF(unittest.TestCase): + + SCENARIO_CFG = { + 'task_path': "", + 'nodes': { + 'tg__1': 'trafficgen_1.yardstick', + 'vnf__1': 'vnf.yardstick'}, + 'runner': { + 'duration': 600, 'type': 'Duration'}, + 'topology': 'prox-tg-topology-2.yaml', + 'traffic_profile': '../../traffic_profiles/prox_binsearch.yaml', + 'type': 'NSPerf', + 'options': { + 'tg__1': {'prox_args': {'-e': '', + '-t': ''}, + 'prox_config': 'configs/l3-gen-2.cfg', + 'prox_path': + '/root/dppd-PROX-v035/build/prox'}, + 'vnf__1': { + 'prox_args': {'-t': ''}, + 'prox_config': 'configs/l3-swap-2.cfg', + 'prox_path': '/root/dppd-PROX-v035/build/prox'}}} + + VNFD_0 = { + 'short-name': 'VpeVnf', + 'vdu': [ + { + 'routing_table': [ + { + 'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0' + }, + { + 'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1' + }, + ], + 'description': 'VPE approximation using DPDK', + 'name': 'vpevnf-baremetal', + 'nd_route_tbl': [ + { + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0' + }, + { + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1' + }, + ], + 'id': 'vpevnf-baremetal', + 'external-interface': [ + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:05:00.0', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 0, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.100.20', + 'local_mac': '00:00:00:00:00:01' + }, + 'vnfd-connection-point-ref': 'xe0', + 'name': 'xe0' + }, + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.1', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 1, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_mac': '00:00:00:00:00:02' + }, + 'vnfd-connection-point-ref': 'xe1', + 'name': 'xe1' + }, + ], + }, + ], + 'description': 'Vpe approximation using DPDK', + 'mgmt-interface': { + 'vdu-id': 'vpevnf-baremetal', + 'host': '1.1.1.1', + 'password': 'r00t', + 'user': 'root', + 'ip': '1.1.1.1' + }, + 'benchmark': { + 'kpi': [ + 'packets_in', + 'packets_fwd', + 'packets_dropped', + ], + }, + 'connection-point': [ + { + 'type': 'VPORT', + 'name': 'xe0', + }, + { + 'type': 'VPORT', + 'name': 'xe1', + }, + ], + 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh' + } + + VNFD = { + 'vnfd:vnfd-catalog': { + 'vnfd': [ + VNFD_0, + ] + } + } + + TRAFFIC_PROFILE = { + "schema": "isb:traffic_profile:0.1", + "name": "fixed", + "description": "Fixed traffic profile to run UDP traffic", + "traffic_profile": { + "traffic_type": "FixedTraffic", + "frame_rate": 100, # pps + "flow_number": 10, + "frame_size": 64, + }, + } + + CONTEXT_CFG = { + 'nodes': { + 'tg__2': { + 'member-vnf-index': '3', + 'role': 'TrafficGen', + 'name': 'trafficgen_2.yardstick', + 'vnfd-id-ref': 'tg__2', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens513f0', + 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.20', + 'dst_mac': '00:00:00:00:00:01', + 'local_mac': '00:00:00:00:00:03', + 'dst_ip': '152.16.40.19', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens513f1', + 'netmask': '255.255.255.0', + 'network': '202.16.100.0', + 'local_ip': '202.16.100.20', + 'local_mac': '00:1e:67:d0:60:5d', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'l3fwd_vnf.yaml', + 'user': 'root', + }, + 'tg__1': { + 'member-vnf-index': '1', + 'role': 'TrafficGen', + 'name': 'trafficgen_1.yardstick', + 'vnfd-id-ref': 'tg__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens785f0', + 'vld_id': prox_vnf.ProxApproxVnf.UPLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.20', + 'dst_mac': '00:00:00:00:00:02', + 'local_mac': '00:00:00:00:00:04', + 'dst_ip': '152.16.100.19', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens785f1', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.21', + 'local_mac': '00:00:00:00:00:01', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'tg_rfc2544_tpl.yaml', + 'user': 'root', + }, + 'vnf__1': { + 'name': 'vnf.yardstick', + 'vnfd-id-ref': 'vnf__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens786f0', + 'vld_id': prox_vnf.ProxApproxVnf.UPLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.19', + 'dst_mac': '00:00:00:00:00:04', + 'local_mac': '00:00:00:00:00:02', + 'dst_ip': '152.16.100.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens786f1', + 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.19', + 'dst_mac': '00:00:00:00:00:03', + 'local_mac': '00:00:00:00:00:01', + 'dst_ip': '152.16.40.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'routing_table': [ + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'network': '152.16.100.20', + 'if': 'xe0', + }, + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'network': '152.16.40.20', + 'if': 'xe1', + }, + ], + 'member-vnf-index': '2', + 'host': '1.2.1.1', + 'role': 'vnf', + 'user': 'root', + 'nd_route_tbl': [ + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0', + }, + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1', + }, + ], + 'password': 'r00t', + 'VNF model': 'prox_vnf.yaml', + }, + }, + } + + def test___init__(self): + prox_irq_vnf = ProxIrqVNF('vnf1', self.VNFD_0, 'task_id') + + self.assertEqual(prox_irq_vnf.name, 'vnf1') + self.assertDictEqual(prox_irq_vnf.vnfd_helper, self.VNFD_0) + + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') + @mock.patch(SSH_HELPER) + def test_collect_kpi(self, ssh, *args): + mock_ssh(ssh) + + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + resource_helper = mock.MagicMock() + + resource_helper = mock.MagicMock() + + core_1 = {'bucket_1': 1, 'bucket_2': 2, 'bucket_3': 3, 'bucket_4': 4, 'bucket_5': 5, + 'bucket_6': 6, 'bucket_7': 7, 'bucket_8': 8, 'bucket_9': 9, 'bucket_10': 10, + 'bucket_11': 11, 'bucket_12': 12, 'bucket_0': 100, 'cpu': 1, 'max_irq': 12, + 'overflow': 10} + core_2 = {'bucket_1': 1, 'bucket_2': 2, 'bucket_3': 3, 'bucket_4': 4, 'bucket_5': 5, + 'bucket_6': 0, 'bucket_7': 0, 'bucket_8': 0, 'bucket_9': 0, 'bucket_10': 0, + 'bucket_11': 0, 'bucket_12': 0, 'bucket_0': 100, 'cpu': 2, 'max_irq': 12, + 'overflow': 10} + + irq_data = {'core_1': core_1, 'core_2': core_2} + resource_helper.execute.return_value = (irq_data) + + build_config_file = mock.MagicMock() + build_config_file.return_value = None + + prox_irq_vnf = ProxIrqVNF(VNF_NAME, vnfd, 'task_id') + + startup = ["global", [["eal", "-4"]]] + master_0 = ["core 0", [["mode", "master"]]] + core_1 = ["core 1", [["mode", "irq"]]] + core_2 = ["core 2", [["mode", "irq"], ["task", "2"]]] + + prox_irq_vnf.setup_helper._prox_config_data = \ + [startup, master_0, core_1, core_2] + + prox_irq_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG + prox_irq_vnf.resource_helper = resource_helper + prox_irq_vnf.setup_helper.build_config_file = build_config_file + + result = prox_irq_vnf.collect_kpi() + self.assertDictEqual(result["collect_stats"], {}) + + result = prox_irq_vnf.collect_kpi() + self.assertFalse('bucket_10' in result["collect_stats"]['core_2']) + self.assertFalse('bucket_11' in result["collect_stats"]['core_2']) + self.assertFalse('bucket_12' in result["collect_stats"]['core_2']) + self.assertEqual(result["collect_stats"]['core_2']['max_irq'], 12) + + + @mock.patch(SSH_HELPER) + def test_vnf_execute_oserror(self, ssh, *args): + mock_ssh(ssh) + + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + prox_irq_vnf = ProxIrqVNF(VNF_NAME, vnfd, 'task_id') + prox_irq_vnf.resource_helper = resource_helper = mock.Mock() + + resource_helper.execute.side_effect = OSError(errno.EPIPE, "") + prox_irq_vnf.vnf_execute("", _ignore_errors=True) + + resource_helper.execute.side_effect = OSError(errno.ESHUTDOWN, "") + prox_irq_vnf.vnf_execute("", _ignore_errors=True) + + resource_helper.execute.side_effect = OSError(errno.EADDRINUSE, "") + with self.assertRaises(OSError): + prox_irq_vnf.vnf_execute("", _ignore_errors=True) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') + @mock.patch(SSH_HELPER) + def test_terminate(self, ssh, *args): + mock_ssh(ssh) + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + + mock_ssh(ssh, exec_result=(1, "", "")) + prox_irq_vnf = ProxIrqVNF(VNF_NAME, vnfd, 'task_id') + + prox_irq_vnf._terminated = mock.MagicMock() + prox_irq_vnf._traffic_process = mock.MagicMock() + prox_irq_vnf._traffic_process.terminate = mock.Mock() + prox_irq_vnf.ssh_helper = mock.MagicMock() + prox_irq_vnf.setup_helper = mock.MagicMock() + prox_irq_vnf.resource_helper = mock.MagicMock() + prox_irq_vnf._vnf_wrapper.setup_helper = mock.MagicMock() + prox_irq_vnf._vnf_wrapper._vnf_process = mock.MagicMock(**{"is_alive.return_value": False}) + prox_irq_vnf._vnf_wrapper.resource_helper = mock.MagicMock() + + prox_irq_vnf._run_prox = mock.Mock(return_value=0) + prox_irq_vnf.q_in = mock.Mock() + prox_irq_vnf.q_out = mock.Mock() + + self.assertIsNone(prox_irq_vnf.terminate()) + + @mock.patch(SSH_HELPER) + def test_wait_for_instantiate_panic(self, ssh, *args): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + + mock_ssh(ssh, exec_result=(1, "", "")) + prox_irq_vnf = ProxIrqVNF(VNF_NAME, vnfd, 'task_id') + + prox_irq_vnf._terminated = mock.MagicMock() + prox_irq_vnf._traffic_process = mock.MagicMock() + prox_irq_vnf._traffic_process.terminate = mock.Mock() + prox_irq_vnf.ssh_helper = mock.MagicMock() + prox_irq_vnf.setup_helper = mock.MagicMock() + prox_irq_vnf.resource_helper = mock.MagicMock() + prox_irq_vnf._vnf_wrapper.setup_helper = mock.MagicMock() + prox_irq_vnf._vnf_wrapper._vnf_process = mock.MagicMock(**{"is_alive.return_value": False}) + prox_irq_vnf._vnf_wrapper.resource_helper = mock.MagicMock() + + prox_irq_vnf._run_prox = mock.Mock(return_value=0) + prox_irq_vnf.q_in = mock.Mock() + prox_irq_vnf.q_out = mock.Mock() + prox_irq_vnf.WAIT_TIME = 0 + with self.assertRaises(RuntimeError): + prox_irq_vnf.wait_for_instantiate() + +class TestProxIrqGen(unittest.TestCase): + + SCENARIO_CFG = { + 'task_path': "", + 'nodes': { + 'tg__1': 'trafficgen_1.yardstick', + 'vnf__1': 'vnf.yardstick'}, + 'runner': { + 'duration': 600, 'type': 'Duration'}, + 'topology': 'prox-tg-topology-2.yaml', + 'traffic_profile': '../../traffic_profiles/prox_binsearch.yaml', + 'type': 'NSPerf', + 'options': { + 'tg__1': {'prox_args': {'-e': '', + '-t': ''}, + 'prox_config': 'configs/l3-gen-2.cfg', + 'prox_path': + '/root/dppd-PROX-v035/build/prox'}, + 'vnf__1': { + 'prox_args': {'-t': ''}, + 'prox_config': 'configs/l3-swap-2.cfg', + 'prox_path': '/root/dppd-PROX-v035/build/prox'}}} + + VNFD_0 = { + 'short-name': 'VpeVnf', + 'vdu': [ + { + 'routing_table': [ + { + 'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0' + }, + { + 'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1' + }, + ], + 'description': 'VPE approximation using DPDK', + 'name': 'vpevnf-baremetal', + 'nd_route_tbl': [ + { + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0' + }, + { + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1' + }, + ], + 'id': 'vpevnf-baremetal', + 'external-interface': [ + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:05:00.0', + 'driver': 'i40e', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 0, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.100.20', + 'local_mac': '00:00:00:00:00:01' + }, + 'vnfd-connection-point-ref': 'xe0', + 'name': 'xe0' + }, + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.1', + 'driver': 'ixgbe', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 1, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_mac': '00:00:00:00:00:02' + }, + 'vnfd-connection-point-ref': 'xe1', + 'name': 'xe1' + }, + ], + }, + ], + 'description': 'Vpe approximation using DPDK', + 'mgmt-interface': { + 'vdu-id': 'vpevnf-baremetal', + 'host': '1.1.1.1', + 'password': 'r00t', + 'user': 'root', + 'ip': '1.1.1.1' + }, + 'benchmark': { + 'kpi': [ + 'packets_in', + 'packets_fwd', + 'packets_dropped', + ], + }, + 'connection-point': [ + { + 'type': 'VPORT', + 'name': 'xe0', + }, + { + 'type': 'VPORT', + 'name': 'xe1', + }, + ], + 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh' + } + + VNFD = { + 'vnfd:vnfd-catalog': { + 'vnfd': [ + VNFD_0, + ], + }, + } + + TRAFFIC_PROFILE = { + "schema": "isb:traffic_profile:0.1", + "name": "fixed", + "description": "Fixed traffic profile to run UDP traffic", + "traffic_profile": { + "traffic_type": "FixedTraffic", + "frame_rate": 100, # pps + "flow_number": 10, + "frame_size": 64, + }, + } + + CONTEXT_CFG = { + 'nodes': { + 'tg__2': { + 'member-vnf-index': '3', + 'role': 'TrafficGen', + 'name': 'trafficgen_2.yardstick', + 'vnfd-id-ref': 'tg__2', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens513f0', + 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.20', + 'dst_mac': '00:00:00:00:00:01', + 'local_mac': '00:00:00:00:00:03', + 'dst_ip': '152.16.40.19', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens513f1', + 'netmask': '255.255.255.0', + 'network': '202.16.100.0', + 'local_ip': '202.16.100.20', + 'local_mac': '00:1e:67:d0:60:5d', + 'driver': 'ixgbe', + 'vpci': '0000:02:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'l3fwd_vnf.yaml', + 'user': 'root', + }, + 'tg__1': { + 'member-vnf-index': '1', + 'role': 'TrafficGen', + 'name': 'trafficgen_1.yardstick', + 'vnfd-id-ref': 'tg__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens785f0', + 'vld_id': prox_vnf.ProxApproxVnf.UPLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.20', + 'dst_mac': '00:00:00:00:00:02', + 'local_mac': '00:00:00:00:00:04', + 'dst_ip': '152.16.100.19', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens785f1', + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.21', + 'local_mac': '00:00:00:00:00:01', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'password': 'r00t', + 'VNF model': 'tg_rfc2544_tpl.yaml', + 'user': 'root', + }, + 'vnf__1': { + 'name': 'vnf.yardstick', + 'vnfd-id-ref': 'vnf__1', + 'ip': '1.2.1.1', + 'interfaces': { + 'xe0': { + 'local_iface_name': 'ens786f0', + 'vld_id': prox_vnf.ProxApproxVnf.UPLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.100.19', + 'dst_mac': '00:00:00:00:00:04', + 'local_mac': '00:00:00:00:00:02', + 'dst_ip': '152.16.100.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': 0, + }, + 'xe1': { + 'local_iface_name': 'ens786f1', + 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK, + 'netmask': '255.255.255.0', + 'local_ip': '152.16.40.19', + 'dst_mac': '00:00:00:00:00:03', + 'local_mac': '00:00:00:00:00:01', + 'dst_ip': '152.16.40.20', + 'driver': 'i40e', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': 1, + }, + }, + 'routing_table': [ + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'network': '152.16.100.20', + 'if': 'xe0', + }, + { + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'network': '152.16.40.20', + 'if': 'xe1', + }, + ], + 'member-vnf-index': '2', + 'host': '1.2.1.1', + 'role': 'vnf', + 'user': 'root', + 'nd_route_tbl': [ + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0', + }, + { + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1', + }, + ], + 'password': 'r00t', + 'VNF model': 'prox_vnf.yaml', + }, + }, + } + + + def test__check_status(self): + prox_irq_gen = ProxIrqGen('tg1', self.VNFD_0, 'task_id') + + with self.assertRaises(NotImplementedError): + prox_irq_gen._check_status() + + def test_listen_traffic(self): + prox_irq_gen = ProxIrqGen('tg1', self.VNFD_0, 'task_id') + + prox_irq_gen.listen_traffic(mock.Mock()) + + def test_verify_traffic(self): + prox_irq_gen = ProxIrqGen('tg1', self.VNFD_0, 'task_id') + + prox_irq_gen.verify_traffic(mock.Mock()) + + mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') + @mock.patch(SSH_HELPER) + def test_terminate(self, ssh, *args): + mock_ssh(ssh) + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + prox_traffic_gen = ProxIrqGen(VNF_NAME, vnfd, 'task_id') + prox_traffic_gen._terminated = mock.MagicMock() + prox_traffic_gen._traffic_process = mock.MagicMock() + prox_traffic_gen._traffic_process.terminate = mock.Mock() + prox_traffic_gen.ssh_helper = mock.MagicMock() + prox_traffic_gen.setup_helper = mock.MagicMock() + prox_traffic_gen.resource_helper = mock.MagicMock() + prox_traffic_gen._vnf_wrapper.setup_helper = mock.MagicMock() + prox_traffic_gen._vnf_wrapper._vnf_process = mock.MagicMock() + prox_traffic_gen._vnf_wrapper.resource_helper = mock.MagicMock() + self.assertIsNone(prox_traffic_gen.terminate()) + + def test__wait_for_process(self): + prox_irq_gen = ProxIrqGen('tg1', self.VNFD_0, 'task_id') + with mock.patch.object(prox_irq_gen, '_check_status', + return_value=0) as mock_status, \ + mock.patch.object(prox_irq_gen, '_tg_process') as mock_proc: + mock_proc.is_alive.return_value = True + mock_proc.exitcode = 234 + self.assertEqual(prox_irq_gen._wait_for_process(), 234) + mock_proc.is_alive.assert_called_once() + mock_status.assert_called_once() + + def test__wait_for_process_not_alive(self): + prox_irq_gen = ProxIrqGen('tg1', self.VNFD_0, 'task_id') + with mock.patch.object(prox_irq_gen, '_tg_process') as mock_proc: + mock_proc.is_alive.return_value = False + self.assertRaises(RuntimeError, prox_irq_gen._wait_for_process) + mock_proc.is_alive.assert_called_once() + + def test__wait_for_process_delayed(self): + prox_irq_gen = ProxIrqGen('tg1', self.VNFD_0, 'task_id') + with mock.patch.object(prox_irq_gen, '_check_status', + side_effect=[1, 0]) as mock_status, \ + mock.patch.object(prox_irq_gen, + '_tg_process') as mock_proc: + mock_proc.is_alive.return_value = True + mock_proc.exitcode = 234 + self.assertEqual(prox_irq_gen._wait_for_process(), 234) + mock_proc.is_alive.assert_has_calls([mock.call(), mock.call()]) + mock_status.assert_has_calls([mock.call(), mock.call()]) + + def test_scale(self): + prox_irq_gen = ProxIrqGen('tg1', self.VNFD_0, 'task_id') + self.assertRaises(y_exceptions.FunctionNotImplemented, + prox_irq_gen.scale) + + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') + @mock.patch(SSH_HELPER) + def test_collect_kpi(self, ssh, *args): + mock_ssh(ssh) + + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + resource_helper = mock.MagicMock() + + core_1 = {'bucket_1': 1, 'bucket_2': 2, 'bucket_3': 3, 'bucket_4': 4, 'bucket_5': 5, + 'bucket_6': 6, 'bucket_7': 7, 'bucket_8': 8, 'bucket_9': 9, 'bucket_10': 10, + 'bucket_11': 11, 'bucket_12': 12, 'bucket_0': 100, 'cpu': 1, 'max_irq': 12, + 'overflow': 10} + core_2 = {'bucket_1': 1, 'bucket_2': 2, 'bucket_3': 3, 'bucket_4': 4, 'bucket_5': 5, + 'bucket_6': 0, 'bucket_7': 0, 'bucket_8': 0, 'bucket_9': 0, 'bucket_10': 0, + 'bucket_11': 0, 'bucket_12': 0, 'bucket_0': 100, 'cpu': 2, 'max_irq': 12, + 'overflow': 10} + + irq_data = {'core_1': core_1, 'core_2': core_2} + resource_helper.sut.irq_core_stats.return_value = (irq_data) + + build_config_file = mock.MagicMock() + build_config_file.return_value = None + + prox_irq_gen = ProxIrqGen(VNF_NAME, vnfd, 'task_id') + + startup = ["global", [["eal", "-4"]]] + master_0 = ["core 0", [["mode", "master"]]] + core_1 = ["core 1", [["mode", "irq"]]] + core_2 = ["core 2", [["mode", "irq"], ["task", "2"]]] + + prox_irq_gen.setup_helper._prox_config_data = \ + [startup, master_0, core_1, core_2] + + prox_irq_gen.scenario_helper.scenario_cfg = self.SCENARIO_CFG + prox_irq_gen.resource_helper = resource_helper + prox_irq_gen.setup_helper.build_config_file = build_config_file + + result = prox_irq_gen.collect_kpi() + self.assertDictEqual(result["collect_stats"], {}) + + result = prox_irq_gen.collect_kpi() + self.assertFalse('bucket_10' in result["collect_stats"]['core_2']) + self.assertFalse('bucket_11' in result["collect_stats"]['core_2']) + self.assertFalse('bucket_12' in result["collect_stats"]['core_2']) + self.assertEqual(result["collect_stats"]['core_2']['max_irq'], 12) |