Merge branch 'master' of github.com:yandex-load/yandex-tank

This commit is contained in:
Andrey Pohilko 2012-12-03 15:29:42 +04:00
commit 172fbbdb65
6 changed files with 354 additions and 177 deletions

View File

@ -6,6 +6,7 @@ from collections import deque
from tankcore import AbstractPlugin
import re
import tankcore
import math
class TotalAutostopPlugin(AbstractPlugin, AggregateResultListener):
''' Cummulative Criterias Plugin '''
@ -72,7 +73,7 @@ class TotalFracTimeCriteria(AbstractCriteria):
if self.real_frac >= float(self.frac) and len(self.data) >= self.seconds_limit:
self.cause_second = self.second_window[0]
self.log.debug(self.explain())
self.autostop.add_counting(self)
# self.autostop.add_counting(self)
return True
return False
@ -130,7 +131,7 @@ class TotalHTTPCodesCriteria(AbstractCriteria):
if (sum(self.data) / queue_len) >= self.level and len(self.data) >= self.seconds_limit:
self.cause_second = self.second_window[0]
self.log.debug(self.explain())
self.autostop.add_counting(self)
# self.autostop.add_counting(self)
return True
return False
@ -209,7 +210,7 @@ class TotalNetCodesCriteria(AbstractCriteria):
if (sum(self.data) / queue_len) >= self.level and len(self.data) >= self.seconds_limit:
self.cause_second = self.second_window[0]
self.log.debug(self.explain())
self.autostop.add_counting(self)
# self.autostop.add_counting(self)
return True
return False
@ -286,7 +287,7 @@ class TotalNegativeHTTPCodesCriteria(AbstractCriteria):
if (sum(self.data) / queue_len) >= self.level and len(self.data) >= self.seconds_limit:
self.cause_second = self.second_window[0]
self.log.debug(self.explain())
self.autostop.add_counting(self)
# self.autostop.add_counting(self)
return True
return False
@ -314,3 +315,150 @@ class TotalNegativeHTTPCodesCriteria(AbstractCriteria):
return ("HTTP not %s>%s for %ss" % items, sum(self.data))
items = (self.codes_mask, self.get_level_str(), self.seconds_limit)
return ("HTTP not %s>%s for %ss" % items, 1.0)
class TotalNegativeNetCodesCriteria(AbstractCriteria):
''' Reversed NET Criteria '''
@staticmethod
def get_type_string():
return 'negative_net'
def __init__(self, autostop, param_str):
AbstractCriteria.__init__(self)
self.seconds_count = 0
self.codes_mask = param_str.split(',')[0].lower()
self.codes_regex = re.compile(self.codes_mask.replace("x", '.'))
self.autostop = autostop
self.data = deque()
self.second_window = deque()
level_str = param_str.split(',')[1].strip()
if level_str[-1:] == '%':
self.level = float(level_str[:-1])
self.is_relative = True
else:
self.level = int(level_str)
self.is_relative = False
self.seconds_limit = tankcore.expand_to_seconds(param_str.split(',')[2])
def notify(self, aggregate_second):
codes = aggregate_second.overall.net_codes.copy()
# if '0' in codes.keys():
# codes.pop('0')
matched_responses = self.count_matched_codes(self.codes_regex, codes)
if self.is_relative:
if aggregate_second.overall.RPS:
matched_responses = float(matched_responses) / aggregate_second.overall.RPS * 100
matched_responses = 100 - matched_responses
else:
matched_responses = 1
self.log.debug("Net codes matching mask not %s: %s/%s", self.codes_mask, round(matched_responses, 1), self.level)
else :
matched_responses = aggregate_second.overall.RPS - matched_responses
self.log.debug("Net codes matching mask not %s: %s/%s", self.codes_mask, matched_responses, self.level)
self.data.append(matched_responses)
self.second_window.append(aggregate_second)
if len(self.data) > self.seconds_limit :
self.data.popleft()
self.second_window.popleft()
queue_len = 1
if self.is_relative :
queue_len = len(self.data)
if (sum(self.data) / queue_len) >= self.level and len(self.data) >= self.seconds_limit:
self.cause_second = self.second_window[0]
self.log.debug(self.explain())
return True
return False
def get_rc(self):
return 29
def get_level_str(self):
''' format level str'''
if self.is_relative:
level_str = str(self.level) + "%"
else:
level_str = self.level
return level_str
def explain(self):
if self.is_relative:
items = (self.codes_mask, self.get_level_str(), self.seconds_limit, self.cause_second.time)
return "Not %s codes count higher than %s for %ss, since %s" % items
items = (self.codes_mask, self.get_level_str(), self.seconds_limit, self.cause_second.time)
return "Not %s codes count higher than %s for %ss, since %s" % items
def widget_explain(self):
if self.is_relative:
items = (self.codes_mask, self.get_level_str(), self.seconds_limit)
return ("Net not %s>%s for %ss" % items, sum(self.data))
items = (self.codes_mask, self.get_level_str(), self.seconds_limit)
return ("Net not %s>%s for %ss" % items, 1.0)
class TotalHTTPTrendCriteria(AbstractCriteria):
''' HTTP Trend Criteria '''
@staticmethod
def get_type_string():
return 'http_trend'
def __init__(self, autostop, param_str):
AbstractCriteria.__init__(self)
self.seconds_count = 0
self.codes_mask = param_str.split(',')[0].lower()
self.codes_regex = re.compile(self.codes_mask.replace("x", '.'))
self.autostop = autostop
self.tangents = deque()
self.second_window = deque()
self.total_tan = float()
self.tangents.append(0)
self.last = 0
self.seconds_limit = tankcore.expand_to_seconds(param_str.split(',')[1])
def notify(self, aggregate_second):
matched_responses = self.count_matched_codes(self.codes_regex, aggregate_second.overall.http_codes)
self.tangents.append(matched_responses - self.last)
self.second_window.append(aggregate_second)
self.last = matched_responses
if len(self.tangents) > self.seconds_limit :
self.tangents.popleft()
self.second_window.popleft()
self.total_tan = float(sum(self.tangents) / len (self.tangents))
self.log.debug("Last trend for http codes %s: %.2f +/- %.2f", self.codes_mask, self.total_tan, self.measurement_error())
if self.total_tan + self.measurement_error() < 0 :
self.cause_second = self.second_window[0]
self.log.debug(self.explain())
return True
return False
def measurement_error(self):
# formula
# sqrt ( (sum(1, n, (k_i - <k>)**2) / (n*(n-1)))
if len(self.tangents) < 2 :
return 0.0
avg_tan = float(sum(self.tangents) / len(self.tangents))
numerator = float()
for i in self.tangents:
numerator += (i - avg_tan)*(i - avg_tan)
return math.sqrt (numerator / len(self.tangents) / (len(self.tangents) - 1) )
def get_rc(self):
return 30
def explain(self):
items = (self.codes_mask, self.total_tan, self.seconds_limit, self.cause_second.time)
return "Last trend for %s http codes is %s for %ss, since %s" % items
def widget_explain(self):
items = (self.codes_mask, self.total_tan, self.seconds_limit)
return ("HTTP(%s) trend %s < 0 for %ss" % items, 1.0)

