"Fossies" - the Fresh Open Source Software Archive

Member "monasca-api-4.0.0/monasca_api/tests/test_ad_repository.py" (13 May 2020, 43166 Bytes) of package /linux/misc/openstack/monasca-api-4.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_ad_repository.py": 3.1.0_vs_4.0.0.

    1 # Copyright 2015 Cray
    2 # Copyright 2016-2017 FUJITSU LIMITED
    3 # (C) Copyright 2016-2017 Hewlett Packard Enterprise Development LP
    4 #
    5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
    6 # not use this file except in compliance with the License. You may obtain
    7 # a copy of the License at
    8 #
    9 # http://www.apache.org/licenses/LICENSE-2.0
   10 #
   11 # Unless required by applicable law or agreed to in writing, software
   12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   14 # License for the specific language governing permissions and limitations
   15 # under the License.
   16 
   17 import datetime
   18 
   19 import fixtures
   20 from oslo_config import cfg
   21 from oslo_db.sqlalchemy.engines import create_engine
   22 from sqlalchemy import delete, MetaData, insert, bindparam, select, func
   23 
   24 from monasca_api.common.repositories import exceptions
   25 from monasca_api.common.repositories.model import sub_alarm_definition
   26 from monasca_api.common.repositories.sqla import models
   27 from monasca_api.expression_parser import alarm_expr_parser
   28 from monasca_api.tests import base
   29 
   30 CONF = cfg.CONF
   31 ALARM_DEF_123_FIELDS = {'actions_enabled': False,
   32                         'alarm_actions': u'29387234,77778687',
   33                         'description': None,
   34                         'expression': u'AVG(hpcs.compute{flavor_id=777, '
   35                         'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
   36                         'id': u'123',
   37                         'match_by': u'flavor_id,image_id',
   38                         'name': u'90% CPU',
   39                         'ok_actions': None,
   40                         'severity': u'LOW',
   41                         'undetermined_actions': None}
   42 TENANT_ID = 'bob'
   43 
   44 
   45 class TestAlarmDefinitionRepoDB(base.BaseTestCase):
   46 
   47     @classmethod
   48     def setUpClass(cls):
   49         engine = create_engine('sqlite://')
   50         qry = open('monasca_api/tests/sqlite_alarm.sql', 'r').read()
   51         sconn = engine.raw_connection()
   52         c = sconn.cursor()
   53         c.executescript(qry)
   54         sconn.commit()
   55         c.close()
   56         cls.engine = engine
   57 
   58         def _fake_engine_from_config(*args, **kw):
   59             return cls.engine
   60 
   61         cls.fixture = fixtures.MonkeyPatch(
   62             'sqlalchemy.create_engine', _fake_engine_from_config)
   63         cls.fixture.setUp()
   64         metadata = MetaData()
   65 
   66         cls.aa = models.create_aa_model(metadata)
   67         cls._delete_aa_query = delete(cls.aa)
   68         cls._insert_aa_query = (insert(cls.aa).values(
   69             alarm_definition_id=bindparam('alarm_definition_id'),
   70             alarm_state=bindparam('alarm_state'),
   71             action_id=bindparam('action_id')))
   72 
   73         cls.ad = models.create_ad_model(metadata)
   74         cls._delete_ad_query = delete(cls.ad)
   75         cls._insert_ad_query = (insert(cls.ad).values(
   76             id=bindparam('id'),
   77             tenant_id=bindparam('tenant_id'),
   78             name=bindparam('name'),
   79             severity=bindparam('severity'),
   80             expression=bindparam('expression'),
   81             match_by=bindparam('match_by'),
   82             actions_enabled=bindparam('actions_enabled'),
   83             created_at=bindparam('created_at'),
   84             updated_at=bindparam('updated_at'),
   85             deleted_at=bindparam('deleted_at')))
   86 
   87         cls.sad = models.create_sad_model(metadata)
   88         cls._delete_sad_query = delete(cls.sad)
   89         cls._insert_sad_query = (insert(cls.sad).values(
   90             id=bindparam('id'),
   91             alarm_definition_id=bindparam('alarm_definition_id'),
   92             function=bindparam('function'),
   93             metric_name=bindparam('metric_name'),
   94             operator=bindparam('operator'),
   95             threshold=bindparam('threshold'),
   96             period=bindparam('period'),
   97             periods=bindparam('periods'),
   98             is_deterministic=bindparam('is_deterministic'),
   99             created_at=bindparam('created_at'),
  100             updated_at=bindparam('updated_at')))
  101 
  102         cls.sadd = models.create_sadd_model(metadata)
  103         cls._delete_sadd_query = delete(cls.sadd)
  104         cls._insert_sadd_query = (insert(cls.sadd).values(
  105             sub_alarm_definition_id=bindparam('sub_alarm_definition_id'),
  106             dimension_name=bindparam('dimension_name'),
  107             value=bindparam('value')))
  108 
  109         cls.nm = models.create_nm_model(metadata)
  110         cls._delete_nm_query = delete(cls.nm)
  111         cls._insert_nm_query = (insert(cls.nm).values(
  112             id=bindparam('id'),
  113             tenant_id=bindparam('tenant_id'),
  114             name=bindparam('name'),
  115             type=bindparam('type'),
  116             address=bindparam('address'),
  117             created_at=bindparam('created_at'),
  118             updated_at=bindparam('updated_at')))
  119 
  120     @classmethod
  121     def tearDownClass(cls):
  122         cls.fixture.cleanUp()
  123         if hasattr(CONF, 'sql_engine'):
  124             delattr(CONF, 'sql_engine')
  125 
  126     def setUp(self):
  127         super(TestAlarmDefinitionRepoDB, self).setUp()
  128         self.conf_default(connection='sqlite://', group='database')
  129 
  130         from monasca_api.common.repositories.sqla import alarm_definitions_repository as adr
  131         self.repo = adr.AlarmDefinitionsRepository()
  132         self.default_ads = [{'id': '123',
  133                              'tenant_id': 'bob',
  134                              'name': '90% CPU',
  135                              'severity': 'LOW',
  136                              'expression': 'AVG(hpcs.compute{flavor_id=777,'
  137                              ' image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  138                              'match_by': 'flavor_id,image_id',
  139                              'actions_enabled': False,
  140                              'created_at': datetime.datetime.now(),
  141                              'updated_at': datetime.datetime.now(),
  142                              'deleted_at': None},
  143                             {'id': '234',
  144                              'tenant_id': 'bob',
  145                              'name': '50% CPU',
  146                              'severity': 'LOW',
  147                              'expression': 'AVG(hpcs.compute{flavor_id=777, '
  148                              'image_id=888, metric_name=mem}) > 20'
  149                              ' and AVG(hpcs.compute) < 100',
  150                              'match_by': 'flavor_id,image_id',
  151                              'actions_enabled': False,
  152                              'created_at': datetime.datetime.now(),
  153                              'updated_at': datetime.datetime.now(),
  154                              'deleted_at': None}]
  155 
  156         self.default_sads = [{'id': '111',
  157                               'alarm_definition_id': '123',
  158                               'function': 'AVG',
  159                               'metric_name': 'hpcs.compute',
  160                               'operator': 'GT',
  161                               'threshold': 10,
  162                               'period': 60,
  163                               'periods': 1,
  164                               'is_deterministic': True,
  165                               'created_at': datetime.datetime.now(),
  166                               'updated_at': datetime.datetime.now()},
  167                              {'id': '222',
  168                               'alarm_definition_id': '234',
  169                               'function': 'AVG',
  170                               'metric_name': 'hpcs.compute',
  171                               'operator': 'GT',
  172                               'threshold': 20,
  173                               'period': 60,
  174                               'periods': 1,
  175                               'is_deterministic': False,
  176                               'created_at': datetime.datetime.now(),
  177                               'updated_at': datetime.datetime.now()},
  178                              {'id': '223',
  179                               'alarm_definition_id': '234',
  180                               'function': 'AVG',
  181                               'metric_name': 'hpcs.compute',
  182                               'operator': 'LT',
  183                               'threshold': 100,
  184                               'period': 60,
  185                               'periods': 1,
  186                               'is_deterministic': False,
  187                               'created_at': datetime.datetime.now(),
  188                               'updated_at': datetime.datetime.now()},
  189                              ]
  190 
  191         self.default_sadds = [{'sub_alarm_definition_id': '111',
  192                                'dimension_name': 'flavor_id',
  193                                'value': '777'},
  194                               {'sub_alarm_definition_id': '111',
  195                                'dimension_name': 'image_id',
  196                                'value': '888'},
  197                               {'sub_alarm_definition_id': '111',
  198                                'dimension_name': 'metric_name',
  199                                'value': 'cpu'},
  200                               {'sub_alarm_definition_id': '111',
  201                                'dimension_name': 'device',
  202                                'value': '1'},
  203                               {'sub_alarm_definition_id': '222',
  204                                'dimension_name': 'flavor_id',
  205                                'value': '777'},
  206                               {'sub_alarm_definition_id': '222',
  207                                'dimension_name': 'image_id',
  208                                'value': '888'},
  209                               {'sub_alarm_definition_id': '222',
  210                                'dimension_name': 'metric_name',
  211                                'value': 'mem'}]
  212 
  213         self.default_nms = [{'id': '29387234',
  214                              'tenant_id': 'alarm-test',
  215                              'name': 'MyEmail',
  216                              'type': 'EMAIL',
  217                              'address': 'a@b',
  218                              'created_at': datetime.datetime.now(),
  219                              'updated_at': datetime.datetime.now()},
  220                             {'id': '77778687',
  221                              'tenant_id': 'alarm-test',
  222                              'name': 'OtherEmail',
  223                              'type': 'EMAIL',
  224                              'address': 'a@b',
  225                              'created_at': datetime.datetime.now(),
  226                              'updated_at': datetime.datetime.now()}]
  227 
  228         self.default_aas = [{'alarm_definition_id': '123',
  229                              'alarm_state': 'ALARM',
  230                              'action_id': '29387234'},
  231                             {'alarm_definition_id': '123',
  232                              'alarm_state': 'ALARM',
  233                              'action_id': '77778687'},
  234                             {'alarm_definition_id': '234',
  235                              'alarm_state': 'ALARM',
  236                              'action_id': '29387234'},
  237                             {'alarm_definition_id': '234',
  238                              'alarm_state': 'ALARM',
  239                              'action_id': '77778687'}]
  240 
  241         with self.engine.begin() as conn:
  242             conn.execute(self._delete_ad_query)
  243             conn.execute(self._insert_ad_query, self.default_ads)
  244             conn.execute(self._delete_sad_query)
  245             conn.execute(self._insert_sad_query, self.default_sads)
  246             conn.execute(self._delete_sadd_query)
  247             conn.execute(self._insert_sadd_query, self.default_sadds)
  248             conn.execute(self._delete_nm_query)
  249             conn.execute(self._insert_nm_query, self.default_nms)
  250             conn.execute(self._delete_aa_query)
  251             conn.execute(self._insert_aa_query, self.default_aas)
  252 
  253     def test_should_create(self):
  254         expression = ('AVG(hpcs.compute{flavor_id=777, image_id=888,'
  255                       ' metric_name=cpu}) > 10')
  256         description = ''
  257         match_by = ['flavor_id', 'image_id']
  258         sub_expr_list = (alarm_expr_parser.AlarmExprParser(expression).sub_expr_list)
  259         alarm_actions = ['29387234', '77778687']
  260         alarmA_id = self.repo.create_alarm_definition('555',
  261                                                       '90% CPU',
  262                                                       expression,
  263                                                       sub_expr_list,
  264                                                       description,
  265                                                       'LOW',
  266                                                       match_by,
  267                                                       alarm_actions,
  268                                                       None,
  269                                                       None)
  270 
  271         alarmB = self.repo.get_alarm_definition('555', alarmA_id)
  272 
  273         self.assertEqual(alarmA_id, alarmB['id'])
  274 
  275         query_sad = (select([self.sad.c.id])
  276                      .select_from(self.sad)
  277                      .where(self.sad.c.alarm_definition_id == alarmA_id))
  278 
  279         query_sadd = (select([func.count()])
  280                       .select_from(self.sadd)
  281                       .where(self.sadd.c.sub_alarm_definition_id == bindparam('id')))
  282 
  283         with self.engine.connect() as conn:
  284             count_sad = conn.execute(query_sad).fetchall()
  285             self.assertEqual(len(count_sad), 1)
  286             count_sadd = conn.execute(query_sadd, id=count_sad[0][0]).fetchone()
  287             self.assertEqual(count_sadd[0], 3)
  288 
  289     def test_should_try_to_create_with_wrong_alarm_action(self):
  290         expression = ('AVG(hpcs.compute{flavor_id=777, image_id=888,'
  291                       ' metric_name=cpu}) > 10')
  292         description = ''
  293         match_by = ['flavor_id', 'image_id']
  294         sub_expr_list = alarm_expr_parser.AlarmExprParser(expression).sub_expr_list
  295         alarm_actions = ['66666666']
  296         args = ('555',
  297                 '90% CPU',
  298                 expression,
  299                 sub_expr_list,
  300                 description,
  301                 'LOW',
  302                 match_by,
  303                 alarm_actions,
  304                 None,
  305                 None)
  306         self.assertRaises(exceptions.InvalidUpdateException,
  307                           self.repo.create_alarm_definition, *args)
  308 
  309     def test_should_update(self):
  310         expression = ''.join(['AVG(hpcs.compute{flavor_id=777, image_id=888,',
  311                               ' metric_name=mem}) > 20 and',
  312                               ' AVG(hpcs.compute) < 100'])
  313         description = ''
  314         match_by = ['flavor_id', 'image_id']
  315         sub_expr_list = (alarm_expr_parser.AlarmExprParser(expression).sub_expr_list)
  316         alarm_actions = ['29387234', '77778687']
  317         self.repo.update_or_patch_alarm_definition('bob', '234',
  318                                                    '90% CPU', expression,
  319                                                    sub_expr_list, False,
  320                                                    description, alarm_actions,
  321                                                    None, None,
  322                                                    match_by, 'LOW')
  323         alarm = self.repo.get_alarm_definition('bob', '234')
  324         expected = {'actions_enabled': False,
  325                     'alarm_actions': '29387234,77778687',
  326                     'description': '',
  327                     'expression': 'AVG(hpcs.compute{flavor_id=777, '
  328                     'image_id=888, metric_name=mem}) > 20 and'
  329                     ' AVG(hpcs.compute) < 100',
  330                     'id': '234',
  331                     'match_by': 'flavor_id,image_id',
  332                     'name': '90% CPU',
  333                     'ok_actions': None,
  334                     'severity': 'LOW',
  335                     'undetermined_actions': None}
  336 
  337         self.assertEqual(alarm, expected)
  338 
  339         sub_alarms = self.repo.get_sub_alarm_definitions('234')
  340 
  341         expected = [{'alarm_definition_id': '234',
  342                      'dimensions': 'flavor_id=777,image_id=888,'
  343                      'metric_name=mem',
  344                      'function': 'AVG',
  345                      'id': '222',
  346                      'metric_name': 'hpcs.compute',
  347                      'operator': 'GT',
  348                      'period': 60,
  349                      'periods': 1,
  350                      'is_deterministic': False,
  351                      'threshold': 20.0},
  352                     {'alarm_definition_id': '234',
  353                      'dimensions': None,
  354                      'function': 'AVG',
  355                      'id': '223',
  356                      'metric_name': 'hpcs.compute',
  357                      'operator': 'LT',
  358                      'period': 60,
  359                      'periods': 1,
  360                      'is_deterministic': False,
  361                      'threshold': 100.0}]
  362 
  363         self.assertEqual(len(sub_alarms), len(expected))
  364 
  365         for s, e in zip(sub_alarms, expected):
  366             e['created_at'] = s['created_at']
  367             e['updated_at'] = s['updated_at']
  368 
  369         self.assertEqual(sub_alarms, expected)
  370         am = self.repo.get_alarm_metrics('bob', '234')
  371         self.assertEqual(am, [])
  372 
  373         sub_alarms = self.repo.get_sub_alarms('bob', '234')
  374         self.assertEqual(sub_alarms, [])
  375 
  376         ads = self.repo.get_alarm_definitions(
  377             'bob', '90% CPU', {
  378                 'image_id': '888'}, None, None, 0, 100)
  379         expected = [{'actions_enabled': False,
  380                      'alarm_actions': '29387234,77778687',
  381                      'description': None,
  382                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  383                      'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  384                      'id': '123',
  385                      'match_by': 'flavor_id,image_id',
  386                      'name': '90% CPU',
  387                      'ok_actions': None,
  388                      'severity': 'LOW',
  389                      'undetermined_actions': None},
  390                     {'actions_enabled': False,
  391                      'alarm_actions': '29387234,77778687',
  392                      'description': '',
  393                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  394                      'image_id=888, metric_name=mem}) > 20 and'
  395                      ' AVG(hpcs.compute) < 100',
  396                      'id': '234',
  397                      'match_by': 'flavor_id,image_id',
  398                      'name': '90% CPU',
  399                      'ok_actions': None,
  400                      'severity': 'LOW',
  401                      'undetermined_actions': None}]
  402         self.assertEqual(ads, expected)
  403 
  404         ads = self.repo.get_alarm_definitions(
  405             'bob', '90% CPU', {
  406                 'image_id': '888'}, 'LOW', None, 0, 100)
  407         expected = [{'actions_enabled': False,
  408                      'alarm_actions': '29387234,77778687',
  409                      'description': None,
  410                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  411                      'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  412                      'id': '123',
  413                      'match_by': 'flavor_id,image_id',
  414                      'name': '90% CPU',
  415                      'ok_actions': None,
  416                      'severity': 'LOW',
  417                      'undetermined_actions': None},
  418                     {'actions_enabled': False,
  419                      'alarm_actions': '29387234,77778687',
  420                      'description': '',
  421                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  422                      'image_id=888, metric_name=mem}) > 20 and'
  423                      ' AVG(hpcs.compute) < 100',
  424                      'id': '234',
  425                      'match_by': 'flavor_id,image_id',
  426                      'name': '90% CPU',
  427                      'ok_actions': None,
  428                      'severity': 'LOW',
  429                      'undetermined_actions': None}]
  430         self.assertEqual(ads, expected)
  431 
  432         ads = self.repo.get_alarm_definitions(
  433             'bob', '90% CPU', {
  434                 'image_id': '888'}, 'CRITICAL', None, 0, 100)
  435         expected = []
  436         self.assertEqual(ads, expected)
  437 
  438         self.repo.update_or_patch_alarm_definition('bob', '234',
  439                                                    '90% CPU', None,
  440                                                    sub_expr_list, False,
  441                                                    description, alarm_actions,
  442                                                    None, None,
  443                                                    match_by, 'LOW')
  444 
  445         self.repo.update_or_patch_alarm_definition('bob', '234',
  446                                                    None, None,
  447                                                    None, True,
  448                                                    None, None,
  449                                                    None, None,
  450                                                    None, None,
  451                                                    True)
  452 
  453         self.repo.update_or_patch_alarm_definition('bob', '234',
  454                                                    None, None,
  455                                                    None, None,
  456                                                    None, None,
  457                                                    None, None,
  458                                                    None, None,
  459                                                    True)
  460 
  461         self.repo.update_or_patch_alarm_definition('bob', '234',
  462                                                    None, None,
  463                                                    None, None,
  464                                                    None, [],
  465                                                    [], [],
  466                                                    None, None,
  467                                                    True)
  468 
  469         self.repo.update_or_patch_alarm_definition('bob', '234',
  470                                                    None, None,
  471                                                    None, False,
  472                                                    None, None,
  473                                                    None, None,
  474                                                    match_by, None,
  475                                                    False)
  476 
  477         self.assertRaises(exceptions.InvalidUpdateException,
  478                           self.repo.update_or_patch_alarm_definition,
  479                           'bob', '234',
  480                           None, None,
  481                           None, False,
  482                           None, None,
  483                           None, None,
  484                           None, None,
  485                           False)
  486 
  487         self.assertRaises(exceptions.InvalidUpdateException,
  488                           self.repo.update_or_patch_alarm_definition,
  489                           'bob', '234',
  490                           '90% CPU', None,
  491                           sub_expr_list, False,
  492                           description, alarm_actions,
  493                           None, None,
  494                           'update_match_by', 'LOW')
  495 
  496         self.repo.delete_alarm_definition('bob', '234')
  497 
  498         self.assertRaises(exceptions.DoesNotExistException,
  499                           self.repo.get_alarm_definition, 'bob', '234')
  500 
  501     def test_should_find_by_id(self):
  502         alarmDef1 = self.repo.get_alarm_definition('bob', '123')
  503         expected = {'actions_enabled': False,
  504                     'alarm_actions': '29387234,77778687',
  505                     'description': None,
  506                     'expression': 'AVG(hpcs.compute{flavor_id=777, '
  507                     'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  508                     'id': '123',
  509                     'match_by': 'flavor_id,image_id',
  510                     'name': '90% CPU',
  511                     'ok_actions': None,
  512                     'severity': 'LOW',
  513                     'undetermined_actions': None}
  514         self.assertEqual(alarmDef1, expected)
  515         with self.engine.begin() as conn:
  516             conn.execute(self._delete_aa_query)
  517 
  518         alarmDef2 = self.repo.get_alarm_definition('bob', '123')
  519         expected['alarm_actions'] = None
  520         self.assertEqual(alarmDef2, expected)
  521 
  522     def test_shoud_find_sub_alarm_metric_definitions(self):
  523         sub_alarms = self.repo.get_sub_alarm_definitions('123')
  524 
  525         expected = [{'alarm_definition_id': '123',
  526                      'dimensions': 'flavor_id=777,image_id=888,'
  527                      'metric_name=cpu,device=1',
  528                      'function': 'AVG',
  529                      'id': '111',
  530                      'metric_name': 'hpcs.compute',
  531                      'operator': 'GT',
  532                      'period': 60,
  533                      'periods': 1,
  534                      'is_deterministic': True,
  535                      'threshold': 10.0}]
  536 
  537         self.assertEqual(len(sub_alarms), len(expected))
  538 
  539         for s, e in zip(sub_alarms, expected):
  540             e['created_at'] = s['created_at']
  541             e['updated_at'] = s['updated_at']
  542 
  543         self.assertEqual(sub_alarms, expected)
  544 
  545         sub_alarms = self.repo.get_sub_alarm_definitions('234')
  546 
  547         expected = [{'alarm_definition_id': '234',
  548                      'dimensions': 'flavor_id=777,image_id=888,metric_name=mem',
  549                      'function': 'AVG',
  550                      'id': '222',
  551                      'metric_name': 'hpcs.compute',
  552                      'operator': 'GT',
  553                      'period': 60,
  554                      'periods': 1,
  555                      'is_deterministic': False,
  556                      'threshold': 20.0},
  557                     {'alarm_definition_id': '234',
  558                      'dimensions': None,
  559                      'function': 'AVG',
  560                      'id': '223',
  561                      'metric_name': 'hpcs.compute',
  562                      'operator': 'LT',
  563                      'period': 60,
  564                      'periods': 1,
  565                      'is_deterministic': False,
  566                      'threshold': 100.0}]
  567 
  568         self.assertEqual(len(sub_alarms), len(expected))
  569 
  570         for s, e in zip(sub_alarms, expected):
  571             e['created_at'] = s['created_at']
  572             e['updated_at'] = s['updated_at']
  573 
  574         self.assertEqual(sub_alarms, expected)
  575 
  576         sub_alarms = self.repo.get_sub_alarm_definitions('asdfasdf')
  577         self.assertEqual(sub_alarms, [])
  578 
  579     def test_try_update_alarm_that_does_not_exist(self):
  580         args = ('koala', '999',
  581                 None, None,
  582                 None, True,
  583                 None, None,
  584                 None, None,
  585                 None, None,
  586                 True)
  587         self.assertRaises(exceptions.DoesNotExistException,
  588                           self.repo.update_or_patch_alarm_definition, *args)
  589 
  590     def test_exists(self):
  591         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  592                                                     name='90% CPU')
  593         expected = {'actions_enabled': False,
  594                     'alarm_actions': '29387234,77778687',
  595                     'description': None,
  596                     'expression': 'AVG(hpcs.compute{flavor_id=777, '
  597                     'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  598                     'id': '123',
  599                     'match_by': 'flavor_id,image_id',
  600                     'name': '90% CPU',
  601                     'ok_actions': None,
  602                     'severity': 'LOW',
  603                     'undetermined_actions': None}
  604 
  605         self.assertEqual(alarmDef1, [expected])
  606         alarmDef2 = self.repo.get_alarm_definitions(tenant_id='bob',
  607                                                     name='999% CPU')
  608         self.assertEqual(alarmDef2, [])
  609 
  610     def test_should_find(self):
  611         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  612                                                     limit=1)
  613         expected = [{'actions_enabled': False,
  614                      'alarm_actions': '29387234,77778687',
  615                      'description': None,
  616                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  617                      'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  618                      'id': '123',
  619                      'match_by': 'flavor_id,image_id',
  620                      'name': '90% CPU',
  621                      'ok_actions': None,
  622                      'severity': 'LOW',
  623                      'undetermined_actions': None},
  624                     {'actions_enabled': False,
  625                      'alarm_actions': '29387234,77778687',
  626                      'description': None,
  627                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  628                      'image_id=888, metric_name=mem}) > 20 and '
  629                      'AVG(hpcs.compute) < 100',
  630                      'id': '234',
  631                      'match_by': 'flavor_id,image_id',
  632                      'name': '50% CPU',
  633                      'ok_actions': None,
  634                      'severity': 'LOW',
  635                      'undetermined_actions': None}]
  636 
  637         self.assertEqual(alarmDef1, expected)
  638         with self.engine.begin() as conn:
  639             conn.execute(self._delete_aa_query)
  640 
  641         alarmDef2 = self.repo.get_alarm_definitions(tenant_id='bob',
  642                                                     limit=1)
  643         expected[0]['alarm_actions'] = None
  644         expected[1]['alarm_actions'] = None
  645         self.assertEqual(alarmDef2, expected)
  646 
  647         alarmDef3 = self.repo.get_alarm_definitions(tenant_id='bill',
  648                                                     limit=1)
  649         self.assertEqual(alarmDef3, [])
  650 
  651         alarmDef3 = self.repo.get_alarm_definitions(tenant_id='bill',
  652                                                     offset='10',
  653                                                     limit=1)
  654         self.assertEqual(alarmDef3, [])
  655 
  656     def test_should_find_by_dimension(self):
  657         expected = [{'actions_enabled': False,
  658                      'alarm_actions': '29387234,77778687',
  659                      'description': None,
  660                      'expression': 'AVG(hpcs.compute{flavor_id=777,'
  661                      ' image_id=888, metric_name=mem}) > 20 '
  662                      'and AVG(hpcs.compute) < 100',
  663                      'id': '234',
  664                      'match_by': 'flavor_id,image_id',
  665                      'name': '50% CPU',
  666                      'ok_actions': None,
  667                      'severity': 'LOW',
  668                      'undetermined_actions': None}]
  669 
  670         dimensions = {'image_id': '888', 'metric_name': 'mem'}
  671         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  672                                                     dimensions=dimensions,
  673                                                     limit=1)
  674         self.assertEqual(alarmDef1, expected)
  675 
  676         expected = [{'actions_enabled': False,
  677                      'alarm_actions': '29387234,77778687',
  678                      'description': None,
  679                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  680                      'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  681                      'id': '123',
  682                      'match_by': 'flavor_id,image_id',
  683                      'name': '90% CPU',
  684                      'ok_actions': None,
  685                      'severity': 'LOW',
  686                      'undetermined_actions': None},
  687                     {'actions_enabled': False,
  688                      'alarm_actions': '29387234,77778687',
  689                      'description': None,
  690                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  691                      'image_id=888, metric_name=mem}) > 20 and '
  692                      'AVG(hpcs.compute) < 100',
  693                      'id': '234',
  694                      'match_by': 'flavor_id,image_id',
  695                      'name': '50% CPU',
  696                      'ok_actions': None,
  697                      'severity': 'LOW',
  698                      'undetermined_actions': None}]
  699 
  700         dimensions = {'image_id': '888'}
  701         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  702                                                     dimensions=dimensions,
  703                                                     limit=1)
  704         self.assertEqual(alarmDef1, expected)
  705 
  706         expected = [{'actions_enabled': False,
  707                      'alarm_actions': '29387234,77778687',
  708                      'description': None,
  709                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  710                      'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  711                      'id': '123',
  712                      'match_by': 'flavor_id,image_id',
  713                      'name': '90% CPU',
  714                      'ok_actions': None,
  715                      'severity': 'LOW',
  716                      'undetermined_actions': None}]
  717 
  718         dimensions = {'device': '1'}
  719         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  720                                                     dimensions=dimensions,
  721                                                     limit=1)
  722         self.assertEqual(alarmDef1, expected)
  723 
  724         dimensions = {'Not real': 'AA'}
  725         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  726                                                     dimensions=dimensions,
  727                                                     limit=1)
  728         self.assertEqual(alarmDef1, [])
  729 
  730     def test_should_find_and_sort(self):
  731         expected = [{'actions_enabled': False,
  732                      'alarm_actions': '29387234,77778687',
  733                      'description': None,
  734                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  735                      'image_id=888, metric_name=cpu, device=1},deterministic) > 10',
  736                      'id': '123',
  737                      'match_by': 'flavor_id,image_id',
  738                      'name': '90% CPU',
  739                      'ok_actions': None,
  740                      'severity': 'LOW',
  741                      'undetermined_actions': None},
  742                     {'actions_enabled': False,
  743                      'alarm_actions': '29387234,77778687',
  744                      'description': None,
  745                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  746                      'image_id=888, metric_name=mem}) > 20 and '
  747                      'AVG(hpcs.compute) < 100',
  748                      'id': '234',
  749                      'match_by': 'flavor_id,image_id',
  750                      'name': '50% CPU',
  751                      'ok_actions': None,
  752                      'severity': 'LOW',
  753                      'undetermined_actions': None}]
  754 
  755         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  756                                                     sort_by=['id'])
  757         self.assertEqual(expected, alarmDef1)
  758         alarmDef2 = self.repo.get_alarm_definitions(tenant_id='bob',
  759                                                     sort_by=['name'])
  760         self.assertEqual(expected[::-1], alarmDef2)
  761 
  762     def test_should_delete_by_id(self):
  763         self.repo.delete_alarm_definition('bob', '123')
  764         from monasca_api.common.repositories import exceptions
  765         self.assertRaises(exceptions.DoesNotExistException,
  766                           self.repo.get_alarm_definition,
  767                           'bob',
  768                           '123')
  769 
  770         expected = [{'actions_enabled': False,
  771                      'alarm_actions': '29387234,77778687',
  772                      'description': None,
  773                      'expression': 'AVG(hpcs.compute{flavor_id=777, '
  774                      'image_id=888, metric_name=mem}) > 20 '
  775                      'and AVG(hpcs.compute) < 100',
  776                      'id': '234',
  777                      'match_by': 'flavor_id,image_id',
  778                      'name': '50% CPU',
  779                      'ok_actions': None,
  780                      'severity': 'LOW',
  781                      'undetermined_actions': None}]
  782 
  783         alarmDef1 = self.repo.get_alarm_definitions(tenant_id='bob',
  784                                                     limit=1)
  785         self.assertEqual(alarmDef1, expected)
  786 
  787     def test_try_delete_alarm_that_does_not_exist(self):
  788         response = self.repo.delete_alarm_definition('goku', '123')
  789         self.assertEqual(False, response)
  790 
  791     def test_should_patch_name(self):
  792         self.run_patch_test(name=u'90% CPU New')
  793 
  794     def test_should_patch_description(self):
  795         self.run_patch_test(description=u'New Description')
  796 
  797     def test_should_patch_severity(self):
  798         self.run_patch_test(severity=u'CRITICAL')
  799 
  800     def test_should_patch_actions_enabled(self):
  801         self.run_patch_test(actions_enabled=False)
  802 
  803     def test_should_patch_ok_actions(self):
  804         self.run_patch_test(ok_actions=[u'29387234'])
  805 
  806     def test_should_patch_alarm_actions(self):
  807         self.run_patch_test(alarm_actions=[u'29387234'])
  808 
  809     def test_should_patch_undetermined_actions(self):
  810         self.run_patch_test(undetermined_actions=[u'29387234', u'77778687'])
  811 
  812     def test_should_patch_match_by(self):
  813         # match_by can't change, so make sure old value works
  814         self.run_patch_test(match_by=[u'flavor_id', u'image_id'])
  815 
  816     def test_should_patch_expression_no_change(self):
  817         # match_by can't change, so make sure old value works
  818         self.run_patch_test(expression=ALARM_DEF_123_FIELDS['expression'])
  819 
  820     def test_should_patch_expression_threshold_change(self):
  821         self.run_patch_test(expression=ALARM_DEF_123_FIELDS['expression'].replace(' 10', ' 20'))
  822 
  823     def test_should_patch_expression_deterministic_change(self):
  824         self.run_patch_test(expression=ALARM_DEF_123_FIELDS['expression'].replace(',deterministic',
  825                                                                                   ''))
  826 
  827     def test_should_patch_expression_function_change(self):
  828         self.run_patch_test(expression=ALARM_DEF_123_FIELDS['expression'].replace('AVG', 'MAX'))
  829 
  830     def test_should_patch_expression_operation_change(self):
  831         self.run_patch_test(expression=ALARM_DEF_123_FIELDS['expression'].replace('>', '<'))
  832 
  833     def test_should_patch_expression_period_change(self):
  834         self.run_patch_test(expression=ALARM_DEF_123_FIELDS['expression'].replace(')', ', 120)'))
  835 
  836     def test_should_patch_expression_periods_change(self):
  837         self.run_patch_test(
  838             expression=ALARM_DEF_123_FIELDS['expression'].replace(
  839                 ' 10', ' 10 times 2'))
  840 
  841     def test_patch_fails_change_match_by(self):
  842         self.assertRaises(
  843             exceptions.InvalidUpdateException,
  844             self.run_patch_test,
  845             match_by=u'device')
  846 
  847     def test_patch_fails_change_metric_name(self):
  848         self.assertRaises(exceptions.InvalidUpdateException, self.run_patch_test,
  849                           expression=ALARM_DEF_123_FIELDS['expression'].replace('hpcs.compute',
  850                                                                                 'new_metric_name'))
  851 
  852     def test_patch_fails_change_metric_dimensions(self):
  853         self.assertRaises(exceptions.InvalidUpdateException, self.run_patch_test,
  854                           expression=ALARM_DEF_123_FIELDS['expression'].replace('image_id=888',
  855                                                                                 'image_id=42'))
  856 
  857     def test_patch_fails_change_num_sub_expressions(self):
  858         self.assertRaises(exceptions.InvalidUpdateException, self.run_patch_test,
  859                           expression=ALARM_DEF_123_FIELDS['expression']
  860                           .replace(' 10', ' 10 and MAX(cpu.idle_perc) < 10'))
  861 
  862     def run_patch_test(self, name=None, expression=None, description=None, actions_enabled=None,
  863                        alarm_actions=None, ok_actions=None, undetermined_actions=None,
  864                        match_by=None, severity=None):
  865         if expression:
  866             sub_expr_list = (alarm_expr_parser.AlarmExprParser(expression).sub_expr_list)
  867         else:
  868             sub_expr_list = None
  869         updates = self.repo.update_or_patch_alarm_definition(TENANT_ID, '123',
  870                                                              name, expression,
  871                                                              sub_expr_list, actions_enabled,
  872                                                              description, alarm_actions,
  873                                                              ok_actions, undetermined_actions,
  874                                                              match_by, severity,
  875                                                              patch=True)
  876 
  877         alarm_def_row = \
  878             (ALARM_DEF_123_FIELDS['id'],
  879              name if name else ALARM_DEF_123_FIELDS['name'],
  880              description if description else ALARM_DEF_123_FIELDS['description'],
  881              expression if expression else ALARM_DEF_123_FIELDS['expression'],
  882              ALARM_DEF_123_FIELDS['match_by'],  # match-by can't change
  883              severity if severity else ALARM_DEF_123_FIELDS['severity'],
  884              actions_enabled if actions_enabled else ALARM_DEF_123_FIELDS['actions_enabled'],
  885              u','.join(alarm_actions) if alarm_actions else ALARM_DEF_123_FIELDS['alarm_actions'],
  886              u','.join(ok_actions) if ok_actions else ALARM_DEF_123_FIELDS['ok_actions'],
  887              (u','.join(undetermined_actions) if undetermined_actions else
  888               ALARM_DEF_123_FIELDS['undetermined_actions']))
  889 
  890         sad = self.default_sads[0]
  891         if expression and ALARM_DEF_123_FIELDS['expression'] != expression:
  892             sub_expr = sub_expr_list[0]
  893             sub_alarm_def = sub_alarm_definition.SubAlarmDefinition(
  894                 row={'id': '',
  895                      'alarm_definition_id': sad['alarm_definition_id'],
  896                      'function': sub_expr.normalized_func,
  897                      'metric_name': sub_expr.metric_name,
  898                      'dimensions': u'device=1,image_id=888,flavor_id=777,metric_name=cpu',
  899                      'operator': sub_expr.normalized_operator,
  900                      'threshold': sub_expr.threshold,
  901                      'period': sub_expr.period,
  902                      'is_deterministic': sub_expr.deterministic,
  903                      'periods': sub_expr.periods})
  904             expected_sub_alarm_maps = {
  905                 'changed': {
  906                     u'111': sub_alarm_def},
  907                 'new': {},
  908                 'old': {},
  909                 'unchanged': {}}
  910         else:
  911             sub_alarm_def = sub_alarm_definition.SubAlarmDefinition(
  912                 row={'id': sad['id'],
  913                      'alarm_definition_id': sad['alarm_definition_id'],
  914                      'function': sad['function'],
  915                      'metric_name': sad['metric_name'],
  916                      'dimensions': u'device=1,image_id=888,flavor_id=777,metric_name=cpu',
  917                      'operator': sad['operator'],
  918                      'threshold': sad['threshold'],
  919                      'period': sad['period'],
  920                      'is_deterministic': sad['is_deterministic'],
  921                      'periods': sad['periods']})
  922             expected_sub_alarm_maps = {'changed': {}, 'new': {},
  923                                        'old': {}, 'unchanged': {u'111': sub_alarm_def}}
  924         self.assertEqual((alarm_def_row, expected_sub_alarm_maps), updates)