202
Tests/TotalCriteriasTest.py Normal file
View File

@ -0,0 +1,202 @@
from Tank.Plugins.Aggregator import SecondAggregateData
from Tank.Plugins.TotalAutostop import TotalFracTimeCriteria, TotalHTTPCodesCriteria, TotalNegativeHTTPCodesCriteria, TotalNetCodesCriteria, TotalNegativeNetCodesCriteria, TotalHTTPTrendCriteria
from Tests.TankTests import TankTestCase
import unittest
class TotalCriteriasTest(TankTestCase):
def setUp(self):
self.frac_criteria = TotalFracTimeCriteria(None, "10ms, 50%, 3s")
self.http_relcriteria = TotalHTTPCodesCriteria(None, "50x, 10%, 3s")
self.http_abscriteria = TotalHTTPCodesCriteria(None, "50x, 30, 4s")
self.negative_http_relcriteria = TotalNegativeHTTPCodesCriteria(None, "2xx, 10%, 3s")
self.negative_http_abscriteria = TotalNegativeHTTPCodesCriteria(None, "20x, 30, 4s")
self.net_relcriteria = TotalNetCodesCriteria(None, "110, 37%, 3s")
self.net_abscriteria = TotalNetCodesCriteria(None, "71, 30, 2s")
self.negative_net_relcriteria = TotalNegativeNetCodesCriteria(None, "0, 45%, 5s")
self.negative_net_abscriteria = TotalNegativeNetCodesCriteria(None, "0, 100, 5s")
self.http_trend = TotalHTTPTrendCriteria(None, "2xx, 10s")
def tearDown(self):
#frac time
del self.frac_criteria
self.frac_criteria = None
#http
del self.http_relcriteria
self.http_relcriteria = None
del self.http_abscriteria
self.http_abscriteria = None
#negative http
del self.negative_http_relcriteria
self.negative_http_relcriteria = None
del self.negative_http_abscriteria
self.negative_http_abscriteria = None
#net
del self.net_relcriteria
self.net_relcriteria = None
del self.net_abscriteria
self.net_abscriteria = None
#negative net
del self.negative_net_relcriteria
self.negative_net_relcriteria = None
del self.negative_net_abscriteria
self.negative_net_abscriteria = None
#tangent of total_count
del self.http_trend
self.http_trend = None
def test_frac_null(self):
data = list()
for i in range(0,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
if i%5 != 0:
data.overall.times_dist = [
{'count': 10, 'to': 10, 'from': 0},
{'count': i+1, 'to': 20, 'from': 10}]
if self.frac_criteria.notify(data) :
break
if i != 13 :
raise RuntimeError();
def test_frac_run(self):
data = list()
for i in range(0,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.times_dist = [
{'count': 10, 'to': 10, 'from': 0},
{'count': i+1, 'to': 20, 'from': 10}]
if self.frac_criteria.notify(data):
break
if i != 11 :
raise RuntimeError()
def test_http_run_relative(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i*2
data.overall.http_codes = {'200': 100, '501': i, '503': i}
if self.http_relcriteria.notify(data):
break
if i != 7 : raise RuntimeError()
def test_http_run_absolute(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i*2
data.overall.http_codes = {'200': 100, '501': i, '503': i}
if self.http_abscriteria.notify(data) :
break
if i != 6 : raise RuntimeError()
def test_negative_http_run_relative(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 200 + 2*i
data.overall.http_codes = {'200': 100, '201': 100, '501': i, '503': i}
if self.negative_http_relcriteria.notify(data):
break
if i != 13 : raise RuntimeError()
def test_negative_http_run_absolute(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 200 + 2*i
data.overall.http_codes = {'200': 100, '201': 100, '302': i*2}
if self.negative_http_abscriteria.notify(data) :
break
if i != 6 : raise RuntimeError()
def test_net_run_relative(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i**2
data.overall.net_codes = {'0': 100, '110': i**2}
if self.net_relcriteria.notify(data) :
break
if i != 9 : raise RuntimeError()
def test_net_run_absolute(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i**2 + i
data.overall.net_codes = {'0': 100, '71': i**2, '110' : i}
if self.net_abscriteria.notify(data) :
break
if i != 5 : raise RuntimeError()
def test_negative_net_run_relative(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i**2
data.overall.net_codes = {'0': 100, '110': i**2}
if self.negative_net_relcriteria.notify(data) :
break
if i != 12 : raise RuntimeError()
def test_negative_net_run_absolute(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i**2
data.overall.net_codes = {'0': 100, '110': i**2}
if self.negative_net_abscriteria.notify(data) :
break
if i != 7 : raise RuntimeError()
def test_http_trend_run(self):
data = list()
for i in range(1,30):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 200
if i < 10 :
data.overall.RPS += i
data.overall.http_codes = {'200': 100+i, '201': 100}
elif i >= 10 and i < 20:
if i % 2:
diff = -3
else :
diff = 3
data.overall.RPS += 10 + diff
data.overall.http_codes = {'200': 110 + diff, '201': 100}
elif i >= 20 and i < 30:
diff = i - 20
data.overall.RPS += 10 - diff + i
data.overall.http_codes = {'200': 110 - diff, '201': 100, '502': i}
if self.http_trend.notify(data) :
break
if i != 28 :
raise RuntimeError()
if __name__ == '__main__':
unittest.main()

View File

@ -1,44 +0,0 @@
from Tank.Plugins.Aggregator import SecondAggregateData
from Tank.Plugins.TotalAutostop import TotalFracTimeCriteria
from Tests.TankTests import TankTestCase
import unittest
class TotalFracTimeCriteriaTest(TankTestCase):
def setUp(self):
self.criteria = TotalFracTimeCriteria(None, "10ms, 50%, 3s")
def tearDown(self):
del self.criteria
self.criteria = None
def test_null(self):
data = list()
for i in range(0,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:" + str(i)
if i%5 != 0:
data.overall.times_dist = [
{'count': 10, 'to': 10, 'from': 0},
{'count': i+1, 'to': 20, 'from': 10}]
if self.criteria.notify(data) :
break
if i != 13 :
raise RuntimeError();
def test_run(self):
data = list()
for i in range(0,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.times_dist = [
{'count': 10, 'to': 10, 'from': 0},
{'count': i+1, 'to': 20, 'from': 10}]
if self.criteria.notify(data):
break
if i != 11 :
raise RuntimeError()
if __name__ == '__main__':
unittest.main()

View File

@ -1,43 +0,0 @@
from Tank.Plugins.Aggregator import SecondAggregateData
from Tank.Plugins.TotalAutostop import TotalHTTPCodesCriteria
from Tests.TankTests import TankTestCase
import unittest
class TotalHTTPCodesCriteriaTest(TankTestCase):
def setUp(self):
self.relcriteria = TotalHTTPCodesCriteria(None, "50x, 10%, 3s")
self.abscriteria = TotalHTTPCodesCriteria(None, "50x, 30, 4s")
def tearDown(self):
del self.relcriteria
self.relcriteria = None
del self.abscriteria
self.abscriteria = None
def test_run_relative(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i*2
data.overall.http_codes = {'200': 100, '501': i, '503': i}
if self.relcriteria.notify(data):
break
if i != 7 : raise RuntimeError()
def test_run_absolute(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i*2
data.overall.http_codes = {'200': 100, '501': i, '503': i}
if self.abscriteria.notify(data) :
break
if i != 6 : raise RuntimeError()
if __name__ == '__main__':
unittest.main()

View File

@ -1,42 +0,0 @@
from Tank.Plugins.Aggregator import SecondAggregateData
from Tank.Plugins.TotalAutostop import TotalNegativeHTTPCodesCriteria
from Tests.TankTests import TankTestCase
import unittest
class TotalNegativeHTTPCodesCriteriaTest(TankTestCase):
def setUp(self):
self.relcriteria = TotalNegativeHTTPCodesCriteria(None, "2xx, 10%, 3s")
self.abscriteria = TotalNegativeHTTPCodesCriteria(None, "20x, 30, 4s")
def tearDown(self):
del self.relcriteria
self.relcriteria = None
del self.abscriteria
self.abscriteria = None
def test_run_relative(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 200 + 2*i
data.overall.http_codes = {'200': 100, '201': 100, '501': i, '503': i}
if self.relcriteria.notify(data):
break
if i != 13 : raise RuntimeError()
def test_run_absolute(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 200 + 2*i
data.overall.http_codes = {'200': 100, '201': 100, '302': i*2}
if self.abscriteria.notify(data) :
break
if i != 6 : raise RuntimeError()
if __name__ == '__main__':
unittest.main()

View File

@ -1,44 +0,0 @@
from Tank.Plugins.Aggregator import SecondAggregateData
from Tank.Plugins.TotalAutostop import TotalNetCodesCriteria
from Tests.TankTests import TankTestCase
import unittest
class TotalNetCodesCriteriaTest(TankTestCase):
def setUp(self):
self.relcriteria = TotalNetCodesCriteria(None, "110, 37%, 3s")
self.abscriteria = TotalNetCodesCriteria(None, "71, 30, 2s")
def tearDown(self):
del self.relcriteria
self.relcriteria = None
del self.abscriteria
self.abscriteria = None
def test_run_relative(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:" + str(i)
data.overall.RPS = 100 + i**2
data.overall.net_codes = {'0': 100, '110': i**2}
if self.relcriteria.notify(data) :
break
if i != 9 : raise RuntimeError()
def test_run_absolute(self):
data = list()
for i in range(1,20):
data = SecondAggregateData()
data.time = "2012-09-25 18:18:18"
data.overall.RPS = 100 + i**2 + i
data.overall.net_codes = {'0': 100, '71': i**2, '110' : i}
if self.abscriteria.notify(data) :
break
if i != 5 : raise RuntimeError()
if __name__ == '__main__':
unittest.main()