def testDELETEAutostackMetricsFromModelsAPI(self, repositoryMock, *_args):
    repositoryMock.getMetric.return_value = self.metric

    app = TestApp(models_api.app.wsgifunc())

    with self.assertRaises(AppError) as e:
      app.delete("/" + self.metric.uid, headers=self.headers)

    self.assertIn("Bad response: 405 Method Not Allowed", str(e.exception))
 def _deleteOneMetric(self):
   """
   Delete one metric from test EC2 instance
   """
   app = TestApp(models_api.app.wsgifunc())
   response = app.get("/", headers=self.headers)
   assertions.assertSuccess(self, response)
   result = app_utils.jsonDecode(response.body)
   self.assertIsInstance(result, list)
   app.delete("/" + result[0]['uid'], headers=self.headers)
class TestAutostackHandler(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    cls.autostack = Mock(uid="blahblahblah",
                         region="bogus",
                         filters=jsonEncode({"tag:Name":["Bogus"]}))
    cls.autostack.name = "Test"

    cls.jsonAutostack = jsonEncode({"uid":"blahblahblah",
                                    "name":"Test",
                                    "region":"bogus",
                                    "filters":{"tag:Name":["Bogus"]}})


  def setUp(self):
    self.headers = getDefaultHTTPHeaders(htm.it.app.config)
    self.app = TestApp(autostacks_api.app.wsgifunc())


  @patch("htm.it.app.webservices.autostacks_api.repository")
  def testDELETEAutostackWithoutModels(self, repositoryMock, *_args):
    autostack = Mock(uid="xyz",
                     name="Test",
                     region="Bogus",
                     filters={"tag:Name": ["Bogus"]})
    repositoryMock.getAutostackMetrics.return_value = iter([])

    response = self.app.delete("/" + autostack.uid,
                               headers=self.headers)

    self.assertEqual(response.status, 204)
    self.assertTrue(repositoryMock.deleteAutostack.called)
    repositoryMock.deleteAutostack.assert_called_with(ANY, autostack.uid)


  @patch("htm.it.app.webservices.autostacks_api.repository")
  @patch("htmengine.model_swapper.utils.deleteHTMModel", autospec=True)
  def testDELETEAutostackWithModels(self,
                                    _deleteHTMModelMock,
                                    repositoryMock,
                                    *_args):
    autostack = Mock(uid="xyz",
                     name="Test",
                     region="Bogus",
                     filters={"tag:Name": ["Bogus"]})
    metricMock = Mock(uid="abc")
    repositoryMock.getAutostackMetrics.return_value = iter([metricMock])
    response = self.app.delete("/" + autostack.uid,
                               headers=self.headers)
    self.assertEqual(response.status, 204)
    self.assertTrue(repositoryMock.deleteAutostack)
    repositoryMock.deleteAutostack.assert_called_with(ANY, autostack.uid)
class TestAutostackHandler(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.autostack = Mock(uid="blahblahblah",
                             region="bogus",
                             filters=jsonEncode({"tag:Name": ["Bogus"]}))
        cls.autostack.name = "Test"

        cls.jsonAutostack = jsonEncode({
            "uid": "blahblahblah",
            "name": "Test",
            "region": "bogus",
            "filters": {
                "tag:Name": ["Bogus"]
            }
        })

    def setUp(self):
        self.headers = getDefaultHTTPHeaders(htm.it.app.config)
        self.app = TestApp(autostacks_api.app.wsgifunc())

    @patch("htm.it.app.webservices.autostacks_api.repository")
    def testDELETEAutostackWithoutModels(self, repositoryMock, *_args):
        autostack = Mock(uid="xyz",
                         name="Test",
                         region="Bogus",
                         filters={"tag:Name": ["Bogus"]})
        repositoryMock.getAutostackMetrics.return_value = iter([])

        response = self.app.delete("/" + autostack.uid, headers=self.headers)

        self.assertEqual(response.status, 204)
        self.assertTrue(repositoryMock.deleteAutostack.called)
        repositoryMock.deleteAutostack.assert_called_with(ANY, autostack.uid)

    @patch("htm.it.app.webservices.autostacks_api.repository")
    @patch("htmengine.model_swapper.utils.deleteHTMModel", autospec=True)
    def testDELETEAutostackWithModels(self, _deleteHTMModelMock,
                                      repositoryMock, *_args):
        autostack = Mock(uid="xyz",
                         name="Test",
                         region="Bogus",
                         filters={"tag:Name": ["Bogus"]})
        metricMock = Mock(uid="abc")
        repositoryMock.getAutostackMetrics.return_value = iter([metricMock])
        response = self.app.delete("/" + autostack.uid, headers=self.headers)
        self.assertEqual(response.status, 204)
        self.assertTrue(repositoryMock.deleteAutostack)
        repositoryMock.deleteAutostack.assert_called_with(ANY, autostack.uid)
class InstanceHandlerTest(unittest.TestCase):
  """Unit tests for class InstanceHandler from Instances API."""


  def setUp(self):
    self.app = TestApp(instances_api.app.wsgifunc())
    self.headers = getDefaultHTTPHeaders(config)


  @patch.object(repository, "listMetricIDsForInstance", autospec=True)
  @patch("grok.app.webservices.models_api.ModelHandler.deleteModel",
    new=Mock(spec_set=models_api.ModelHandler.deleteModel))
  def testDeleteInstanceHandler(self, listMetricIDsMock, engineFactoryMock):
    """
    Test for Delete "/_instances/<instanceId>"
    response is validated for appropriate headers, body and status
    """
    listMetricIDsMock.return_value = ["2490fb7a9df5470fa3678530c4cb0a43",
                                      "b491ab2310ef4a799b14c08fa3e09f1c"]
    response = self.app.delete("", headers=self.headers,
                               params=json.dumps(["i-cd660efb"]))

    assertions.assertDeleteSuccessResponse(self, response)
    self.assertTrue(listMetricIDsMock.called)
    listMetricIDsMock.assert_called_once_with(
      (engineFactoryMock.return_value.connect.return_value.__enter__
       .return_value),
      "i-cd660efb")
def test_fixture():
    app = TestApp(SimpleApplication())
    res = app.get('/', params={'a': ['1', '2']})
    assert (res.request.environ['QUERY_STRING'] ==
            'a=1&a=2')
    res = app.put('/')
    assert (res.request.environ['REQUEST_METHOD'] ==
            'PUT')
    res = app.delete('/')
    assert (res.request.environ['REQUEST_METHOD'] ==
            'DELETE')
    class FakeDict(object):
        def items(self):
            return [('a', '10'), ('a', '20')]
    res = app.post('/params', params=FakeDict())

    # test multiple cookies in one request
    app.cookies['one'] = 'first';
    app.cookies['two'] = 'second';
    app.cookies['three'] = '';
    res = app.get('/')
    hc = res.request.environ['HTTP_COOKIE'].split('; ');
    assert ('one=first' in hc)
    assert ('two=second' in hc)
    assert ('three=' in hc)
Beispiel #7
0
class InstanceHandlerTest(unittest.TestCase):
    """Unit tests for class InstanceHandler from Instances API."""
    def setUp(self):
        self.app = TestApp(instances_api.app.wsgifunc())
        self.headers = getDefaultHTTPHeaders(config)

    @patch.object(repository, "listMetricIDsForInstance", autospec=True)
    @patch("YOMP.app.webservices.models_api.ModelHandler.deleteModel",
           new=Mock(spec_set=models_api.ModelHandler.deleteModel))
    def testDeleteInstanceHandler(self, listMetricIDsMock, engineFactoryMock):
        """
    Test for Delete "/_instances/<instanceId>"
    response is validated for appropriate headers, body and status
    """
        listMetricIDsMock.return_value = [
            "2490fb7a9df5470fa3678530c4cb0a43",
            "b491ab2310ef4a799b14c08fa3e09f1c"
        ]
        response = self.app.delete("",
                                   headers=self.headers,
                                   params=json.dumps(["i-cd660efb"]))

        assertions.assertDeleteSuccessResponse(self, response)
        self.assertTrue(listMetricIDsMock.called)
        listMetricIDsMock.assert_called_once_with(
            (engineFactoryMock.return_value.connect.return_value.__enter__.
             return_value), "i-cd660efb")
 def _deleteInstance(self):
   """
   Delete test EC2 instance created by :py:meth:`_createEC2Instance`
   """
   app = TestApp(instances_api.app.wsgifunc())
   response = app.delete("/", params=json.dumps([self.instanceId]),
                         headers=self.headers)
   assertions.assertSuccess(self, response)
   result = app_utils.jsonDecode(response.body)
   self.assertIsInstance(result, dict)
   self.assertEqual(result, {"result": "success"})
class TestDELETE():
    def setUp(self):
        middleware = []
        self.client = TestApp(app.wsgifunc(*middleware))

    def test_delete_a_key_value(self):
        lazy_url = ''.join([lazy_controller, 'l777'])
        canonical_url = ''.join([canonical_controller, 'l777'])
        self.client.post(canonical_url, "should have a deleted flag")
        
        self.client.delete(lazy_url, status=202)
        self.client.get(canonical_url, status=404)
        
    def test_cannot_delete_a_non_existing_key_value(self):
        url_xyz = ''.join([lazy_controller, 'lxyz'])
        self.client.delete(url_xyz, status=404)
                
    def test_delete_existing_and_immediately_insert_a_key_value(self):
        lazy_url = ''.join([lazy_controller, 'l737'])
        canonical_url = ''.join([canonical_controller, 'l737'])        
        self.client.post(canonical_url, "will be deleted and over written on canonical. Can be visible in others.")
        
        self.client.delete(lazy_url, status=202)
        self.client.post(lazy_url, "deleted existing. and written a new value")
        r2 = self.client.get(canonical_url)
        r2.mustcontain("deleted existing. and written a new value")
Beispiel #10
0
 def test_delete(self):
     middleware = []
     testApp = TestApp(app.wsgifunc(*middleware))
     key = 'test3'
     message = 'jhfsdf'
     obj_data = {'key': key, 'message': message}
     r1 = testApp.post('/storage/' + key, params=json.dumps(obj_data))
     r = testApp.get('/storage/' + key)
     self.assertEqual(r1.status, 200)
     self.assertEqual(r.status, 200)
     self.assertEqual(json.loads(r.body.decode('utf-8'))['message'], message)
     r3 = testApp.delete('/storage/' + key)
     r4 = testApp.get('/storage/'+ key, status="*")
     self.assertEqual(r4.status, 404)
class TestDELETE():
    def setUp(self):
        middleware = []
        self.client = TestApp(app.wsgifunc(*middleware))

    def test_delete_a_key_value(self):
        url_995 = ''.join([controller, 'c995'])        
        self.client.post(url_995, "should have a deleted flag")
        self.client.delete(url_995, status=202)
        self.client.get(url_995, status=404)
        
    def test_cannot_delete_a_non_existing_key_value(self):
        url_xyz = ''.join([controller, 'cxyz'])
        self.client.delete(url_xyz, status=404)
                
    def test_delete_and_immediately_insert_a_key_value(self):
        url_885 = ''.join([controller, 'c885'])
        self.client.post(url_885, "will be deleted and over written")
        self.client.delete(url_885, status=202)
        
        self.client.post(url_885, "deleted existing. and written a new value")
        r2 = self.client.get(url_885)
        r2.mustcontain("deleted existing. and written a new value")
Beispiel #12
0
class TestModelHandler(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    cls.model_list = json.load(open(os.path.join(grok.app.GROK_HOME,
      "tests/py/data/app/webservices/models_list.json")))


  def setUp(self):
    self.headers = getDefaultHTTPHeaders(grok.app.config)
    self.app = TestApp(models_api.app.wsgifunc())
    metric = Mock(uid="cebe9fab-f416-4845-8dab-02d292244112",
                  datasource="cloudwatch",
                  description="The number of database connections in use by "
                              "Amazon RDS database",
                  server="grokdb2",
                  location="us-east-1",
                  parameters=app_utils.jsonEncode(
                    {"region":"us-east-1", "DBInstanceIdentifier":"grokdb2"}),
                  status=1,
                  message=None,
                  collector_error=None,
                  last_timestamp="2013-08-15 21:25:00",
                  poll_interval=60,
                  tag_name=None,
                  model_params=None,
                  last_rowid=20277)

    metric.name = "AWS/RDS/DatabaseConnections"
    self.metric = metric



  @patch.object(repository, 'getAllModels', autospec=True)
  def testModelHandlerListModelsEmptyResponse(self, getAllModelsMock,
                                              _engineMock, *args):
    getAllModelsMock.return_value = []
    response = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, response)
    result = jsonDecode(response.body)
    self.assertEqual(result, [])


  @patch.object(repository, 'getAllModels', autospec=True)
  def testModelHandlerListModelsWithSlashEmptyResponse(self, getAllModelsMock,
                                              _engineMock, *args):
    getAllModelsMock.return_value = []
    response = self.app.get("/", headers=self.headers)
    assertions.assertSuccess(self, response)
    result = jsonDecode(response.body)
    self.assertEqual(result, [])


  @patch("grok.app.webservices.models_api.repository", autospec=True)
  @patch("grok.app.webservices.models_api.getMetricDisplayFields")
  def testModelHandlerListModelsWithSlashValidResponse(
      self, getMetricDisplayFieldsMock, repositoryMock, _engineMock, *args):

    cols = []
    for key in METRIC_DISPLAY_FIELDS:
      m = Mock()
      m.configure_mock(name=key)
      cols.append(m)

    getMetricDisplayFieldsMock.return_value=cols

    metric = Mock(**dict((col, getattr(self.metric, col))
                         for col in METRIC_DISPLAY_FIELDS))
    metric.keys.return_value = [col for col in METRIC_DISPLAY_FIELDS]
    metric.name = self.metric.name

    repositoryMock.getAllModels = Mock(return_value=[metric])

    response = self.app.get('/', headers=self.headers)
    assertions.assertSuccess(self, response)


    self.assertEqual(json.loads(response.body), self.model_list)


  @patch("grok.app.webservices.models_api.getMetricDisplayFields")
  @patch.object(models_api.ModelHandler, "createModel",
    spec_set=models_api.ModelHandler.createModel)
  def testModelHandlerPOSTModel(self, createModel, getMetricDisplayFieldsMock,
                                _engineMock):
    cols = []
    for key in METRIC_DISPLAY_FIELDS:
      m = Mock()
      m.configure_mock(name=key)
      cols.append(m)

    getMetricDisplayFieldsMock.return_value=cols

    metric = Mock(**dict((col, getattr(self.metric, col))
                         for col in METRIC_DISPLAY_FIELDS))
    metric.keys.return_value = [col for col in METRIC_DISPLAY_FIELDS]
    metric.name = self.metric.name

    createModel.return_value = metric

    params = {"type": "metric",
              "region": "us-east-1",
              "namespace": "AWS/EC2",
              "datasource": "cloudwatch",
              "metric": "CPUUtilization",
              "dimensions": {
                "InstanceId": "i-0c149c66"
              }}
    response = self.app.post("/", json.dumps(params), headers=self.headers)
    assertions.assertResponseStatusCode(self, response, 201)
    assertions.assertResponseHeaders(self, response, "json")
    self.assertTrue(createModel.called)


  @patch("grok.app.webservices.models_api.getMetricDisplayFields")
  @patch.object(models_api.ModelHandler, "createModel",
     spec_set=models_api.ModelHandler.createModel)
  def testModelHandlerPUTModelCreate(self, createModel,
                                     getMetricDisplayFieldsMock, _engineMock):
    cols = []
    for key in METRIC_DISPLAY_FIELDS:
      m = Mock()
      m.configure_mock(name=key)
      cols.append(m)

    getMetricDisplayFieldsMock.return_value=cols

    metric = Mock(**dict((col, getattr(self.metric, col))
                         for col in METRIC_DISPLAY_FIELDS))
    metric.keys.return_value = [col for col in METRIC_DISPLAY_FIELDS]
    metric.name = self.metric.name

    createModel.return_value = metric

    params = {"type": "metric",
              "region": "us-east-1",
              "namespace": "AWS/EC2",
              "datasource": "cloudwatch",
              "metric": "CPUUtilization",
              "dimensions": {
                "InstanceId": "i-0c149c66"
              }}
    response = self.app.put("/", json.dumps(params), headers=self.headers)
    assertions.assertResponseStatusCode(self, response, 201)
    assertions. assertResponseHeaders(self, response, "json")
    self.assertTrue(createModel.called)



  @patch("grok.app.quota.repository")
  @patch("grok.app.webservices.models_api.getMetricDisplayFields")
  @patch("grok.app.webservices.models_api.createDatasourceAdapter",
         autospec=True)
  @patch("grok.app.webservices.models_api.repository", autospec=True)
  def testModelHandlerPUTMonitorMetric(self,
                                       repositoryMock,
                                       createDatasourceAdapterMock,
                                       getMetricDisplayFieldsMock,
                                       quotaRepositoryMock,
                                       engineMock):

    cols = []
    for key in METRIC_DISPLAY_FIELDS:
      m = Mock()
      m.configure_mock(name=key)
      cols.append(m)

    getMetricDisplayFieldsMock.return_value=cols

    metric = Mock(**dict((col, getattr(self.metric, col))
                         for col in METRIC_DISPLAY_FIELDS))
    metric.keys.return_value = [col for col in METRIC_DISPLAY_FIELDS]
    metric.name = self.metric.name

    quotaRepositoryMock.getInstanceCount.return_value = 0
    repositoryMock.getMetric.return_value = metric

    params = {
        "region": "us-east-1",
        "namespace": "AWS/EC2",
        "datasource": "cloudwatch",
        "metric": "CPUUtilization",
        "dimensions": {
            "InstanceId": "i-0c149c66"
        }
    }

    response = self.app.put("/", json.dumps(params), headers=self.headers)
    assertions.assertResponseStatusCode(self, response, 201)
    assertions.assertResponseHeaders(self, response, "json")
    repositoryMock.getMetric.assert_called_once_with(
      engineMock.return_value.connect.return_value.__enter__.return_value,
      createDatasourceAdapterMock.return_value.monitorMetric.return_value)


  @patch("grok.app.quota.repository")
  @patch("grok.app.webservices.models_api.getMetricDisplayFields")
  @patch("grok.app.webservices.models_api.createDatasourceAdapter",
         autospec=True)
  @patch("grok.app.webservices.models_api.repository", autospec=True)
  def testModelHandlerPUTImportModel(self,
                                     repositoryMock,
                                     createDatasourceAdapterMock,
                                     getMetricDisplayFieldsMock,
                                     quotaRepositoryMock,
                                     engineMock):
    cols = []
    for key in METRIC_DISPLAY_FIELDS:
      m = Mock()
      m.configure_mock(name=key)
      cols.append(m)

    getMetricDisplayFieldsMock.return_value=cols

    metric = Mock(**dict((col, getattr(self.metric, col))
                         for col in METRIC_DISPLAY_FIELDS))
    metric.keys.return_value = [col for col in METRIC_DISPLAY_FIELDS]
    metric.name = self.metric.name

    quotaRepositoryMock.getInstanceCount.return_value = 0
    repositoryMock.getMetric.return_value = metric

    params = {
        "type": "metric",
        "region": "us-east-1",
        "namespace": "AWS/EC2",
        "datasource": "cloudwatch",
        "metric": "CPUUtilization",
        "dimensions": {
            "InstanceId": "i-0c149c66"
        }
    }
    response = self.app.put("/", json.dumps(params), headers=self.headers)
    assertions.assertResponseStatusCode(self, response, 201)
    assertions.assertResponseHeaders(self, response, "json")
    repositoryMock.getMetric.assert_called_once_with(
      engineMock.return_value.connect.return_value.__enter__.return_value,
      createDatasourceAdapterMock.return_value.importModel.return_value)


  @patch.object(models_api.ModelHandler, "deleteModel",
    spec_set=models_api.ModelHandler.deleteModel)
  def testModelHandlerDELETEModel(self, deleteModel, _engineMock):
    response = self.app.delete("/12232-jn939", headers=self.headers)
    self.assertTrue(deleteModel.called)
    assertions.assertResponseStatusCode(self, response, 200)
    assertions. assertResponseHeaders(self, response, "json")


  @patch.object(web, "data", return_value=None, autospec=True)
  def testCreateModelEmpty(self, data, _engineMock):
    response = self.app.post("/", {}, headers=self.headers, status="*")
    assertions.assertBadRequest(self, response)
    self.assertTrue(data.called)


  @patch.object(repository, "getMetric", autospec=True)
  def testDeleteModelInvalid(self, getMetricMock, _engineMock):
    getMetricMock.side_effect = ObjectNotFoundError("Test")
    response = self.app.delete("/12232-jn939", headers=self.headers,
      status="*")
    assertions.assertNotFound(self, response)
    self.assertEqual("ObjectNotFoundError Metric not found:"
                     " Metric ID: 12232-jn939", response.body)


  @patch.object(repository, "deleteModel", autospec=True)
  @patch.object(repository, "getMetric", autospec=True)
  @patch.object(model_swapper_utils, "deleteHTMModel",
    spec_set=model_swapper_utils.deleteHTMModel)
  @patch("grok.app.webservices.models_api.createDatasourceAdapter",
         auto_spec=True)
  def testDeleteModelValid(self, _createDatasourceAdapterMock,
                           _deleteHTMModel, _getMetricMock, _deleteModelMock,
                           _engineMock):
    response = self.app.delete("/12232-jn939", headers=self.headers)
    result = jsonDecode(response.body)
    self.assertEqual(result, {"result": "success"})


  @patch("grok.app.quota.repository")
  @patch("grok.app.webservices.models_api.repository")
  @patch("web.ctx")
  @patch("grok.app.webservices.models_api.createDatasourceAdapter",
         autospec=True)
  def testCreateModelForMonitorMetric(self,
                                      createDatasourceAdapterMock,
                                      ctxMock,
                                      repositoryMock,
                                      quotaRepositoryMock,
                                      _engineMock): # pylint: disable=W0613
    nativeMetric = {
        "region": "us-west-2",
        "namespace": "AWS/EC2",
        "datasource": "cloudwatch",
        "metric": "CPUUtilization",
        "dimensions": {
          "InstanceId": "i-ab15a19d"
        }
      }

    metricSpec = {
        "region": nativeMetric["region"],
        "namespace": nativeMetric["namespace"],
        "metric": nativeMetric["metric"],
        "dimensions": nativeMetric["dimensions"]
      }

    metricAdapter = AWSResourceAdapterBase.createMetricAdapter(metricSpec)
    (createDatasourceAdapterMock
     .return_value
     .getInstanceNameForModelSpec
     .return_value) = metricAdapter.getCanonicalResourceName()

    quotaRepositoryMock.getInstanceCount.return_value = 0

    result = models_api.ModelHandler.createModel(nativeMetric)

    self.assertIs(result, repositoryMock.getMetric.return_value)

    repositoryMock.getMetric.assert_called_once_with(
      ctxMock.connFactory.return_value.__enter__.return_value,
      createDatasourceAdapterMock.return_value.monitorMetric.return_value)


  @patch("grok.app.quota.repository")
  @patch("grok.app.webservices.models_api.repository")
  @patch("web.ctx")
  @patch("grok.app.webservices.models_api.createDatasourceAdapter",
         autospec=True)
  def testCreateModelForImportModel(self,
                                    createDatasourceAdapterMock,
                                    ctxMock,
                                    repositoryMock,
                                    quotaRepositoryMock,
                                    _engineMock):
    nativeMetric = {
        "type": "metric",
        "region": "us-west-2",
        "namespace": "AWS/EC2",
        "datasource": "cloudwatch",
        "metric": "CPUUtilization",
        "dimensions": {
          "InstanceId": "i-ab15a19d"
        }
      }

    metricSpec = {
        "region": nativeMetric["region"],
        "namespace": nativeMetric["namespace"],
        "metric": nativeMetric["metric"],
        "dimensions": nativeMetric["dimensions"]
      }

    metricAdapter = AWSResourceAdapterBase.createMetricAdapter(metricSpec)
    (createDatasourceAdapterMock
     .return_value
     .getInstanceNameForModelSpec
     .return_value) = metricAdapter.getCanonicalResourceName()

    quotaRepositoryMock.getInstanceCount.return_value = 0

    result = models_api.ModelHandler.createModel(nativeMetric)

    self.assertIs(result, repositoryMock.getMetric.return_value)

    repositoryMock.getMetric.assert_called_once_with(
      ctxMock.connFactory.return_value.__enter__.return_value,
      createDatasourceAdapterMock.return_value.importModel.return_value)

  @patch("grok.app.quota.repository")
  @patch("grok.app.webservices.models_api.repository")
  @patch("web.ctx")
  @patch("grok.app.webservices.models_api.createDatasourceAdapter",
         autospec=True)
  def testImportModelAutostack(self, adapterMock, ctxMock, repositoryMock,
                               quotaRepositoryMock, _engineMock):
    nativeMetric = {
      "type": "autostack",
      "name": "test1",
      "region": "us-west-2",
      "datasource": "cloudwatch",
      "filters": {
        "tag:Name": [
          "*d*"
        ]
      },
      "metric": {
        "metric": "DiskWriteBytes",
        "namespace": "AWS/EC2"
      }
    }

    quotaRepositoryMock.getInstanceCount.return_value = 0

    adapter = createDatasourceAdapter("autostack")
    importModelMock = create_autospec(adapter.importModel)
    adapterMock.return_value.importModel = importModelMock

    result = models_api.ModelHandler.createModel(nativeMetric)
    self.assertIs(result, repositoryMock.getMetric.return_value)
    repositoryMock.getMetric.assert_called_once_with(
      ctxMock.connFactory.return_value.__enter__.return_value,
      adapterMock.return_value.importModel.return_value)


  @patch("web.webapi.ctx")
  @patch("grok.app.webservices.web.ctx")
  def testCreateModelRaisesBadRequestForEmptyRequest(self, webMock,
                                                     loggerWebMock,
                                                     _engineMock):
    webMock.badrequest = web.badrequest
    loggerWebMock.env = {'HTTP_HOST':'localhost',
                         'SCRIPT_NAME':'',
                         'PATH_INFO':'/_models/test',
                         'HTTP_USER_AGENT':'test'}
    with self.assertRaises(web.badrequest) as e:
      models_api.ModelHandler.createModel()
    self.assertIsInstance(e.exception, InvalidRequestResponse)
    self.assertIn("Metric data is missing", e.exception.data)


  @patch("grok.app.quota.repository")
  @patch("grok.app.webservices.models_api.repository")
  @patch("web.ctx")
  @patch("grok.app.webservices.models_api.createDatasourceAdapter",
         autospec=True)
  def testCreateModels(self, # pylint: disable=W0613
                       createDatasourceAdapterMock,
                       ctxMock,
                       repositoryMock,
                       quotaRepositoryMock,
                       _engineMock):
    nativeMetric = {
        "region": "us-west-2",
        "namespace": "AWS/EC2",
        "datasource": "cloudwatch",
        "metric": "CPUUtilization",
        "dimensions": {
          "InstanceId": "i-ab15a19d"
        }
      }

    metricSpec = {
        "region": nativeMetric["region"],
        "namespace": nativeMetric["namespace"],
        "metric": nativeMetric["metric"],
        "dimensions": nativeMetric["dimensions"]
      }

    metricAdapter = AWSResourceAdapterBase.createMetricAdapter(metricSpec)
    (createDatasourceAdapterMock
     .return_value
     .getInstanceNameForModelSpec
     .return_value) = metricAdapter.getCanonicalResourceName()

    quotaRepositoryMock.getInstanceCount.return_value = 0

    result = models_api.ModelHandler.createModels([nativeMetric])
    self.assertIsInstance(result, list)
    self.assertIs(result[0], repositoryMock.getMetric.return_value)
    repositoryMock.getMetric.assert_called_once_with(
      ctxMock.connFactory.return_value.__enter__.return_value,
      createDatasourceAdapterMock.return_value.monitorMetric.return_value)


  @patch("web.webapi.ctx")
  @patch("grok.app.webservices.web.ctx")
  def testCreateModelsRaisesBadRequestForEmptyRequest(self, webMock,
                                                      loggerWebMock,
                                                      _engineMock):
    webMock.data.return_value = None
    webMock.badrequest = web.badrequest
    loggerWebMock.env = {'HTTP_HOST':'localhost',
                         'SCRIPT_NAME':'',
                         'PATH_INFO':'/_models/test',
                         'HTTP_USER_AGENT':'test'}
    with self.assertRaises(web.badrequest) as e:
      models_api.ModelHandler.createModels()
    self.assertEqual(e.exception.data, "Metric data is missing")
Beispiel #13
0
class TaurusModelsAPITestCase(unittest.TestCase):
  def setUp(self):
    apikey = taurus.engine.config.get("security", "apikey")
    self.headers = {
      "Authorization": "Basic %s" % base64.b64encode(apikey + ":")
    }

    self.app = TestApp(models_api.app.wsgifunc())


  @patch("taurus.engine.webservices.models_api.createDatasourceAdapter")
  def testCreateModels(self, datasourceMock, _engineMock):
    """ Taurus Models API properly passes incoming model parameters to
    datasource adapter.  This mirrors the path taken by
    `taurus.engine.metric_collectors.metric_utils.createAllModels()` and tests
    the expected API.
    """

    datasourceMock.return_value = Mock(spec_set=DatasourceAdapterIface)

    # Snippet from taurus.metric_collectors models.json file
    metricsConfiguration = {
      "3M": {
        "metrics": {
          "TWITTER.TWEET.HANDLE.MMM.VOLUME": {
            "metricType": "TwitterVolume",
            "metricTypeName": "Twitter Volume",
            "modelParams": {
              "minResolution": 0.6
            },
            "provider": "twitter",
            "screenNames": [
              "3M"
            ]
          },
          "XIGNITE.MMM.CLOSINGPRICE": {
            "metricType": "StockPrice",
            "metricTypeName": "Stock Price",
            "modelParams": {
              "minResolution": 0.2
            },
            "provider": "xignite",
            "sampleKey": "Close"
          },
          "XIGNITE.MMM.VOLUME": {
            "metricType": "StockVolume",
            "metricTypeName": "Stock Volume",
            "modelParams": {
              "minResolution": 0.2
            },
            "provider": "xignite",
            "sampleKey": "Volume"
          }
        },
        "stockExchange": "NYSE",
        "symbol": "MMM"
      }
    }

    for resName, resVal in metricsConfiguration.iteritems():
      for metricName, metricVal in resVal["metrics"].iteritems():
        params = {
          "datasource": "custom",
          "metricSpec": {
            "metric": metricName,
            "resource": resName,
            "userInfo": {
              "metricType": metricVal["metricType"],
              "metricTypeName": metricVal["metricTypeName"],
              "symbol": resVal["symbol"]
            }
          },
          "modelParams": metricVal["modelParams"]
        }

        self.app.put("/", json.dumps(params), headers=self.headers)

        self.assertTrue(datasourceMock.called)
        self.assertTrue(datasourceMock.return_value.monitorMetric.called)
        datasourceMock.return_value.monitorMetric.assert_called_once_with({
          "datasource": "custom",
          "metricSpec": {
            "metric": metricName,
            "resource": resName,
            "userInfo": {
              "metricType": metricVal["metricType"],
              "metricTypeName": metricVal["metricTypeName"],
              "symbol": resVal["symbol"]}
          },
          "modelParams": {
            "minResolution": metricVal["modelParams"]["minResolution"]
          }
        })

        datasourceMock.reset_mock()


  @patch("taurus.engine.webservices.models_api.createDatasourceAdapter")
  @patch("taurus.engine.webservices.models_api.repository", autospec=True)
  def testDelete(self, repositoryMock, datasourceMock, _engineMock):
    """ Test that a model is deleted at /_models/<model id>
    """
    datasourceMock.return_value = Mock(spec_set=DatasourceAdapterIface)

    self.app.delete("/foo", headers=self.headers)

    self.assertTrue(repositoryMock.getMetric.called)
    repositoryMock.getMetric.assert_called_once_with(ANY, "foo")
    self.assertTrue(datasourceMock.called)
    self.assertTrue(datasourceMock.return_value.unmonitorMetric.called)
    datasourceMock.return_value.unmonitorMetric.assert_called_once_with("foo")


  @patch("taurus.engine.webservices.models_api.repository", autospec=True)
  def testGetModel(self, repositoryMock, _engineMock):
    """ Test that a model is available at /_models/<model id>
    """
    self.app.get("/foo", headers=self.headers)

    self.assertTrue(repositoryMock.getMetric.called)
    repositoryMock.getMetric.assert_called_once_with(ANY, "foo", ANY)


  @patch("taurus.engine.webservices.models_api.repository", autospec=True)
  def testGetAllModels(self, repositoryMock, _engineMock):
    """ Test that all models available at /_models/
    """
    self.app.get("/", headers=self.headers)

    self.assertTrue(repositoryMock.getAllModels.called)
class AnnotationsHandlerTest(unittest.TestCase):
    def setUp(self):
        self.headers = getDefaultHTTPHeaders(htm.it.app.config)
        self.app = TestApp(annotations_api.app.wsgifunc())
        self.annotation = {
            "uid": "f4aa70b361f04036b0b39530900f38fa",
            "timestamp": "2014-01-25 05:00:00",
            "created": "2014-01-25 07:14:06",
            "device": "device1",
            "user": "******",
            "server": "htm-itdb2",
            "message": "My annotation",
            "data": None
        }
        # Prepare request as annotation without "uid" or "created" fields
        self.request = self.annotation.copy()
        del self.request["uid"]
        del self.request["created"]

    @patch("htm.it.app.repository.getAnnotationById")
    def testGETAnnotationById(self, getAnnotationById, _):
        """
      Test Get Annotation

      Request::

        GET /_annotations/{uid}

    Response::

      HTTP 200 Ok
      [
        {
           "uid": "2a123bb1dd4d46e7a806d62efc29cbb9",
           "device", "1231AC32FE",
           "created":"2013-08-27 16:46:51",
           "timestamp":"2013-08-27 16:45:00",
           "user":"******",
           "server":" AWS/EC2/i-53f52b67",
           "message":" The CPU Utilization was high ...",
           "data": { Optional JSON Object }
         }
      ]
    """
        getAnnotationById.return_value = self.annotation

        response = self.app.get("/%s" % self.annotation["uid"],
                                headers=self.headers)
        self.assertEqual(response.status, 200)
        actual = json.loads(response.body)
        expected = json.loads(app_utils.jsonEncode(self.annotation))

        self.assertDictEqual(expected, actual[0])

    @patch("htm.it.app.repository.getAnnotationById")
    def testGETAnnotationByIdNotFound(self, getAnnotationById, _):
        """
      Test Get Annotation for unknown uid

      Request::

        GET /_annotations/{uid}

    Response::

      HTTP 404 Not Found

    """
        getAnnotationById.side_effect = app_exceptions.ObjectNotFoundError
        with self.assertRaises(AppError) as e:
            self.app.get("/dummy", headers=self.headers)

        self.assertIn("Bad response: 404 Not Found", str(e.exception))

    @patch("htm.it.app.repository.getAnnotations")
    def testGetAnnotations(self, getAnnotations, _):
        """
      Test Get Annotation

      Request::

        GET /_annotations?device={device}&user={user}&server={server}
                          &from={from}&to={to}

    Response::

      HTTP 200 Ok
      [
        {
           "uid": "2a123bb1dd4d46e7a806d62efc29cbb9",
           "device", "1231AC32FE",
           "created":"2013-08-27 16:46:51",
           "timestamp":"2013-08-27 16:45:00",
           "user":"******",
           "server":" AWS/EC2/i-53f52b67",
           "message":" The CPU Utilization was high ...",
           "data": { Optional JSON Object }
         },
        ...
      ]
    """
        getAnnotations.return_value = [self.annotation]

        response = self.app.get("?%s=%s" % ("server", "dummy"),
                                headers=self.headers)
        self.assertEqual(response.status, 200)
        actual = json.loads(response.body)
        expected = json.loads(app_utils.jsonEncode(self.annotation))

        self.assertDictEqual(expected, actual[0])

    @patch("htm.it.app.repository.deleteAnnotationById")
    def testDeleteAnnotationNotFound(self, deleteAnnotationById, _):
        """
    Test Delete unknown Annotation

    Request::

      DELETE /_annotations/{uid}

    Response::

      HTTP 404 Not Found
    """
        deleteAnnotationById.side_effect = app_exceptions.ObjectNotFoundError
        with self.assertRaises(AppError) as e:
            self.app.delete("/dummy", headers=self.headers)

        self.assertIn("Bad response: 404 Not Found", str(e.exception))

    @patch("htm.it.app.repository.deleteAnnotationById")
    def testDeleteAnnotation(self, deleteAnnotationById, _):
        """
    Test Delete Annotation

    Request::

      DELETE /_annotations/{uid}

    Response::

      HTTP 204 No Content
    """
        response = self.app.delete("/%s" % self.annotation["uid"],
                                   headers=self.headers)
        self.assertEqual(response.status, 204)
        self.assertFalse(response.body)
        self.assertTrue(deleteAnnotationById.called)

    @patch("htm.it.app.repository.addAnnotation")
    def testAddAnnotation(self, addAnnotation, _):
        """
    Test Create new Annotation

    Request::

      POST /_annotations

      {
         "device", "1231AC32FE",
         "timestamp":"2013-08-27 16:45:00",
         "user":"******",
         "server":" AWS/EC2/i-53f52b67",
         "message":" The CPU Utilization was high ...",
         "data": { Optional JSON Object }
      }

    Response::

      HTTP Status 201 Created

      {
         "uid": "2a123bb1dd4d46e7a806d62efc29cbb9",
         "device", "1231AC32FE",
         "created":"2013-08-27 16:46:51",
         "timestamp":"2013-08-27 16:45:00",
         "user":"******",
         "server":" AWS/EC2/i-53f52b67",
         "message":" The CPU Utilization was high ...",
         "data": { Optional JSON Object }
      }
    """
        addAnnotation.return_value = self.annotation

        response = self.app.post("",
                                 app_utils.jsonEncode(self.request),
                                 headers=self.headers)
        self.assertEqual(response.status, 201)
        actual = json.loads(response.body)
        # The result should contain new "uid" and "created" fields
        self.assertIn("uid", actual)
        self.assertIn("created", actual)
        # All the other fields should match request
        self.assertDictContainsSubset(self.request, actual)

    def testAddAnnotationIncomplete(self, _):
        """
    Test Failed to Create incomplete Annotation

    Response::

      HTTP Status 400 Missing "field" in request
    """
        # Annotation without timestamp
        badRequest = self.request.copy()
        del badRequest["timestamp"]
        with self.assertRaises(AppError) as e:
            self.app.post("",
                          app_utils.jsonEncode(badRequest),
                          headers=self.headers)

        error = e.exception
        self.assertRegexpMatches(error.message,
                                 "Missing 'timestamp' in request")

        # Annotation without device
        badRequest = self.request.copy()
        del badRequest["device"]
        with self.assertRaises(AppError) as e:
            self.app.post("",
                          app_utils.jsonEncode(badRequest),
                          headers=self.headers)

        error = e.exception
        self.assertRegexpMatches(error.message, "Missing 'device' in request")

        # Annotation without server
        badRequest = self.request.copy()
        del badRequest["server"]
        with self.assertRaises(AppError) as e:
            self.app.post("",
                          app_utils.jsonEncode(badRequest),
                          headers=self.headers)

        error = e.exception
        self.assertRegexpMatches(error.message, "Missing 'server' in request")

        # Annotation without user
        badRequest = self.request.copy()
        del badRequest["user"]
        with self.assertRaises(AppError) as e:
            self.app.post("",
                          app_utils.jsonEncode(badRequest),
                          headers=self.headers)

        error = e.exception
        self.assertRegexpMatches(error.message, "Missing 'user' in request")

        # Annotation without data and message
        badRequest = self.request.copy()
        del badRequest["message"]
        del badRequest["data"]
        with self.assertRaises(AppError) as e:
            self.app.post("",
                          app_utils.jsonEncode(badRequest),
                          headers=self.headers)

        error = e.exception
        self.assertRegexpMatches(
            error.message,
            "Annotation must contain either 'message' or 'data'")

    def testAddAnnotationInvalidJSON(self, _):
        """
    Test failed to create annotation with invalid JSON argument

    Response::

      HTTP Status 400 Invalid JSON in request
    """
        badRequest = "{Not a JSON Request}"
        with self.assertRaises(AppError) as e:
            self.app.post("", badRequest, headers=self.headers)

        error = e.exception
        self.assertRegexpMatches(error.message, "Invalid JSON in request")
Beispiel #15
0
class TestModelExportHandler(unittest.TestCase):
    """
  Integration test for Model Export Handler API
  """
    def setUp(self):
        self.app = TestApp(models_api.app.wsgifunc())
        self.headers = getDefaultHTTPHeaders(htm.it.app.config)
        data = open(
            os.path.join(
                htm.it.app.HTM_IT_HOME,
                "tests/py/data/app/webservices/models_api_integration_test.json"
            )).read()
        self.modelsTestData = json.loads(data)

    @ManagedTempRepository("TestModelExportHandler")
    def testCompleteModelExportApiLifecycle(self):
        """
      Happy path testing for the route "/_models/export"
    """
        data = self.modelsTestData["create_data"]
        createResponse = self.app.put("/",
                                      utils.jsonEncode(data),
                                      headers=self.headers)
        assertions.assertSuccess(self, createResponse, code=201)

        # NOTE: export uses a new format
        expectedExportSpec = {
            "datasource": data["datasource"],
            "metricSpec": {
                "region": data["region"],
                "namespace": data["namespace"],
                "metric": data["metric"],
                "dimensions": data["dimensions"]
            }
        }

        # Test export all data
        response = self.app.get("/export", headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)
        responseData = utils.jsonDecode(createResponse.body)
        uid = responseData[0]['uid']

        # Test for exporting single metric.
        response = self.app.get("/%s/export" % uid, headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)

        # Delete the model that was created earlier
        response = self.app.delete("/%s" % uid, headers=self.headers)
        assertions.assertDeleteSuccessResponse(self, response)

        # Import the model from exported data
        response = self.app.put("/",
                                utils.jsonEncode(exportedData),
                                headers=self.headers)
        assertions.assertSuccess(self, response, code=201)
        responseData = utils.jsonDecode(response.body)
        uid = responseData[0]['uid']

        # Export the newly-imported model
        response = self.app.get("/%s/export" % uid, headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)

        # Delete the model that was created earlier
        response = self.app.delete("/%s" % uid, headers=self.headers)
        assertions.assertDeleteSuccessResponse(self, response)

        # Import the model using legacy format
        legacyImportSpec = dict(type="metric", **data)
        response = self.app.put("/",
                                utils.jsonEncode(legacyImportSpec),
                                headers=self.headers)
        assertions.assertSuccess(self, response, code=201)
        responseData = utils.jsonDecode(response.body)
        uid = responseData[0]['uid']

        # Export the newly-imported model
        response = self.app.get("/%s/export" % uid, headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)

    @ManagedTempRepository("TestModelExportHandler")
    def testExportNonExistentModelUID(self):
        """
      Test for export of non existent model"
    """
        response = self.app.get("/f00bar/export",
                                status="*",
                                headers=self.headers)
        assertions.assertObjectNotFoundError(self, response)
Beispiel #16
0
def test_unicode_path():
    app = TestApp(SimpleApplication())
    app.get(u"/?")
    app.post(u"/?")
    app.put(u"/?")
    app.delete(u"/?")
class TestNotificationsHandler(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    cls.model_list = json.load(open(os.path.join(grok.app.GROK_HOME,
      "tests/py/data/app/webservices/models_list.json")))


  def setUp(self):
    self.headers = getDefaultHTTPHeaders(grok.app.config)
    self.app = TestApp(notifications_api.app.wsgifunc())

    # Set up dummy notification assets
    self.deviceId = str(uuid.uuid4())
    self.notificationId = str(uuid.uuid4())

    metricParams = {u"region":u"us-east-1", u"DBInstanceIdentifier":u"grokdb2"}
    self.metric = {"uid": u"cebe9fab-f416-4845-8dab-02d292244112",
                   "datasource": u"cloudwatch",
                   "name": u"AWS/RDS/DatabaseConnections",
                   "description": u"The number of database connections in use "
                                  u"by Amazon RDS database",
                   "server": u"grokdb2",
                   "location": u"us-east-1",
                   "parameters": app_utils.jsonEncode(metricParams),
                   "status": 1,
                   "message":None,
                   "collector_error": None,
                   "last_timestamp": u"2013-08-15 21:25:00",
                   "poll_interval": 60,
                   "tag_name": None,
                   "model_params": None,
                   "last_rowid": 20277}

    self.notification = {"uid": self.deviceId,
                         "metric": self.metric["uid"],
                         "device": self.deviceId,
                         "windowsize": 3600,
                         "timestamp": datetime.datetime.utcnow(),
                         "acknowledged": 0,
                         "seen": 0,
                         "ses_message_id": None,
                         "rowid": 666}

    self.settings = {"uid": self.deviceId,
                     "windowsize": 3600,
                     "sensitivity": 0.99999,
                     "email_addr": "*****@*****.**",
                     "last_timestamp": datetime.datetime.utcnow()}


  @patch.object(repository, "getNotification", autospec=True)
  def testGETNotification(self, getNotificationMock, _engineMock):
    """ Test GETing single notification from Notification API
    """
    getNotificationMock.return_value = self.notification


    response = self.app.get("/%s/%s" % (self.notification["device"],
                                        self.notification["uid"]),
                            headers=self.headers)

    self.assertEqual(response.status, 200)
    result = json.loads(response.body)

    notificationDict = copy.deepcopy(self.notification)
    del notificationDict["ses_message_id"]
    del notificationDict["rowid"]

    jsonNotification = json.loads(app_utils.jsonEncode(notificationDict))

    self.assertDictEqual(result, jsonNotification)


  @patch.object(repository, "batchAcknowledgeNotifications", autospec=True)
  def testDELETENotification(self, batchAcknowledgeMock, engineMock):
    """ Test notification DELETE endpoint
    """
    response = self.app.delete("/%s/%s" %
                               (self.notification["device"],
                                self.notification["uid"]),
                               headers=self.headers)

    self.assertEqual(response.status, 204)
    self.assertFalse(response.body)
    self.assertTrue(batchAcknowledgeMock.called)
    batchAcknowledgeMock.assert_called_with(
      engineMock.return_value.connect.return_value.__enter__.return_value,
      [self.notification["uid"]])


  @patch.object(repository, "batchAcknowledgeNotifications", autospec=True)
  def testDELETENotificationBatch(self, batchAcknowledgeMock, engineMock):
    """ Test notification DELETE endpoint (batch)
    """
    uids = [self.notification["uid"],
            self.notification["uid"]]
    response = self.app.delete("/%s" % self.notification["device"],
                               app_utils.jsonEncode(uids),
                               headers=self.headers)

    self.assertEqual(response.status, 204)
    self.assertFalse(response.body)
    self.assertTrue(batchAcknowledgeMock.called)
    batchAcknowledgeMock.assert_called_with(
      engineMock.return_value.connect.return_value.__enter__.return_value, uids)


  @patch.object(repository, "batchAcknowledgeNotifications", autospec=True)
  def testAcknowledgeNotificationBatch(self, batchAcknowledgeMock, engineMock):
    """ Test notification POST endpoint (batch)
    """
    uids = [self.notification["uid"],
            self.notification["uid"]]
    response = self.app.post("/%s/acknowledge" %
                             self.notification["device"],
                             app_utils.jsonEncode(uids),
                             headers=self.headers)

    self.assertEqual(response.status, 204)
    self.assertFalse(response.body)
    self.assertTrue(batchAcknowledgeMock.called)
    batchAcknowledgeMock.assert_called_with(
      engineMock.return_value.connect.return_value.__enter__.return_value, uids)


  @patch.object(repository, "batchSeeNotifications", autospec=True)
  def testSeeNotificationBatch(self, batchaSeeMock, engineMock):
    """ Test notification POST endpoint (batch)
    """
    uids = [self.notification["uid"],
            self.notification["uid"]]
    response = self.app.post("/%s/see" % self.notification["device"],
                             app_utils.jsonEncode(uids),
                             headers=self.headers)

    self.assertEqual(response.status, 204)
    self.assertFalse(response.body)
    self.assertTrue(batchaSeeMock.called)
    batchaSeeMock.assert_called_with(
      engineMock.return_value.connect.return_value.__enter__.return_value, uids)


  @patch("grok.app.webservices.notifications_api.repository", autospec=True)
  def testGETNotificationHistory(self, repositoryMock, _engineMock):
    """ Test GET notification history
    """
    repositoryMock.getUnseenNotificationList = Mock(return_value = [self.notification])

    response = self.app.get("/%s/history" %
                            self.notification["device"],
                            headers=self.headers)

    self.assertEqual(response.status, 200)
    result = json.loads(response.body)

    notificationDict = copy.deepcopy(self.notification)
    del notificationDict["ses_message_id"]
    del notificationDict["rowid"]
    jsonNotifications = json.loads(app_utils.jsonEncode([notificationDict]))
    self.assertSequenceEqual(result, jsonNotifications)


  @patch("grok.app.webservices.notifications_api.repository", autospec=True)
  def testGETNotificationSettings(self, repositoryMock, _engineMock):
    """ Test GET notification settings
    """
    repositoryMock.getDeviceNotificationSettings = Mock(return_value = self.settings)

    response = self.app.get("/%s/settings" %
                            self.notification["device"],
                            headers=self.headers)

    self.assertEqual(response.status, 200)
    result = json.loads(response.body)

    settingsDict = copy.deepcopy(self.settings)
    jsonNotificationSettings = json.loads(app_utils.jsonEncode(settingsDict))

    self.assertDictEqual(result, jsonNotificationSettings)


  @patch("grok.app.webservices.notifications_api.repository", autospec=True)
  def testPUTNotificationSettingsUpdate(self, repositoryMock, engineMock):
    """ Test PUT notification settings (update)
    """
    repositoryMock.getDeviceNotificationSettings = Mock(return_value=self.settings)

    update = {
      "windowsize": 3601,
      "sensitivity": 0.999999,
      "email_addr": "*****@*****.**"}

    response = self.app.put("/%s/settings" %
                            self.notification["device"],
                            app_utils.jsonEncode(update),
                            headers=self.headers)

    self.assertEqual(response.status, 204)
    self.assertFalse(response.body)
    repositoryMock.updateDeviceNotificationSettings.assert_called_with(
      engineMock.return_value.connect.return_value.__enter__.return_value,
      self.notification["device"],
      {"windowsize": 3601,
       "sensitivity": 0.999999,
       "email_addr": "*****@*****.**"})


  @patch("grok.app.webservices.notifications_api.repository", autospec=True)
  def testPUTNotificationSettingsCreate(self, repositoryMock, engineMock):
    """ Test PUT notification settings (create)
    """

    repositoryMock.getDeviceNotificationSettings.side_effect = (
      ObjectNotFoundError("No settings yet"))

    update = {
      "windowsize": 3601,
      "sensitivity": 0.999999,
      "email_addr": "*****@*****.**"}



    response = self.app.put("/%s/settings" %
                            self.notification["device"],
                            app_utils.jsonEncode(update),
                            headers=self.headers)

    self.assertEqual(response.status, 201)
    self.assertFalse(response.body)
    self.assertTrue(repositoryMock.getDeviceNotificationSettings.called)
    repositoryMock.addDeviceNotificationSettings.assert_called_with(
      engineMock.return_value.connect.return_value.__enter__.return_value,
      self.notification["device"],
      update["windowsize"],
      update["sensitivity"],
      update["email_addr"])
Beispiel #18
0
class TestModelHandler(unittest.TestCase):
  """
  Integration test for Model Handler API
  """



  def setUp(self):
    self.app = TestApp(models_api.app.wsgifunc())
    self.headers = getDefaultHTTPHeaders(htm.it.app.config)
    data = open(os.path.join(htm.it.app.HTM_IT_HOME,
     "tests/py/data/app/webservices/models_api_integration_test.json")).read()
    self.modelsTestData = json.loads(data)


  def _checkCreateModelResult(self, postResult, metricSpec):
    dimensions = metricSpec["dimensions"]
    expectedRegion = metricSpec["region"]
    expectedNamespace = metricSpec["namespace"]
    expectedInstanceId = dimensions["InstanceId"]

    self.assertItemsEqual(postResult.keys(),
                          self.modelsTestData["create_response"].keys())

    self.assertEqual(postResult["server"],
      "%s/%s/%s" % (expectedRegion, expectedNamespace, expectedInstanceId))

    self.assertEqual(postResult["location"], expectedRegion)

    self.assertEqual(postResult["name"],
                     expectedNamespace + "/" + metricSpec["metric"])


  def testCompleteModelsApiLifecycle(self):
    """
      Happy path testing for the route "/_models"
    """
    # get all models in the system when there are no models
    # expected response is []
    response = self.app.get("/", headers=self.headers)
    assertions.assertSuccess(self, response)
    allModelsResult = utils.jsonDecode(response.body)
    self.assertEqual(len(allModelsResult), 0)
    self.assertIsInstance(allModelsResult, list)

    data = self.modelsTestData["create_data"]

    # create a model using PUT;
    # Any HTTP POST call is forwarded to HTTP PUT in the Model API.
    #   def POST(self):
    #      return self.PUT()
    # The tests are just calling PUT.
    # TODO: wouldn't POST be a better method to test in that case, since it
    #  would exercise both POST and PUT?
    response = self.app.put("/", utils.jsonEncode(data), headers=self.headers)
    assertions.assertSuccess(self, response, code=201)
    postResult = utils.jsonDecode(response.body)
    self.assertEqual(len(postResult), 1)
    self._checkCreateModelResult(postResult[0], data)

    # get model that was previously created
    uid = postResult[0]["uid"]
    response = self.app.get("/%s" % uid, headers=self.headers)
    assertions.assertSuccess(self, response)
    getModelResult = utils.jsonDecode(response.body)
    self.assertItemsEqual(getModelResult[0].keys(),
      self.modelsTestData["get_response"].keys())

    # get all models in the system
    response = self.app.get("/", headers=self.headers)
    assertions.assertSuccess(self, response)
    allModelsResult = utils.jsonDecode(response.body)
    self.assertItemsEqual(allModelsResult[0].keys(),
      self.modelsTestData["get_response"].keys())
    self.assertItemsEqual(allModelsResult[0].keys(),
      self.modelsTestData["get_response"].keys())
    self.assertEqual(len(allModelsResult), 1)

    # Repeat the request to monitor same metric and verify that it returns the
    # same model uid instead of creating a new one
    response = self.app.post("/", utils.jsonEncode(data), headers=self.headers)

    assertions.assertSuccess(self, response, code=201)
    postResult = utils.jsonDecode(response.body)
    self.assertEqual(postResult[0]["uid"], uid)
    self.assertEqual(len(postResult), 1)
    self._checkCreateModelResult(postResult[0], data)

    # Compare http and https responses for all models
    for x in range(3):
      https_response = requests.get("https://localhost/_models",
                                    headers=self.headers,
                                    verify=False)
      http_response = requests.get("http://localhost/_models",
                                   headers=self.headers)

      self.assertEqual(http_response.status_code, 200)
      self.assertEqual(https_response.status_code, 200)

      httpsData = json.loads(https_response.text)

      try:
        self.assertIsInstance(httpsData, list)
        self.assertTrue(httpsData)
        for item in httpsData:
          self.assertIn("status", item)
          self.assertIn("last_rowid", item)
          self.assertIn("display_name", item)
          self.assertIn("uid", item)
          self.assertIn("datasource", item)

        httpData = json.loads(http_response.text)
        self.assertIsInstance(httpData, list)
        self.assertTrue(httpData)
        for item in httpData:
          self.assertIn("status", item)
          self.assertIn("last_rowid", item)
          self.assertIn("display_name", item)
          self.assertIn("uid", item)
          self.assertIn("datasource", item)

        self.assertEqual(http_response.text, https_response.text)

        break
      except AssertionError:
        time.sleep(10)

    else:
      self.fail("Unable to synchronize http and https responses.")

    # Compare http and https response for all models data
    https_response = requests.get("https://localhost/_models/data",
                                  headers=self.headers,
                                  verify=False)
    http_response = requests.get("http://localhost/_models/data",
                                 headers=self.headers)

    self.assertEqual(http_response.status_code, 200)
    self.assertEqual(https_response.status_code, 200)

    httpData = json.loads(http_response.text)
    self.assertIsInstance(httpData, dict)
    self.assertItemsEqual(httpData.keys(), ["metrics", "names"])
    self.assertItemsEqual(httpData["names"], ["timestamp",
                                              "value",
                                              "anomaly_score",
                                              "rowid"])

    httpsData = json.loads(https_response.text)
    self.assertIsInstance(httpsData, dict)
    self.assertItemsEqual(httpsData.keys(), ["metrics", "names"])
    self.assertItemsEqual(httpsData["names"], ["timestamp",
                                               "value",
                                               "anomaly_score",
                                               "rowid"])

    # delete the model that was created earlier
    response = self.app.delete("/%s" % uid, headers=self.headers)
    assertions.assertDeleteSuccessResponse(self, response)


  @ManagedTempRepository("TestModelHandler")
  def testMonitorMetricViaModelSpec(self):
    """
      Happy path testing for the route "/_models" with new modelSpec format
    """
    modelSpec = {
      "datasource": "cloudwatch",

      "metricSpec": {
        "region": "us-west-2",
        "namespace": "AWS/EC2",
        "metric": "CPUUtilization",
        "dimensions": {
          "InstanceId": "i-12d67826"
        }
      },

      "modelParams": {
        "min": 0,  # optional
        "max": 100  # optional
      }
    }

    # create a model
    response = self.app.post("/", utils.jsonEncode(modelSpec),
                             headers=self.headers)
    assertions.assertSuccess(self, response, code=201)
    postResult = utils.jsonDecode(response.body)
    self.assertEqual(len(postResult), 1)
    self._checkCreateModelResult(postResult[0], modelSpec["metricSpec"])

    # get model that was previously created
    uid = postResult[0]["uid"]
    response = self.app.get("/%s" % uid, headers=self.headers)
    assertions.assertSuccess(self, response)
    getModelResult = utils.jsonDecode(response.body)
    self.assertItemsEqual(getModelResult[0].keys(),
      self.modelsTestData["get_response"].keys())

    # get all models in the system
    response = self.app.get("/", headers=self.headers)
    assertions.assertSuccess(self, response)
    allModelsResult = utils.jsonDecode(response.body)
    self.assertItemsEqual(allModelsResult[0].keys(),
      self.modelsTestData["get_response"].keys())
    self.assertItemsEqual(allModelsResult[0].keys(),
      self.modelsTestData["get_response"].keys())
    self.assertEqual(len(allModelsResult), 1)

    # Repeat the request to monitor same metric and verify that it returns the
    # same model uid instead of creating a new one
    response = self.app.post("/", utils.jsonEncode(modelSpec),
                             headers=self.headers)
    assertions.assertSuccess(self, response, code=201)
    postResult = utils.jsonDecode(response.body)
    self.assertEqual(postResult[0]["uid"], uid)
    self.assertEqual(len(postResult), 1)
    self._checkCreateModelResult(postResult[0], modelSpec["metricSpec"])

    # Unmonitor the metric
    response = self.app.delete("/%s" % uid, headers=self.headers)
    assertions.assertDeleteSuccessResponse(self, response)



  @ManagedTempRepository("TestModelHandler")
  def testGetNonExistentModelUID(self):
    """
      Test for the get call with non-existent Model uid.
    """
    response = self.app.get("/f00bar", status="*", headers=self.headers)
    assertions.assertObjectNotFoundError(self, response)


  @ManagedTempRepository("TestModelHandler")
  def testDeleteNonExistentModelUID(self):
    """
      Test for the delete call with non-existent Model uid.
    """
    response = self.app.delete("/f00bar", status="*", headers=self.headers)
    assertions.assertObjectNotFoundError(self, response)


  @ManagedTempRepository("TestModelHandler")
  def testInvalidJsonModelsApi(self):
    """
      Test for the invalid json.
    """
    data = self.modelsTestData["create_data"]
    response = self.app.put("/", data, status="*", headers=self.headers)
    self.assertIn("No JSON object could be decoded", response.body)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithEmptyRegionArg(self):
    """
      Test for the missing empty datasource field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_empty_region"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithInvalidRegionKey(self):
    """
      Test for the invalid region field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_invalid_region_key"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithEmptyDatasourceArg(self):
    """
      Test for the missing empty datasource field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_empty_ds_data"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithInvalidDatasourceArg(self):
    """
      Test for the invalid metric field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_invalid_ds_data"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithEmptyMetricArg(self):
    """
      Test for the missing empty metric field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_empty_metric_data"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithInvalidMetricArg(self):
    """
      Test for the invalid metric field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_invalid_metric_data"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertBadRequest(self, response, "json")

    response = self.app.get("/", headers=self.headers)
    self.assertFalse(json.loads(response.body),
                     "Model actually created with invalid metric")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithEmptyDimensionsArg(self):
    """
      Test for the missing empty dimension field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_empty_dimension_data"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithInvalidDimensionsArg(self):
    """
      Test for the invalid dimension field in json.
    """
    data = utils.jsonEncode(
      self.modelsTestData["create_invalid_dimension_data"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertBadRequest(self, response, "json")

    response = self.app.get("/", headers=self.headers)
    self.assertFalse(json.loads(response.body),
                     "Model actually created with invalid dimension")


  @ManagedTempRepository("TestModelHandler")
  def testCreateModelWithEmptyInstanceIdArg(self):
    """
      Test for the empty dimension field in json.
    """
    data = utils.jsonEncode(self.modelsTestData["create_empty_instanceid_data"])
    response = self.app.put("/", data, status="*", headers=self.headers)
    assertions.assertInvalidArgumentsError(self, response, "json")


  @ManagedTempRepository("TestModelHandler")
  def testNoAuthHeaders(self):
    """
    Negative test for authentication guarded route.
    invoke get request without passing authentication headers
    response is validated for appropriate headers and body
    """
    response = self.app.get("/", status="*")
    assertions.assertInvalidAuthenticationResponse(self, response)


  @ManagedTempRepository("TestModelHandler")
  def testInvalidAuthHeaders(self):
    """
    Negative test for authentication guarded route.
    invoke get request with invalid authentication headers
    response is validated for appropriate headers and body
    """
    invalidHeaders = getInvalidHTTPHeaders()
    response = self.app.get("/", status="*", headers=invalidHeaders)
    assertions.assertInvalidAuthenticationResponse(self, response)


  @ManagedTempRepository("TestModelHandler")
  def testPutMethodWithNoData(self):
    """
    Test making a PUT call with no data.
    """
    response = self.app.put("/", status="*", headers=self.headers)
    self.assertIn("Metric data is missing", response.body)
    assertions.assertBadRequest(self, response)
class InstancesHandlerTest(unittest.TestCase):
  """Unit tests for class InstancesHandler from Instances API."""


  def setUp(self):
    self.app = TestApp(instances_api.app.wsgifunc())
    self.headers = getDefaultHTTPHeaders(config)


  def _getInstancesHandlerCommon(self, instancesMock, route, expectedResult):
    """
    This method wraps around common testing path for all GET routes which falls
    to listing all available instances
    instancesMock : Mock for Instances class
    route : route under test for current testcase
    expectedResult : expected response from API call
    """
    response = self.app.get(route, headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)
    self.assertIsInstance(result, list)
    self.assertEqual(result, expectedResult)
    self.assertTrue(instancesMock.getInstances.called)


  @patch.object(repository, "getInstances", autospec=True)
  def testGetInstancesHandlerEmptyResponse(self, getInstancesMock,
                                           engineFactoryMock):
    """
    Test for Get "/_instances"
    response is validated for appropriate headers, body and status
    """
    getInstancesMock.return_value = []

    response = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)

    self.assertIsInstance(result, list)
    self.assertEqual(result, [])
    self.assertTrue(getInstancesMock.called)
    getInstancesMock.assert_called_with(
      engineFactoryMock.return_value.connect.return_value.__enter__
      .return_value)


  @patch.object(repository, "getInstances", autospec=True)
  def testGetInstancesHandlerNonEmptyResponse(self, getInstancesMock,
                                              engineFactoryMock):
    """
    Test for Get "/_instances"
    response is validated for appropriate headers, body and status
    """
    instancesAPIData = json.load(open(os.path.join(GROK_HOME,
      "tests/py/data/app/webservices/instances_api.json")))
    getInstancesMock.return_value = instancesAPIData["getInstances"]

    response = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)

    self.assertIsInstance(result, list)
    self.assertEqual(result, instancesAPIData["getInstances"])
    self.assertTrue(getInstancesMock.called)
    getInstancesMock.assert_called_with(
      engineFactoryMock.return_value.connect.return_value.__enter__
      .return_value)



  @patch.object(repository, "getInstances", autospec=True)
  def testGetInstancesHandlerEmptyResponseWithSlash(self, getInstancesMock,
                                                    engineFactoryMock):
    """
    Test for Get "/_instances/"
    response is validated for appropriate headers, body and status
    """
    getInstancesMock.return_value = []

    response = self.app.get("/", headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)

    self.assertIsInstance(result, list)
    self.assertEqual(result, [])
    self.assertTrue(getInstancesMock.called)
    getInstancesMock.assert_called_with(
      engineFactoryMock.return_value.connect.return_value.__enter__
      .return_value)


  @patch("grok.app.webservices.instances_api.repository.getInstances",
         autospec=True)
  def testGetInstancesHandlerNonEmptyResponseWithSlash(self,
                                                       getInstancesMock,
                                                       engineFactoryMock):
    """
    Test for Get "/_instances/"
    response is validated for appropriate headers, body and status
    """
    instancesAPIData = json.load(open(os.path.join(GROK_HOME,
      "tests/py/data/app/webservices/instances_api.json")))
    getInstancesMock.return_value = instancesAPIData["getInstances"]

    response = self.app.get("/", headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)

    self.assertIsInstance(result, list)
    self.assertEqual(result, instancesAPIData["getInstances"])
    self.assertTrue(getInstancesMock.called)
    getInstancesMock.assert_called_with(
      engineFactoryMock.return_value.connect.return_value.__enter__
      .return_value)


  @patch.object(repository, "listMetricIDsForInstance", autospec=True)
  @patch("grok.app.webservices.models_api.ModelHandler.deleteModel",
    new=Mock(spec_set=models_api.ModelHandler.deleteModel))
  def testDeleteInstancesHandler(self, listMetricIDsMock, engineFactoryMock):
    """
    Test for Delete "/_instances"
    response is validated for appropriate headers, body and status
    """
    listMetricIDsMock.return_value = \
      ["2490fb7a9df5470fa3678530c4cb0a43", "b491ab2310ef4a799b14c08fa3e09f1c"]
    params = ["grok-docs-elb", "i-e16bd2d5"]
    response = self.app.delete("", params=app_utils.jsonEncode(params),
      headers=self.headers)
    assertions.assertDeleteSuccessResponse(self, response)
    self.assertTrue(listMetricIDsMock.called)
    listMetricIDsMock.assert_called_with(
      (engineFactoryMock.return_value.connect.return_value.__enter__
       .return_value),
      params[1])



  @patch.object(repository, "listMetricIDsForInstance", autospec=True)
  @patch("grok.app.webservices.models_api.ModelHandler.deleteModel",
    new=Mock(spec_set=models_api.ModelHandler.deleteModel))
  def testDeleteInstancesHandlerNonJSONData(self, listMetricIDsMock,
                                            _engineFactoryMock):
    """
    Test for Delete "/_instances" with non JSON input
    response is validated for appropriate headers, body and status
    """
    response = self.app.delete("", params="params", headers=self.headers,
     status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertFalse(listMetricIDsMock.called)


  @patch.object(repository, "listMetricIDsForInstance", autospec=True)
  @patch("grok.app.webservices.models_api.ModelHandler.deleteModel",
    new=Mock(spec_set=models_api.ModelHandler.deleteModel))
  def testDeleteInstancesHandlerEmptyData(self, listMetricIDsMock,
                                            _engineFactoryMock):
    """
    Test for Delete "/_instances" with with empty input data
    response is validated for appropriate headers, body and status
    """
    params = []
    response = self.app.delete("", params=app_utils.jsonEncode(params),
      headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertFalse(listMetricIDsMock.called)
class AnnotationHandlerTest(unittest.TestCase):


  def _createEC2Instance(self):
    """
    Created EC2 instance to be used by the tests
    :return: Instance ID
    :rtype: str
    """
    app = TestApp(instances_api.app.wsgifunc())

    response = app.post("/" + self.instanceId, headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)
    self.assertIsInstance(result, dict)
    self.assertEqual(result, {"result": "success"})


  def _deleteInstance(self):
    """
    Delete test EC2 instance created by :py:meth:`_createEC2Instance`
    """
    app = TestApp(instances_api.app.wsgifunc())
    response = app.delete("/", params=json.dumps([self.instanceId]),
                          headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)
    self.assertIsInstance(result, dict)
    self.assertEqual(result, {"result": "success"})


  def _deleteOneMetric(self):
    """
    Delete one metric from test EC2 instance
    """
    app = TestApp(models_api.app.wsgifunc())
    response = app.get("/", headers=self.headers)
    assertions.assertSuccess(self, response)
    result = app_utils.jsonDecode(response.body)
    self.assertIsInstance(result, list)
    app.delete("/" + result[0]['uid'], headers=self.headers)


  def setUp(self):
    self.headers = getDefaultHTTPHeaders(app_config)
    self.invalidHeaders = getInvalidHTTPHeaders()
    self.app = TestApp(annotations_api.app.wsgifunc())
    self.annotation = {
        "uid": "f4aa70b361f04036b0b39530900f38fa",
        "timestamp": "2014-01-25 05:00:00",
        "created": "2014-01-25 07:14:06",
        "device": "device1",
        "user": "******",
        "server": "us-west-2/AWS/EC2/i-f52075fe",
        "message": "My annotation",
        "data": None
    }
    self.instanceId = "%s/AWS/EC2/%s" % (
        VALID_EC2_INSTANCES["region"],
        VALID_EC2_INSTANCES["instanceId"])

    # Prepare request as annotation without "uid" or "created" fields
    self.request = self.annotation.copy()
    self.request["server"] = self.instanceId
    del self.request["uid"]
    del self.request["created"]


  @ManagedTempRepository("Lifecycle")
  def testAnnotationLifecycle(self):
    """
    **Happy Path**

    * Make sure annotation was successfully created and all fields were
      initialized.
    * Make sure user can get annotation by ID and fail (Not Found) if he uses
      the wrong ID
    * Make sure user can get annotations by device and receive an empty array if
      he uses the wrong device
    * Make sure user can get annotations by instance and receive an empty array
      if he uses the wrong instance
    * Make sure user can get annotation by date and receive an empty array if he
      uses dates out of range
    * Make sure user can delete annotations
    """
    # Create Instance before annotation
    self._createEC2Instance()

    # Create Annotation
    response = self.app.post("", app_utils.jsonEncode(self.request),
                                        headers=self.headers)
    self.assertEqual(response.status, 201)

    # Use this newly created annotation as expected annotation from now on
    expectedAnnotation = app_utils.jsonDecode(response.body)

    # The result should contain new "uid" and "created" fields
    self.assertIn("uid", expectedAnnotation)
    self.assertIn("created", expectedAnnotation)
    # All the other fields should match request
    self.assertDictContainsSubset(self.request, expectedAnnotation)

    # Get Annotation By ID
    response = self.app.get("/" + expectedAnnotation["uid"],
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertDictEqual(expectedAnnotation, actual[0])

    # Get Annotation with wrong ID
    with self.assertRaises(AppError) as e:
      response = self.app.get("/dummy", headers=self.headers)
    self.assertIn("Bad response: 404 Not Found", str(e.exception))

    # Get all annotations
    response = self.app.get("/", headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertItemsEqual([expectedAnnotation], actual)

    # Get Annotations by Device
    response = self.app.get("/", {"device": self.request["device"]},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertDictEqual(expectedAnnotation, actual[0])

    # Get Annotations with wrong Device
    response = self.app.get("/", {"device": "dummy"},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertTrue(len(actual) == 0)

    # Get Annotations by server
    response = self.app.get("/", {"server": self.request["server"]},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertDictEqual(expectedAnnotation, actual[0])

    # Get Annotations with wrong server
    response = self.app.get("/", {"server": "dummy"},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertTrue(len(actual) == 0)

    # Get Annotations by date
    response = self.app.get("/", {"from": "2014-01-01 00:00:00"},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertDictEqual(expectedAnnotation, actual[0])

    response = self.app.get("/", {"from": self.request["timestamp"]},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertDictEqual(expectedAnnotation, actual[0])

    response = self.app.get("/", {"to": self.request["timestamp"]},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertDictEqual(expectedAnnotation, actual[0])

    response = self.app.get("/", {"from": "2014-01-01 00:00:00",
                                             "to": "2014-12-31 00:00:00"},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertDictEqual(expectedAnnotation, actual[0])

    # Get Annotations with date out of range
    response = self.app.get("/", {"from": "2014-12-31 00:00:00"},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertTrue(len(actual) == 0)

    response = self.app.get("/", {"to": "2014-01-01 00:00:00"},
                                       headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertTrue(len(actual) == 0)

    # Delete annotation with wrong ID
    with self.assertRaises(AppError) as e:
      self.app.delete("/dummy", headers=self.headers)
    self.assertIn("Bad response: 404 Not Found", str(e.exception))

    # Make sure no annotation was deleted
    response = self.app.get("/", headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertItemsEqual([expectedAnnotation], actual)

    # Delete annotation
    response = self.app.delete("/" + expectedAnnotation["uid"],
                                          headers=self.headers)
    self.assertEqual(response.status, 204)
    self.assertFalse(response.body)

    # Make sure annotation was deleted
    response = self.app.get("/", headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertTrue(len(actual) == 0)


  @ManagedTempRepository("DataIntegrity")
  def testAnnotationDataIntegrity(self):
    """
    **Test Required Fields**

    * Make sure user is not allowed to add annotations without device
    * Make sure user is not allowed to add annotations without timestamp
    * Make sure user is not allowed to add annotations without instance
    * Make sure user is not allowed to add annotations with invalid/unknown
      instance
    * Do not delete annotations when metric is deleted
    * Delete annotations when instance is deleted
    """
    # Create Instance before annotation
    self._createEC2Instance()

    # Create request without "device"
    req = self.request.copy()
    del req["device"]
    with self.assertRaises(AppError):
      self.app.post("", app_utils.jsonEncode(req),
                               headers=self.headers)

    # Create request without "timestamp"
    req = self.request.copy()
    del req["timestamp"]
    with self.assertRaises(AppError):
      self.app.post("", app_utils.jsonEncode(req),
                               headers=self.headers)

    # Create request without "instance"
    req = self.request.copy()
    del req["server"]
    with self.assertRaises(AppError):
      self.app.post("", app_utils.jsonEncode(req),
                               headers=self.headers)

    # Create request with invalid/unknown "instance"
    req = self.request.copy()
    req["server"] = "dummy"
    with self.assertRaises(AppError):
      self.app.post("", app_utils.jsonEncode(req),
                               headers=self.headers)

    # Create request without "message" and "data"
    req = self.request.copy()
    del req["message"]
    del req["data"]
    with self.assertRaises(AppError):
      self.app.post("", app_utils.jsonEncode(req),
                               headers=self.headers)


    # Add annotation
    response = self.app.post("", app_utils.jsonEncode(self.request),
                                        headers=self.headers)
    self.assertEqual(response.status, 201)

    # Use this newly created annotation as expected annotation from now on
    expectedAnnotation = app_utils.jsonDecode(response.body)

    # Do not delete annotations when metric is deleted

    # Delete metric
    self._deleteOneMetric()

    # Make sure no annotation was deleted
    response = self.app.get("/", headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertItemsEqual([expectedAnnotation], actual)

    # Delete annotations when instance is deleted
    self._deleteInstance()

    # Make sure annotation was deleted
    response = self.app.get("/", headers=self.headers)
    actual = app_utils.jsonDecode(response.body)
    self.assertTrue(len(actual) == 0)


  @ManagedTempRepository("Security")
  def testAnnotationSecurity(self):
    """
    **Test Security**

    * Make sure user is unable to add annotation using invalid key
    * Make sure user is unable to delete annotation using invalid key
    * Make sure user is unable to get annotation using invalid key
    """
    # Create Instance before annotation
    self._createEC2Instance()

    # Create single annotation for testing
    response = self.app.post("", app_utils.jsonEncode(self.request),
                                        headers=self.headers)
    expectedAnnotation = app_utils.jsonDecode(response.body)


    # Make sure user is unable to add annotation using invalid key
    with self.assertRaises(AppError):
      self.app.post("", app_utils.jsonEncode(self.request),
                               headers=self.invalidHeaders)

    # Make sure user is unable to get annotation using invalid key
    with self.assertRaises(AppError):
      self.app.get("/", headers=self.invalidHeaders)

    with self.assertRaises(AppError):
      self.app.get("/", {"device": self.request["device"]},
                              headers=self.invalidHeaders)

    with self.assertRaises(AppError):
      self.app.get("/" + expectedAnnotation["uid"],
                              headers=self.invalidHeaders)

    # Make sure user is unable to delete annotation using invalid key
    with self.assertRaises(AppError):
      self.app.delete("/" + expectedAnnotation["uid"],
                                 headers=self.invalidHeaders)
class InstancesApiMultipleInstanceTest(unittest.TestCase):
  """
  Integration tests methods for multiple instaces
  """


  def setUp(self):
    self.app = TestApp(instances_api.app.wsgifunc())
    self.headers = getDefaultHTTPHeaders(grok.app.config)


  @ManagedTempRepository("InstancesApiMultiple")
  def testLifecycleForMultipleInstances(self):
    """
    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    This expects response from application in initial stage when
    no instances are under monitor

    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    post multiple instances

    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    This test check for listed monitored instances from previous step

    Test for delete '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with valid instanceId for listed monitored instances
    from previous step


    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    This invokes get call to assert that all instances which were
    under monitor have been deleted and we get empty response
    """
    # Check instance list at initial phase for empty response
    getIntialResponse = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, getIntialResponse)
    getIntialResult = app_utils.jsonDecode(getIntialResponse.body)
    self.assertItemsEqual(getIntialResult, [])


    # Test for post '/_instances'

    # TODO: Until MER-1172 is resolved
    # test will execute this as temporary. This will add expected instances
    # under monitor. Which will be used for further tests
    # here adding
    params = [VALID_EC2_INSTANCES["rpm-builder"]["instanceId"],
      VALID_EC2_INSTANCES["grok-docs"]["instanceId"]]
    region = "us-west-2"
    namespace = "EC2"
    for instance in params:
      postResponse = self.app.post("/%s/AWS/%s/%s" % (region,
       namespace, instance), headers=self.headers)
      assertions.assertSuccess(self, postResponse)
      postResult = app_utils.jsonDecode(postResponse.body)
      self.assertIsInstance(postResult, dict)
      self.assertEqual(postResult, {"result": "success"})

    # TODO Use Api calls below once MER-1172 is resolved

    #postResponse = self.app.post("/us-west-2/AWS/EC2",
    #  params=app_utils.jsonEncode(params), headers=self.headers, status="*")
    #assertions.assertSuccess(self, response)
    #postResult = app_utils.jsonDecode(postResponse.body)
    #self.assertIsInstance(postResult, dict)
    #self.assertEqual(postResult, {"result": "success"})

    # Test for Get '/_instances'
    getPostCheckResponse = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, getPostCheckResponse)
    getPostCheckResult = app_utils.jsonDecode(getPostCheckResponse.body)
    instanceIds = []
    self.assertIsInstance(getPostCheckResult, list)
    for instance in getPostCheckResult:
      instanceIds.append(instance["server"])
      self.assertEqual(instance["namespace"], "AWS/EC2")
      self.assertEqual(instance["location"], "us-west-2")
    self.assertItemsEqual([instanceId.rpartition("/")[2]
                           for instanceId in instanceIds], params)

    # Delete instances under monitor
    deleteResponse = self.app.delete("",
                                     params=app_utils.jsonEncode(instanceIds),
                                     headers=self.headers)
    assertions.assertDeleteSuccessResponse(self, deleteResponse)

    # check instances to confirm the delete action
    getPostDeleteCheckResponse = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, getPostDeleteCheckResponse)
    getPostDeleteResult = app_utils.jsonDecode(getPostDeleteCheckResponse.body)
    self.assertItemsEqual(getPostDeleteResult, [])


  @ManagedTempRepository("InstancesApiMultiple")
  def testPostMultipleWithEmptyData(self):
    """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with empty data
    """
    params = []
    response = self.app.post("/us-west-2/AWS/EC2",
      params=app_utils.jsonEncode(params), headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("InvalidArgumentsError", response.body)


  @ManagedTempRepository("InstancesApiMultiple")
  def testPostMultipleWithNonJsonData(self):
    """
    Test for '/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with non-json data
    """
    params = []
    response = self.app.post("/us-west-2/AWS/EC2",
      params=params, headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("Invalid request", response.body)


  @ManagedTempRepository("InstancesApiMultiple")
  def testPostMultipleWithInvalidInstanceId(self):
    """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with invalid instanceId

    Expect a 200 OK even when attempting to POST to an invalid instance,
    this saves the overhead of asking AWS if we're dealing with a valid
    instance every POST.

    We expect the CLI user to know what instance ID he/she is looking for.
    """
    params = ["abcd1234"]
    response = self.app.post("/us-west-2/AWS/EC2",
      params=app_utils.jsonEncode(params), headers=self.headers, status="*")
    assertions.assertSuccess(self, response)


  @ManagedTempRepository("InstancesApiMultiple")
  def testPostMultipleWithInstanceToIncorrectNamespace(self):
    """
    Test for post'/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with valid instance id to incorrect namespace

    Expect a 200 OK even when attempting to POST an instance to the wrong
    namespace, this saves the overhead of asking AWS if we're dealing with a
    valid instance in the given namespace with every POST request.

    We expect the CLI user to know what instance ID he/she is looking for.

    """
    params = ["grok-docs-elb"]
    response = self.app.post("/us-west-2/AWS/EC2",
      params=app_utils.jsonEncode(params), headers=self.headers, status="*")
    assertions.assertSuccess(self, response)


  @ManagedTempRepository("InstancesApiMultiple")
  def testPostMultipleWithInstanceToIncorrectRegion(self):
    """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke post with valid instance id to incorrect region
    """
    params = [VALID_EC2_INSTANCES["jenkins-master"]]
    response = self.app.post("/us-east-1/AWS/EC2",
      params=app_utils.jsonEncode(params), headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("InvalidArgumentsError", response.body)


  @ManagedTempRepository("InstancesApiMultiple")
  def testDeleteMultipleWithEmptyData(self):
    """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with empty data
    """
    params = []

    with self.assertRaises(AppError) as err:
      self.app.delete("",
                      params=app_utils.jsonEncode(params),
                      headers=self.headers)

    self.assertIn("Missing instances in DELETE request", str(err.exception))


  @ManagedTempRepository("InstancesApiMultiple")
  def testDeleteMultipleWithInvalidInstanceId(self):
    """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with invalid Instance id
    """
    params = ["abcd1234"]
    response = self.app.delete("", params=app_utils.jsonEncode(params),
      headers=self.headers, status="*")
    assertions.assertNotFound(self, response)
    self.assertIn("Not able to delete", response.body)


  @ManagedTempRepository("InstancesApiMultiple")
  def testDeleteMultipleinstancesWithInvalidData(self):
    """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with invalid Instance id
    """
    params = []
    response = self.app.delete("", params=params, headers=self.headers,
      status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("Invalid request", response.body)
class TestModelExportHandler(unittest.TestCase):
    """
  Integration test for Model Export Handler API
  """

    def setUp(self):
        self.app = TestApp(models_api.app.wsgifunc())
        self.headers = getDefaultHTTPHeaders(grok.app.config)
        data = open(
            os.path.join(grok.app.GROK_HOME, "tests/py/data/app/webservices/models_api_integration_test.json")
        ).read()
        self.modelsTestData = json.loads(data)

    @ManagedTempRepository("TestModelExportHandler")
    def testCompleteModelExportApiLifecycle(self):
        """
      Happy path testing for the route "/_models/export"
    """
        data = self.modelsTestData["create_data"]
        createResponse = self.app.put("/", utils.jsonEncode(data), headers=self.headers)
        assertions.assertSuccess(self, createResponse, code=201)

        # NOTE: export uses a new format
        expectedExportSpec = {
            "datasource": data["datasource"],
            "metricSpec": {
                "region": data["region"],
                "namespace": data["namespace"],
                "metric": data["metric"],
                "dimensions": data["dimensions"],
            },
        }

        # Test export all data
        response = self.app.get("/export", headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)
        responseData = utils.jsonDecode(createResponse.body)
        uid = responseData[0]["uid"]

        # Test for exporting single metric.
        response = self.app.get("/%s/export" % uid, headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)

        # Delete the model that was created earlier
        response = self.app.delete("/%s" % uid, headers=self.headers)
        assertions.assertDeleteSuccessResponse(self, response)

        # Import the model from exported data
        response = self.app.put("/", utils.jsonEncode(exportedData), headers=self.headers)
        assertions.assertSuccess(self, response, code=201)
        responseData = utils.jsonDecode(response.body)
        uid = responseData[0]["uid"]

        # Export the newly-imported model
        response = self.app.get("/%s/export" % uid, headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)

        # Delete the model that was created earlier
        response = self.app.delete("/%s" % uid, headers=self.headers)
        assertions.assertDeleteSuccessResponse(self, response)

        # Import the model using legacy format
        legacyImportSpec = dict(type="metric", **data)
        response = self.app.put("/", utils.jsonEncode(legacyImportSpec), headers=self.headers)
        assertions.assertSuccess(self, response, code=201)
        responseData = utils.jsonDecode(response.body)
        uid = responseData[0]["uid"]

        # Export the newly-imported model
        response = self.app.get("/%s/export" % uid, headers=self.headers)
        assertions.assertSuccess(self, response)
        exportedData = utils.jsonDecode(response.body)
        self.assertIsInstance(exportedData, list)
        self.assertEqual(exportedData[0], expectedExportSpec)

    @ManagedTempRepository("TestModelExportHandler")
    def testExportNonExistentModelUID(self):
        """
      Test for export of non existent model"
    """
        response = self.app.get("/f00bar/export", status="*", headers=self.headers)
        assertions.assertObjectNotFoundError(self, response)
class TestAutostackMetricsHandler(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    with open(
        os.path.join(
          htm.it.app.HTM_IT_HOME,
          "tests/py/data/app/webservices/models_list.json")) as fileObj:
      cls.model_list = json.load(fileObj)

    cls.autostack = Mock(uid="blahblahblah",
                         region="bogus",
                         filters=jsonEncode({"tag:Name":["Bogus"]}))
    cls.autostack.name = "Test"

    cls.jsonAutostack = jsonEncode({"uid":"blahblahblah",
                                    "name":"Test",
                                    "region":"bogus",
                                    "filters":{"tag:Name":["Bogus"]}})
    cls.metric = Mock(uid="cebe9fab-f416-4845-8dab-02d292244112",
                      datasource="autostack",
                      description="The number of database connections in use "
                                  "by Amazon RDS database",
                      server="htm-itdb2",
                      location="us-east-1",
                      parameters=jsonEncode(
                        {"region":"us-east-1",
                         "DBInstanceIdentifier":"htm-itdb2"}),
                      status=1,
                      message=None,
                      collector_error=None,
                      last_timestamp="2013-08-15 21:25:00",
                      poll_interval=60,
                      tag_name=None,
                      model_params=None,
                      last_rowid=20277)
    cls.metric.name = "AWS/RDS/DatabaseConnections"

    cls.jsonMetric = jsonEncode(
      {"uid":cls.metric.uid,
       "datasource":cls.metric.datasource,
       "name":cls.metric.name,
       "description":cls.metric.description,
       "server":cls.metric.server,
       "location":cls.metric.location,
       "parameters":jsonDecode(cls.metric.parameters),
       "status":cls.metric.status,
       "message":cls.metric.message,
       "last_timestamp":cls.metric.last_timestamp,
       "poll_interval":cls.metric.poll_interval,
       "tag_name":cls.metric.tag_name,
       "last_rowid":cls.metric.last_rowid,
       "display_name":cls.metric.server})

  def setUp(self):
    self.headers = getDefaultHTTPHeaders(htm.it.app.config)
    self.app = TestApp(autostacks_api.app.wsgifunc())


  @patch("htm.it.app.webservices.autostacks_api.repository")
  def testGETAutostackMetrics(self, repositoryMock, *_args):
    repositoryMock.getAutostackMetrics.return_value = iter([self.metric])
    response = self.app.get(
      "/" + self.autostack.uid + "/metrics", headers=self.headers)
    self.assertEqual(response.status, 200)
    result = json.loads(response.body)
    self.assertDictEqual(json.loads(self.jsonMetric), result[0])


  @patch("htm.it.app.webservices.autostacks_api.createAutostackDatasourceAdapter")
  @patch("htm.it.app.repository.getMetric", autospec=True)
  @patch("htm.it.app.repository.addMetric", autospec=True)
  def testPOSTAutostackMetricsNoMinMax(
        self,
        addMetricMock,
        getMetricMock,
        adapterMock,
        *_args):

    getMetricMock.return_value = self.metric
    addMetricMock.return_value = self.metric

    response = self.app.post("/" + self.autostack.uid + "/metrics",
                             app_utils.jsonEncode([{"metric": "CPUUtilization",
                                                    "namespace": "AWS/EC2"},
                                                   {"metric": "NetworkIn",
                                                    "namespace": "AWS/EC2"}]),
                             headers=self.headers)
    self.assertEqual(response.status, 201)
    self.assertEqual(adapterMock.return_value.monitorMetric.call_count, 2)

    metricSpec = (
      adapterMock.return_value.monitorMetric
      .call_args_list[0][0][0]["metricSpec"])
    self.assertEqual(metricSpec["slaveMetric"]["metric"], "CPUUtilization")
    self.assertEqual(metricSpec["slaveMetric"]["namespace"], "AWS/EC2")

    metricSpec = (
      adapterMock.return_value.monitorMetric
      .call_args_list[1][0][0]["metricSpec"])
    self.assertEqual(metricSpec["slaveMetric"]["metric"], "NetworkIn")
    self.assertEqual(metricSpec["slaveMetric"]["namespace"], "AWS/EC2")



  @patch("htm.it.app.webservices.autostacks_api.createAutostackDatasourceAdapter")
  @patch("htm.it.app.repository.getMetric", autospec=True)
  @patch("htm.it.app.repository.addMetric", autospec=True)
  def testPOSTAutostackMetricsWithMinMax(
      self,
      addMetricMock,
      getMetricMock,
      adapterMock,
      *_args):

    getMetricMock.return_value = self.metric
    addMetricMock.return_value = self.metric

    response = self.app.post("/" + self.autostack.uid + "/metrics",
                             app_utils.jsonEncode([{"metric": "CPUUtilization",
                                                    "namespace": "AWS/EC2",
                                                    "min": 0.0, "max": 10.0}]),
                             headers=self.headers)
    self.assertEqual(response.status, 201)
    self.assertTrue(adapterMock.return_value.monitorMetric.called)
    self.assertEqual(
      adapterMock.return_value.monitorMetric
      .call_args_list[0][0][0]["modelParams"],
      {'max': 10.0, 'min': 0.0})


  @patch("htm.it.app.webservices.autostacks_api.createAutostackDatasourceAdapter")
  @patch("htm.it.app.webservices.models_api.repository.getAutostack")
  def testPOSTAutostackMetricsHandlesObjectNotFoundError(
      self,
      autostackGetMock,
      adapterMock,
      _repositoryMock):
    autostackGetMock.return_value = self.autostack
    adapterMock.return_value.monitorMetric.side_effect = (
      ValueError("Autostack not found."))

    with self.assertRaises(AppError) as e:
      self.app.post("/" + self.autostack.uid + "/metrics",
                    app_utils.jsonEncode(
                      [{"metric": "Foobar",
                        "namespace": "AWS/EC2"}]),
                    headers=self.headers)

    self.assertIn("400 Bad Request", str(e.exception))
    self.assertTrue(adapterMock.return_value.monitorMetric.called)


  @patch("htmengine.model_swapper.utils.deleteHTMModel")
  @patch("htm.it.app.webservices.autostacks_api.repository")
  def testDELETEAutostackMetrics(self, repositoryMock, deleteHTMModelMock,
                                 *_args):
    repositoryMock.getAutostackFromMetric.return_value = Mock(
      uid=self.autostack.uid)
    response = self.app.delete(
      "/" + self.autostack.uid + "/metrics/" + self.metric.uid,
      headers=self.headers)
    self.assertEqual(response.status, 204)
    self.assertTrue(repositoryMock.deleteMetric.called)
    repositoryMock.deleteMetric.assert_called_with(ANY, self.metric.uid)
    deleteHTMModelMock.assert_called_once_with(self.metric.uid)


  @patch("htmengine.model_swapper.utils.deleteHTMModel",
         auto_spec=True)
  @patch("htm.it.app.webservices.autostacks_api.repository",
         auto_spec=True)
  def testDELETEAutostackMetricsWrongAutostack(self, repositoryMock,
                                               *_args):
    repositoryMock.getAutostackFromMetric.return_value = Mock(
      uid="wrong-autostack-id")
    with self.assertRaises(AppError) as cm:
      self.app.delete(
        "/" + self.autostack.uid + "/metrics/" + self.metric.uid,
        headers=self.headers)
    self.assertIn("Bad response: 400 Bad Request", str(cm.exception))
    self.assertIn(
      "Metric=cebe9fab-f416-4845-8dab-02d292244112 does not belong to "
      "autostack=blahblahblah", str(cm.exception))


  @patch("htm.it.app.webservices.models_api.repository")
  def testDELETEAutostackMetricsFromModelsAPI(self, repositoryMock, *_args):
    repositoryMock.getMetric.return_value = self.metric

    app = TestApp(models_api.app.wsgifunc())

    with self.assertRaises(AppError) as e:
      app.delete("/" + self.metric.uid, headers=self.headers)

    self.assertIn("Bad response: 405 Method Not Allowed", str(e.exception))
class TestNotificationsHandler(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.model_list = json.load(
            open(
                os.path.join(
                    grok.app.GROK_HOME,
                    "tests/py/data/app/webservices/models_list.json")))

    def setUp(self):
        self.headers = getDefaultHTTPHeaders(grok.app.config)
        self.app = TestApp(notifications_api.app.wsgifunc())

        # Set up dummy notification assets
        self.deviceId = str(uuid.uuid4())
        self.notificationId = str(uuid.uuid4())

        metricParams = {
            u"region": u"us-east-1",
            u"DBInstanceIdentifier": u"grokdb2"
        }
        self.metric = {
            "uid": u"cebe9fab-f416-4845-8dab-02d292244112",
            "datasource": u"cloudwatch",
            "name": u"AWS/RDS/DatabaseConnections",
            "description": u"The number of database connections in use "
            u"by Amazon RDS database",
            "server": u"grokdb2",
            "location": u"us-east-1",
            "parameters": app_utils.jsonEncode(metricParams),
            "status": 1,
            "message": None,
            "collector_error": None,
            "last_timestamp": u"2013-08-15 21:25:00",
            "poll_interval": 60,
            "tag_name": None,
            "model_params": None,
            "last_rowid": 20277
        }

        self.notification = {
            "uid": self.deviceId,
            "metric": self.metric["uid"],
            "device": self.deviceId,
            "windowsize": 3600,
            "timestamp": datetime.datetime.utcnow(),
            "acknowledged": 0,
            "seen": 0,
            "ses_message_id": None,
            "rowid": 666
        }

        self.settings = {
            "uid": self.deviceId,
            "windowsize": 3600,
            "sensitivity": 0.99999,
            "email_addr": "*****@*****.**",
            "last_timestamp": datetime.datetime.utcnow()
        }

    @patch.object(repository, "getNotification", autospec=True)
    def testGETNotification(self, getNotificationMock, _engineMock):
        """ Test GETing single notification from Notification API
    """
        getNotificationMock.return_value = self.notification

        response = self.app.get(
            "/%s/%s" % (self.notification["device"], self.notification["uid"]),
            headers=self.headers)

        self.assertEqual(response.status, 200)
        result = json.loads(response.body)

        notificationDict = copy.deepcopy(self.notification)
        del notificationDict["ses_message_id"]
        del notificationDict["rowid"]

        jsonNotification = json.loads(app_utils.jsonEncode(notificationDict))

        self.assertDictEqual(result, jsonNotification)

    @patch.object(repository, "batchAcknowledgeNotifications", autospec=True)
    def testDELETENotification(self, batchAcknowledgeMock, engineMock):
        """ Test notification DELETE endpoint
    """
        response = self.app.delete(
            "/%s/%s" % (self.notification["device"], self.notification["uid"]),
            headers=self.headers)

        self.assertEqual(response.status, 204)
        self.assertFalse(response.body)
        self.assertTrue(batchAcknowledgeMock.called)
        batchAcknowledgeMock.assert_called_with(
            engineMock.return_value.connect.return_value.__enter__.
            return_value, [self.notification["uid"]])

    @patch.object(repository, "batchAcknowledgeNotifications", autospec=True)
    def testDELETENotificationBatch(self, batchAcknowledgeMock, engineMock):
        """ Test notification DELETE endpoint (batch)
    """
        uids = [self.notification["uid"], self.notification["uid"]]
        response = self.app.delete("/%s" % self.notification["device"],
                                   app_utils.jsonEncode(uids),
                                   headers=self.headers)

        self.assertEqual(response.status, 204)
        self.assertFalse(response.body)
        self.assertTrue(batchAcknowledgeMock.called)
        batchAcknowledgeMock.assert_called_with(
            engineMock.return_value.connect.return_value.__enter__.
            return_value, uids)

    @patch.object(repository, "batchAcknowledgeNotifications", autospec=True)
    def testAcknowledgeNotificationBatch(self, batchAcknowledgeMock,
                                         engineMock):
        """ Test notification POST endpoint (batch)
    """
        uids = [self.notification["uid"], self.notification["uid"]]
        response = self.app.post("/%s/acknowledge" %
                                 self.notification["device"],
                                 app_utils.jsonEncode(uids),
                                 headers=self.headers)

        self.assertEqual(response.status, 204)
        self.assertFalse(response.body)
        self.assertTrue(batchAcknowledgeMock.called)
        batchAcknowledgeMock.assert_called_with(
            engineMock.return_value.connect.return_value.__enter__.
            return_value, uids)

    @patch.object(repository, "batchSeeNotifications", autospec=True)
    def testSeeNotificationBatch(self, batchaSeeMock, engineMock):
        """ Test notification POST endpoint (batch)
    """
        uids = [self.notification["uid"], self.notification["uid"]]
        response = self.app.post("/%s/see" % self.notification["device"],
                                 app_utils.jsonEncode(uids),
                                 headers=self.headers)

        self.assertEqual(response.status, 204)
        self.assertFalse(response.body)
        self.assertTrue(batchaSeeMock.called)
        batchaSeeMock.assert_called_with(
            engineMock.return_value.connect.return_value.__enter__.
            return_value, uids)

    @patch("grok.app.webservices.notifications_api.repository", autospec=True)
    def testGETNotificationHistory(self, repositoryMock, _engineMock):
        """ Test GET notification history
    """
        repositoryMock.getUnseenNotificationList = Mock(
            return_value=[self.notification])

        response = self.app.get("/%s/history" % self.notification["device"],
                                headers=self.headers)

        self.assertEqual(response.status, 200)
        result = json.loads(response.body)

        notificationDict = copy.deepcopy(self.notification)
        del notificationDict["ses_message_id"]
        del notificationDict["rowid"]
        jsonNotifications = json.loads(app_utils.jsonEncode([notificationDict
                                                             ]))
        self.assertSequenceEqual(result, jsonNotifications)

    @patch("grok.app.webservices.notifications_api.repository", autospec=True)
    def testGETNotificationSettings(self, repositoryMock, _engineMock):
        """ Test GET notification settings
    """
        repositoryMock.getDeviceNotificationSettings = Mock(
            return_value=self.settings)

        response = self.app.get("/%s/settings" % self.notification["device"],
                                headers=self.headers)

        self.assertEqual(response.status, 200)
        result = json.loads(response.body)

        settingsDict = copy.deepcopy(self.settings)
        jsonNotificationSettings = json.loads(
            app_utils.jsonEncode(settingsDict))

        self.assertDictEqual(result, jsonNotificationSettings)

    @patch("grok.app.webservices.notifications_api.repository", autospec=True)
    def testPUTNotificationSettingsUpdate(self, repositoryMock, engineMock):
        """ Test PUT notification settings (update)
    """
        repositoryMock.getDeviceNotificationSettings = Mock(
            return_value=self.settings)

        update = {
            "windowsize": 3601,
            "sensitivity": 0.999999,
            "email_addr": "*****@*****.**"
        }

        response = self.app.put("/%s/settings" % self.notification["device"],
                                app_utils.jsonEncode(update),
                                headers=self.headers)

        self.assertEqual(response.status, 204)
        self.assertFalse(response.body)
        repositoryMock.updateDeviceNotificationSettings.assert_called_with(
            engineMock.return_value.connect.return_value.__enter__.
            return_value, self.notification["device"], {
                "windowsize": 3601,
                "sensitivity": 0.999999,
                "email_addr": "*****@*****.**"
            })

    @patch("grok.app.webservices.notifications_api.repository", autospec=True)
    def testPUTNotificationSettingsCreate(self, repositoryMock, engineMock):
        """ Test PUT notification settings (create)
    """

        repositoryMock.getDeviceNotificationSettings.side_effect = (
            ObjectNotFoundError("No settings yet"))

        update = {
            "windowsize": 3601,
            "sensitivity": 0.999999,
            "email_addr": "*****@*****.**"
        }

        response = self.app.put("/%s/settings" % self.notification["device"],
                                app_utils.jsonEncode(update),
                                headers=self.headers)

        self.assertEqual(response.status, 201)
        self.assertFalse(response.body)
        self.assertTrue(repositoryMock.getDeviceNotificationSettings.called)
        repositoryMock.addDeviceNotificationSettings.assert_called_with(
            engineMock.return_value.connect.return_value.__enter__.
            return_value, self.notification["device"], update["windowsize"],
            update["sensitivity"], update["email_addr"])
class TestAutostackMetricsHandler(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        with open(
                os.path.join(htm.it.app.HTM_IT_HOME,
                             "tests/py/data/app/webservices/models_list.json")
        ) as fileObj:
            cls.model_list = json.load(fileObj)

        cls.autostack = Mock(uid="blahblahblah",
                             region="bogus",
                             filters=jsonEncode({"tag:Name": ["Bogus"]}))
        cls.autostack.name = "Test"

        cls.jsonAutostack = jsonEncode({
            "uid": "blahblahblah",
            "name": "Test",
            "region": "bogus",
            "filters": {
                "tag:Name": ["Bogus"]
            }
        })
        cls.metric = Mock(
            uid="cebe9fab-f416-4845-8dab-02d292244112",
            datasource="autostack",
            description="The number of database connections in use "
            "by Amazon RDS database",
            server="htm-itdb2",
            location="us-east-1",
            parameters=jsonEncode({
                "region": "us-east-1",
                "DBInstanceIdentifier": "htm-itdb2"
            }),
            status=1,
            message=None,
            collector_error=None,
            last_timestamp="2013-08-15 21:25:00",
            poll_interval=60,
            tag_name=None,
            model_params=None,
            last_rowid=20277)
        cls.metric.name = "AWS/RDS/DatabaseConnections"

        cls.jsonMetric = jsonEncode({
            "uid":
            cls.metric.uid,
            "datasource":
            cls.metric.datasource,
            "name":
            cls.metric.name,
            "description":
            cls.metric.description,
            "server":
            cls.metric.server,
            "location":
            cls.metric.location,
            "parameters":
            jsonDecode(cls.metric.parameters),
            "status":
            cls.metric.status,
            "message":
            cls.metric.message,
            "last_timestamp":
            cls.metric.last_timestamp,
            "poll_interval":
            cls.metric.poll_interval,
            "tag_name":
            cls.metric.tag_name,
            "last_rowid":
            cls.metric.last_rowid,
            "display_name":
            cls.metric.server
        })

    def setUp(self):
        self.headers = getDefaultHTTPHeaders(htm.it.app.config)
        self.app = TestApp(autostacks_api.app.wsgifunc())

    @patch("htm.it.app.webservices.autostacks_api.repository")
    def testGETAutostackMetrics(self, repositoryMock, *_args):
        repositoryMock.getAutostackMetrics.return_value = iter([self.metric])
        response = self.app.get("/" + self.autostack.uid + "/metrics",
                                headers=self.headers)
        self.assertEqual(response.status, 200)
        result = json.loads(response.body)
        self.assertDictEqual(json.loads(self.jsonMetric), result[0])

    @patch(
        "htm.it.app.webservices.autostacks_api.createAutostackDatasourceAdapter"
    )
    @patch("htm.it.app.repository.getMetric", autospec=True)
    @patch("htm.it.app.repository.addMetric", autospec=True)
    def testPOSTAutostackMetricsNoMinMax(self, addMetricMock, getMetricMock,
                                         adapterMock, *_args):

        getMetricMock.return_value = self.metric
        addMetricMock.return_value = self.metric

        response = self.app.post("/" + self.autostack.uid + "/metrics",
                                 app_utils.jsonEncode([{
                                     "metric": "CPUUtilization",
                                     "namespace": "AWS/EC2"
                                 }, {
                                     "metric": "NetworkIn",
                                     "namespace": "AWS/EC2"
                                 }]),
                                 headers=self.headers)
        self.assertEqual(response.status, 201)
        self.assertEqual(adapterMock.return_value.monitorMetric.call_count, 2)

        metricSpec = (adapterMock.return_value.monitorMetric.call_args_list[0]
                      [0][0]["metricSpec"])
        self.assertEqual(metricSpec["slaveMetric"]["metric"], "CPUUtilization")
        self.assertEqual(metricSpec["slaveMetric"]["namespace"], "AWS/EC2")

        metricSpec = (adapterMock.return_value.monitorMetric.call_args_list[1]
                      [0][0]["metricSpec"])
        self.assertEqual(metricSpec["slaveMetric"]["metric"], "NetworkIn")
        self.assertEqual(metricSpec["slaveMetric"]["namespace"], "AWS/EC2")

    @patch(
        "htm.it.app.webservices.autostacks_api.createAutostackDatasourceAdapter"
    )
    @patch("htm.it.app.repository.getMetric", autospec=True)
    @patch("htm.it.app.repository.addMetric", autospec=True)
    def testPOSTAutostackMetricsWithMinMax(self, addMetricMock, getMetricMock,
                                           adapterMock, *_args):

        getMetricMock.return_value = self.metric
        addMetricMock.return_value = self.metric

        response = self.app.post("/" + self.autostack.uid + "/metrics",
                                 app_utils.jsonEncode([{
                                     "metric": "CPUUtilization",
                                     "namespace": "AWS/EC2",
                                     "min": 0.0,
                                     "max": 10.0
                                 }]),
                                 headers=self.headers)
        self.assertEqual(response.status, 201)
        self.assertTrue(adapterMock.return_value.monitorMetric.called)
        self.assertEqual(
            adapterMock.return_value.monitorMetric.call_args_list[0][0][0]
            ["modelParams"], {
                'max': 10.0,
                'min': 0.0
            })

    @patch(
        "htm.it.app.webservices.autostacks_api.createAutostackDatasourceAdapter"
    )
    @patch("htm.it.app.webservices.models_api.repository.getAutostack")
    def testPOSTAutostackMetricsHandlesObjectNotFoundError(
            self, autostackGetMock, adapterMock, _repositoryMock):
        autostackGetMock.return_value = self.autostack
        adapterMock.return_value.monitorMetric.side_effect = (
            ValueError("Autostack not found."))

        with self.assertRaises(AppError) as e:
            self.app.post("/" + self.autostack.uid + "/metrics",
                          app_utils.jsonEncode([{
                              "metric": "Foobar",
                              "namespace": "AWS/EC2"
                          }]),
                          headers=self.headers)

        self.assertIn("400 Bad Request", str(e.exception))
        self.assertTrue(adapterMock.return_value.monitorMetric.called)

    @patch("htmengine.model_swapper.utils.deleteHTMModel")
    @patch("htm.it.app.webservices.autostacks_api.repository")
    def testDELETEAutostackMetrics(self, repositoryMock, deleteHTMModelMock,
                                   *_args):
        repositoryMock.getAutostackFromMetric.return_value = Mock(
            uid=self.autostack.uid)
        response = self.app.delete("/" + self.autostack.uid + "/metrics/" +
                                   self.metric.uid,
                                   headers=self.headers)
        self.assertEqual(response.status, 204)
        self.assertTrue(repositoryMock.deleteMetric.called)
        repositoryMock.deleteMetric.assert_called_with(ANY, self.metric.uid)
        deleteHTMModelMock.assert_called_once_with(self.metric.uid)

    @patch("htmengine.model_swapper.utils.deleteHTMModel", auto_spec=True)
    @patch("htm.it.app.webservices.autostacks_api.repository", auto_spec=True)
    def testDELETEAutostackMetricsWrongAutostack(self, repositoryMock, *_args):
        repositoryMock.getAutostackFromMetric.return_value = Mock(
            uid="wrong-autostack-id")
        with self.assertRaises(AppError) as cm:
            self.app.delete("/" + self.autostack.uid + "/metrics/" +
                            self.metric.uid,
                            headers=self.headers)
        self.assertIn("Bad response: 400 Bad Request", str(cm.exception))
        self.assertIn(
            "Metric=cebe9fab-f416-4845-8dab-02d292244112 does not belong to "
            "autostack=blahblahblah", str(cm.exception))

    @patch("htm.it.app.webservices.models_api.repository")
    def testDELETEAutostackMetricsFromModelsAPI(self, repositoryMock, *_args):
        repositoryMock.getMetric.return_value = self.metric

        app = TestApp(models_api.app.wsgifunc())

        with self.assertRaises(AppError) as e:
            app.delete("/" + self.metric.uid, headers=self.headers)

        self.assertIn("Bad response: 405 Method Not Allowed", str(e.exception))
Beispiel #26
0
class AnnotationsHandlerTest(unittest.TestCase):

  def setUp(self):
    self.headers = getDefaultHTTPHeaders(YOMP.app.config)
    self.app = TestApp(annotations_api.app.wsgifunc())
    self.annotation = {
      "uid": "f4aa70b361f04036b0b39530900f38fa",
      "timestamp": "2014-01-25 05:00:00",
      "created": "2014-01-25 07:14:06",
      "device": "device1",
      "user": "******",
      "server": "YOMPdb2",
      "message": "My annotation",
      "data": None
    }
    # Prepare request as annotation without "uid" or "created" fields
    self.request = self.annotation.copy()
    del self.request["uid"]
    del self.request["created"]


  @patch("YOMP.app.repository.getAnnotationById")
  def testGETAnnotationById(self, getAnnotationById, _):
    """
      Test Get Annotation

      Request::

        GET /_annotations/{uid}

    Response::

      HTTP 200 Ok
      [
        {
           "uid": "2a123bb1dd4d46e7a806d62efc29cbb9",
           "device", "1231AC32FE",
           "created":"2013-08-27 16:46:51",
           "timestamp":"2013-08-27 16:45:00",
           "user":"******",
           "server":" AWS/EC2/i-53f52b67",
           "message":" The CPU Utilization was high ...",
           "data": { Optional JSON Object }
         }
      ]
    """
    getAnnotationById.return_value = self.annotation

    response = self.app.get("/%s" % self.annotation["uid"],
                            headers=self.headers)
    self.assertEqual(response.status, 200)
    actual = json.loads(response.body)
    expected = json.loads(app_utils.jsonEncode(self.annotation))

    self.assertDictEqual(expected, actual[0])


  @patch("YOMP.app.repository.getAnnotationById")
  def testGETAnnotationByIdNotFound(self, getAnnotationById, _):
    """
      Test Get Annotation for unknown uid

      Request::

        GET /_annotations/{uid}

    Response::

      HTTP 404 Not Found

    """
    getAnnotationById.side_effect = app_exceptions.ObjectNotFoundError
    with self.assertRaises(AppError) as e:
      self.app.get("/dummy", headers=self.headers)

    self.assertIn("Bad response: 404 Not Found", str(e.exception))


  @patch("YOMP.app.repository.getAnnotations")
  def testGetAnnotations(self, getAnnotations, _):
    """
      Test Get Annotation

      Request::

        GET /_annotations?device={device}&user={user}&server={server}
                          &from={from}&to={to}

    Response::

      HTTP 200 Ok
      [
        {
           "uid": "2a123bb1dd4d46e7a806d62efc29cbb9",
           "device", "1231AC32FE",
           "created":"2013-08-27 16:46:51",
           "timestamp":"2013-08-27 16:45:00",
           "user":"******",
           "server":" AWS/EC2/i-53f52b67",
           "message":" The CPU Utilization was high ...",
           "data": { Optional JSON Object }
         },
        ...
      ]
    """
    getAnnotations.return_value = [self.annotation]

    response = self.app.get("?%s=%s" % ("server", "dummy"),
                            headers=self.headers)
    self.assertEqual(response.status, 200)
    actual = json.loads(response.body)
    expected = json.loads(app_utils.jsonEncode(self.annotation))

    self.assertDictEqual(expected, actual[0])


  @patch("YOMP.app.repository.deleteAnnotationById")
  def testDeleteAnnotationNotFound(self, deleteAnnotationById, _):
    """
    Test Delete unknown Annotation

    Request::

      DELETE /_annotations/{uid}

    Response::

      HTTP 404 Not Found
    """
    deleteAnnotationById.side_effect = app_exceptions.ObjectNotFoundError
    with self.assertRaises(AppError) as e:
      self.app.delete("/dummy", headers=self.headers)

    self.assertIn("Bad response: 404 Not Found", str(e.exception))


  @patch("YOMP.app.repository.deleteAnnotationById")
  def testDeleteAnnotation(self, deleteAnnotationById, _):
    """
    Test Delete Annotation

    Request::

      DELETE /_annotations/{uid}

    Response::

      HTTP 204 No Content
    """
    response = self.app.delete("/%s" % self.annotation["uid"],
                               headers=self.headers)
    self.assertEqual(response.status, 204)
    self.assertFalse(response.body)
    self.assertTrue(deleteAnnotationById.called)


  @patch("YOMP.app.repository.addAnnotation")
  def testAddAnnotation(self, addAnnotation, _):
    """
    Test Create new Annotation

    Request::

      POST /_annotations

      {
         "device", "1231AC32FE",
         "timestamp":"2013-08-27 16:45:00",
         "user":"******",
         "server":" AWS/EC2/i-53f52b67",
         "message":" The CPU Utilization was high ...",
         "data": { Optional JSON Object }
      }

    Response::

      HTTP Status 201 Created

      {
         "uid": "2a123bb1dd4d46e7a806d62efc29cbb9",
         "device", "1231AC32FE",
         "created":"2013-08-27 16:46:51",
         "timestamp":"2013-08-27 16:45:00",
         "user":"******",
         "server":" AWS/EC2/i-53f52b67",
         "message":" The CPU Utilization was high ...",
         "data": { Optional JSON Object }
      }
    """
    addAnnotation.return_value = self.annotation

    response = self.app.post("", app_utils.jsonEncode(self.request),
                             headers=self.headers)
    self.assertEqual(response.status, 201)
    actual = json.loads(response.body)
    # The result should contain new "uid" and "created" fields
    self.assertIn("uid", actual)
    self.assertIn("created", actual)
    # All the other fields should match request
    self.assertDictContainsSubset(self.request, actual)


  def testAddAnnotationIncomplete(self, _):
    """
    Test Failed to Create incomplete Annotation

    Response::

      HTTP Status 400 Missing "field" in request
    """
    # Annotation without timestamp
    badRequest = self.request.copy()
    del badRequest["timestamp"]
    with self.assertRaises(AppError) as e:
      self.app.post("", app_utils.jsonEncode(badRequest), headers=self.headers)

    error = e.exception
    self.assertRegexpMatches(error.message, "Missing 'timestamp' in request")

    # Annotation without device
    badRequest = self.request.copy()
    del badRequest["device"]
    with self.assertRaises(AppError) as e:
      self.app.post("", app_utils.jsonEncode(badRequest), headers=self.headers)

    error = e.exception
    self.assertRegexpMatches(error.message, "Missing 'device' in request")

    # Annotation without server
    badRequest = self.request.copy()
    del badRequest["server"]
    with self.assertRaises(AppError) as e:
      self.app.post("", app_utils.jsonEncode(badRequest), headers=self.headers)

    error = e.exception
    self.assertRegexpMatches(error.message, "Missing 'server' in request")

    # Annotation without user
    badRequest = self.request.copy()
    del badRequest["user"]
    with self.assertRaises(AppError) as e:
      self.app.post("", app_utils.jsonEncode(badRequest), headers=self.headers)

    error = e.exception
    self.assertRegexpMatches(error.message, "Missing 'user' in request")

    # Annotation without data and message
    badRequest = self.request.copy()
    del badRequest["message"]
    del badRequest["data"]
    with self.assertRaises(AppError) as e:
      self.app.post("", app_utils.jsonEncode(badRequest), headers=self.headers)

    error = e.exception
    self.assertRegexpMatches(error.message,
                             "Annotation must contain either 'message' or 'data'")


  def testAddAnnotationInvalidJSON(self, _):
    """
    Test failed to create annotation with invalid JSON argument

    Response::

      HTTP Status 400 Invalid JSON in request
    """
    badRequest = "{Not a JSON Request}"
    with self.assertRaises(AppError) as e:
      self.app.post("", badRequest, headers=self.headers)

    error = e.exception
    self.assertRegexpMatches(error.message, "Invalid JSON in request")
class InstancesApiSingleTest(unittest.TestCase):
  """
  Integration tests methods for single instance
  """


  def setUp(self):
    self.app = TestApp(instances_api.app.wsgifunc())
    self.headers = getDefaultHTTPHeaders(grok.app.config)


  @ManagedTempRepository("InstancesApiSingleInstance")
  def testLifecycleForSingleInstance(self):
    """
    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    Make sure app returns empty list at initial step

    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke post with valid instanceId

    Test for get '/_instances/{instanceId}'
    response is validated for appropriate headers, body and status
    Check if you can invoke get on previously post'ed instance Instance

    Test for delete '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    This invokes delete call on previously monitored instance

    Test for get '/_instances/{instanceId}'
    response is validated for appropriate headers, body and status
    This invokes get call with instanceId which is deleted from monitored list
    """

    # check initial empty response with get request
    initialGetResponse = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, initialGetResponse)
    initialGetResult = app_utils.jsonDecode(initialGetResponse.body)
    self.assertItemsEqual(initialGetResult, [])

    # Post single instance details to add under monitor
    region = VALID_EC2_INSTANCES["jenkins-master"]["region"]
    namespace = "EC2"
    instanceId = "%s/AWS/%s/%s" % (
      region, namespace, VALID_EC2_INSTANCES["jenkins-master"]["instanceId"])
    postResponse = self.app.post("/" + instanceId, headers=self.headers)
    assertions.assertSuccess(self, postResponse)
    postResult = app_utils.jsonDecode(postResponse.body)
    self.assertIsInstance(postResult, dict)
    self.assertEqual(postResult, {"result": "success"})

    # Verify that instance is successfully added under monitor
    getPostCheckResponse = self.app.get("", headers=self.headers)
    assertions.assertSuccess(self, getPostCheckResponse)
    getPostCheckResult = app_utils.jsonDecode(getPostCheckResponse.body)
    self.assertEqual(len(getPostCheckResult), 1)
    instanceResult = getPostCheckResult[0]
    self.assertEqual(region, instanceResult["location"])
    self.assertTrue(instanceId, instanceResult["server"])

    # Delete instance from monitor
    deleteResponse = self.app.delete("/", headers=self.headers,
                                     params=json.dumps([instanceId]))
    assertions.assertDeleteSuccessResponse(self, deleteResponse)

    # Check get reponse to confirm that instance has been deleted successfully
    getPostDeleteResponse = self.app.get("", headers=self.headers)
    postResult = app_utils.jsonDecode(getPostDeleteResponse.body)
    self.assertEqual(postResult, [])

    # TODO:  Assertion pending MER-1170
    #assertions.assertNotFound(self, getPostDeleteResponse)
    #self.assertEqual("Instance %s was not found" % instanceId,
    # getPostDeleteResponse.body)


  @ManagedTempRepository("InstancesApiSingleInstance")
  def testPostWithInvalidRegion(self):
    """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with region that does not exists
    """
    region = "fake-region"
    namespace = "EC2"
    instanceId = VALID_EC2_INSTANCES["jenkins-master"]["instanceId"]
    response = self.app.post("/%s/AWS/%s/%s" % (region, namespace, instanceId),
      headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("Not supported.", response.body)


  @ManagedTempRepository("InstancesApiSingleInstance")
  def testPostWithInvalidNamespace(self):
    """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with namespace that does not exists
    """
    region = "us-west-2"
    namespace = "foo"
    instanceId = VALID_EC2_INSTANCES["jenkins-master"]["instanceId"]
    response = self.app.post("/%s/AWS/%s/%s" % (region, namespace, instanceId),
      headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("Not supported.", response.body)


  @ManagedTempRepository("InstancesApiSingleInstance")
  def testPostWithInvalidServiceName(self):
    """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with namespace that does not exists. Specifically
    replace AWS with some invalid string making namespace invalid
    """
    region = "us-west-2"
    namespace = "EC2"
    instanceId = VALID_EC2_INSTANCES["jenkins-master"]["instanceId"]
    response = self.app.post("/%s/foo/%s/%s" % (region, namespace, instanceId),
      headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("Not supported.", response.body)


  @ManagedTempRepository("InstancesApiSingleInstance")
  def testPostWithInvalidInstanceId(self):
    """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with instanceId that does not exists

    Expect a 200 OK even when attempting to POST to an invalid instance,
    this saves the overhead of asking AWS if we're dealing with a valid
    instance every POST.

    We expect the CLI user to know what instance ID he/she is looking for.
    """
    region = "us-west-2"
    namespace = "EC2"
    instanceId = "abcd1234"
    response = self.app.post("/%s/AWS/%s/%s" % (region, namespace, instanceId),
      headers=self.headers, status="*")
    assertions.assertSuccess(self, response)

  @ManagedTempRepository("InstancesApiSingleInstance")
  def testPostInstanceIdToIncorrectNamespace(self):
    """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with instance to incorrect namespace.
    e.g post grok-docs-elb to AWS/EC2

    Expect a 200 OK even when attempting to POST an instance to the wrong
    namespace, this saves the overhead of asking AWS if we're dealing with a
    valid instance in the given namespace with every POST request.

    We expect the CLI user to know what instance ID he/she is looking for.
    """
    region = "us-west-2"
    namespace = "EC2"
    instanceId = "grok-docs-elb"
    response = self.app.post("/%s/AWS/%s/%s" % (region, namespace, instanceId),
      headers=self.headers, status="*")
    assertions.assertSuccess(self, response)


  @ManagedTempRepository("InstancesApiSingleInstance")
  def testPostWithoutInstanceId(self):
    """
    Test for post '/_instances/region/namespace/instanceId' without instanceId
    response is validated for appropriate headers, body and status
    This invokes post call with without instanceId
    """
    response = self.app.post("/us-west-2/AWS/EC2/",
     headers=self.headers, status="*")
    assertions.assertBadRequest(self, response, "json")
    self.assertIn("Invalid request", response.body)
Beispiel #28
0
class InstancesHandlerTest(unittest.TestCase):
    """Unit tests for class InstancesHandler from Instances API."""
    def setUp(self):
        self.app = TestApp(instances_api.app.wsgifunc())
        self.headers = getDefaultHTTPHeaders(config)

    def _getInstancesHandlerCommon(self, instancesMock, route, expectedResult):
        """
    This method wraps around common testing path for all GET routes which falls
    to listing all available instances
    instancesMock : Mock for Instances class
    route : route under test for current testcase
    expectedResult : expected response from API call
    """
        response = self.app.get(route, headers=self.headers)
        assertions.assertSuccess(self, response)
        result = app_utils.jsonDecode(response.body)
        self.assertIsInstance(result, list)
        self.assertEqual(result, expectedResult)
        self.assertTrue(instancesMock.getInstances.called)

    @patch.object(repository, "getInstances", autospec=True)
    def testGetInstancesHandlerEmptyResponse(self, getInstancesMock,
                                             engineFactoryMock):
        """
    Test for Get "/_instances"
    response is validated for appropriate headers, body and status
    """
        getInstancesMock.return_value = []

        response = self.app.get("", headers=self.headers)
        assertions.assertSuccess(self, response)
        result = app_utils.jsonDecode(response.body)

        self.assertIsInstance(result, list)
        self.assertEqual(result, [])
        self.assertTrue(getInstancesMock.called)
        getInstancesMock.assert_called_with(
            engineFactoryMock.return_value.connect.return_value.__enter__.
            return_value)

    @patch.object(repository, "getInstances", autospec=True)
    def testGetInstancesHandlerNonEmptyResponse(self, getInstancesMock,
                                                engineFactoryMock):
        """
    Test for Get "/_instances"
    response is validated for appropriate headers, body and status
    """
        instancesAPIData = json.load(
            open(
                os.path.join(
                    YOMP_HOME,
                    "tests/py/data/app/webservices/instances_api.json")))
        getInstancesMock.return_value = instancesAPIData["getInstances"]

        response = self.app.get("", headers=self.headers)
        assertions.assertSuccess(self, response)
        result = app_utils.jsonDecode(response.body)

        self.assertIsInstance(result, list)
        self.assertEqual(result, instancesAPIData["getInstances"])
        self.assertTrue(getInstancesMock.called)
        getInstancesMock.assert_called_with(
            engineFactoryMock.return_value.connect.return_value.__enter__.
            return_value)

    @patch.object(repository, "getInstances", autospec=True)
    def testGetInstancesHandlerEmptyResponseWithSlash(self, getInstancesMock,
                                                      engineFactoryMock):
        """
    Test for Get "/_instances/"
    response is validated for appropriate headers, body and status
    """
        getInstancesMock.return_value = []

        response = self.app.get("/", headers=self.headers)
        assertions.assertSuccess(self, response)
        result = app_utils.jsonDecode(response.body)

        self.assertIsInstance(result, list)
        self.assertEqual(result, [])
        self.assertTrue(getInstancesMock.called)
        getInstancesMock.assert_called_with(
            engineFactoryMock.return_value.connect.return_value.__enter__.
            return_value)

    @patch("YOMP.app.webservices.instances_api.repository.getInstances",
           autospec=True)
    def testGetInstancesHandlerNonEmptyResponseWithSlash(
            self, getInstancesMock, engineFactoryMock):
        """
    Test for Get "/_instances/"
    response is validated for appropriate headers, body and status
    """
        instancesAPIData = json.load(
            open(
                os.path.join(
                    YOMP_HOME,
                    "tests/py/data/app/webservices/instances_api.json")))
        getInstancesMock.return_value = instancesAPIData["getInstances"]

        response = self.app.get("/", headers=self.headers)
        assertions.assertSuccess(self, response)
        result = app_utils.jsonDecode(response.body)

        self.assertIsInstance(result, list)
        self.assertEqual(result, instancesAPIData["getInstances"])
        self.assertTrue(getInstancesMock.called)
        getInstancesMock.assert_called_with(
            engineFactoryMock.return_value.connect.return_value.__enter__.
            return_value)

    @patch.object(repository, "listMetricIDsForInstance", autospec=True)
    @patch("YOMP.app.webservices.models_api.ModelHandler.deleteModel",
           new=Mock(spec_set=models_api.ModelHandler.deleteModel))
    def testDeleteInstancesHandler(self, listMetricIDsMock, engineFactoryMock):
        """
    Test for Delete "/_instances"
    response is validated for appropriate headers, body and status
    """
        listMetricIDsMock.return_value = \
          ["2490fb7a9df5470fa3678530c4cb0a43", "b491ab2310ef4a799b14c08fa3e09f1c"]
        params = ["YOMP-docs-elb", "i-e16bd2d5"]
        response = self.app.delete("",
                                   params=app_utils.jsonEncode(params),
                                   headers=self.headers)
        assertions.assertDeleteSuccessResponse(self, response)
        self.assertTrue(listMetricIDsMock.called)
        listMetricIDsMock.assert_called_with(
            (engineFactoryMock.return_value.connect.return_value.__enter__.
             return_value), params[1])

    @patch.object(repository, "listMetricIDsForInstance", autospec=True)
    @patch("YOMP.app.webservices.models_api.ModelHandler.deleteModel",
           new=Mock(spec_set=models_api.ModelHandler.deleteModel))
    def testDeleteInstancesHandlerNonJSONData(self, listMetricIDsMock,
                                              _engineFactoryMock):
        """
    Test for Delete "/_instances" with non JSON input
    response is validated for appropriate headers, body and status
    """
        response = self.app.delete("",
                                   params="params",
                                   headers=self.headers,
                                   status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertFalse(listMetricIDsMock.called)

    @patch.object(repository, "listMetricIDsForInstance", autospec=True)
    @patch("YOMP.app.webservices.models_api.ModelHandler.deleteModel",
           new=Mock(spec_set=models_api.ModelHandler.deleteModel))
    def testDeleteInstancesHandlerEmptyData(self, listMetricIDsMock,
                                            _engineFactoryMock):
        """
    Test for Delete "/_instances" with with empty input data
    response is validated for appropriate headers, body and status
    """
        params = []
        response = self.app.delete("",
                                   params=app_utils.jsonEncode(params),
                                   headers=self.headers,
                                   status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertFalse(listMetricIDsMock.called)
Beispiel #29
0
class InstancesApiMultipleInstanceTest(unittest.TestCase):
    """
  Integration tests methods for multiple instaces
  """
    def setUp(self):
        self.app = TestApp(instances_api.app.wsgifunc())
        self.headers = getDefaultHTTPHeaders(grok.app.config)

    @ManagedTempRepository("InstancesApiMultiple")
    def testLifecycleForMultipleInstances(self):
        """
    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    This expects response from application in initial stage when
    no instances are under monitor

    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    post multiple instances

    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    This test check for listed monitored instances from previous step

    Test for delete '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with valid instanceId for listed monitored instances
    from previous step


    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    This invokes get call to assert that all instances which were
    under monitor have been deleted and we get empty response
    """
        # Check instance list at initial phase for empty response
        getIntialResponse = self.app.get("", headers=self.headers)
        assertions.assertSuccess(self, getIntialResponse)
        getIntialResult = app_utils.jsonDecode(getIntialResponse.body)
        self.assertItemsEqual(getIntialResult, [])

        # Test for post '/_instances'

        # TODO: Until MER-1172 is resolved
        # test will execute this as temporary. This will add expected instances
        # under monitor. Which will be used for further tests
        # here adding
        params = [
            VALID_EC2_INSTANCES["rpm-builder"]["instanceId"],
            VALID_EC2_INSTANCES["grok-docs"]["instanceId"]
        ]
        region = "us-west-2"
        namespace = "EC2"
        for instance in params:
            postResponse = self.app.post("/%s/AWS/%s/%s" %
                                         (region, namespace, instance),
                                         headers=self.headers)
            assertions.assertSuccess(self, postResponse)
            postResult = app_utils.jsonDecode(postResponse.body)
            self.assertIsInstance(postResult, dict)
            self.assertEqual(postResult, {"result": "success"})

        # TODO Use Api calls below once MER-1172 is resolved

        #postResponse = self.app.post("/us-west-2/AWS/EC2",
        #  params=app_utils.jsonEncode(params), headers=self.headers, status="*")
        #assertions.assertSuccess(self, response)
        #postResult = app_utils.jsonDecode(postResponse.body)
        #self.assertIsInstance(postResult, dict)
        #self.assertEqual(postResult, {"result": "success"})

        # Test for Get '/_instances'
        getPostCheckResponse = self.app.get("", headers=self.headers)
        assertions.assertSuccess(self, getPostCheckResponse)
        getPostCheckResult = app_utils.jsonDecode(getPostCheckResponse.body)
        instanceIds = []
        self.assertIsInstance(getPostCheckResult, list)
        for instance in getPostCheckResult:
            instanceIds.append(instance["server"])
            self.assertEqual(instance["namespace"], "AWS/EC2")
            self.assertEqual(instance["location"], "us-west-2")
        self.assertItemsEqual(
            [instanceId.rpartition("/")[2] for instanceId in instanceIds],
            params)

        # Delete instances under monitor
        deleteResponse = self.app.delete(
            "", params=app_utils.jsonEncode(instanceIds), headers=self.headers)
        assertions.assertDeleteSuccessResponse(self, deleteResponse)

        # check instances to confirm the delete action
        getPostDeleteCheckResponse = self.app.get("", headers=self.headers)
        assertions.assertSuccess(self, getPostDeleteCheckResponse)
        getPostDeleteResult = app_utils.jsonDecode(
            getPostDeleteCheckResponse.body)
        self.assertItemsEqual(getPostDeleteResult, [])

    @ManagedTempRepository("InstancesApiMultiple")
    def testPostMultipleWithEmptyData(self):
        """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with empty data
    """
        params = []
        response = self.app.post("/us-west-2/AWS/EC2",
                                 params=app_utils.jsonEncode(params),
                                 headers=self.headers,
                                 status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("InvalidArgumentsError", response.body)

    @ManagedTempRepository("InstancesApiMultiple")
    def testPostMultipleWithNonJsonData(self):
        """
    Test for '/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with non-json data
    """
        params = []
        response = self.app.post("/us-west-2/AWS/EC2",
                                 params=params,
                                 headers=self.headers,
                                 status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("Invalid request", response.body)

    @ManagedTempRepository("InstancesApiMultiple")
    def testPostMultipleWithInvalidInstanceId(self):
        """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with invalid instanceId

    Expect a 200 OK even when attempting to POST to an invalid instance,
    this saves the overhead of asking AWS if we're dealing with a valid
    instance every POST.

    We expect the CLI user to know what instance ID he/she is looking for.
    """
        params = ["abcd1234"]
        response = self.app.post("/us-west-2/AWS/EC2",
                                 params=app_utils.jsonEncode(params),
                                 headers=self.headers,
                                 status="*")
        assertions.assertSuccess(self, response)

    @ManagedTempRepository("InstancesApiMultiple")
    def testPostMultipleWithInstanceToIncorrectNamespace(self):
        """
    Test for post'/_instances'
    response is validated for appropriate headers, body and status
    Invoke post with valid instance id to incorrect namespace

    Expect a 200 OK even when attempting to POST an instance to the wrong
    namespace, this saves the overhead of asking AWS if we're dealing with a
    valid instance in the given namespace with every POST request.

    We expect the CLI user to know what instance ID he/she is looking for.

    """
        params = ["grok-docs-elb"]
        response = self.app.post("/us-west-2/AWS/EC2",
                                 params=app_utils.jsonEncode(params),
                                 headers=self.headers,
                                 status="*")
        assertions.assertSuccess(self, response)

    @ManagedTempRepository("InstancesApiMultiple")
    def testPostMultipleWithInstanceToIncorrectRegion(self):
        """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke post with valid instance id to incorrect region
    """
        params = [VALID_EC2_INSTANCES["jenkins-master"]]
        response = self.app.post("/us-east-1/AWS/EC2",
                                 params=app_utils.jsonEncode(params),
                                 headers=self.headers,
                                 status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("InvalidArgumentsError", response.body)

    @ManagedTempRepository("InstancesApiMultiple")
    def testDeleteMultipleWithEmptyData(self):
        """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with empty data
    """
        params = []

        with self.assertRaises(AppError) as err:
            self.app.delete("",
                            params=app_utils.jsonEncode(params),
                            headers=self.headers)

        self.assertIn("Missing instances in DELETE request",
                      str(err.exception))

    @ManagedTempRepository("InstancesApiMultiple")
    def testDeleteMultipleWithInvalidInstanceId(self):
        """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with invalid Instance id
    """
        params = ["abcd1234"]
        response = self.app.delete("",
                                   params=app_utils.jsonEncode(params),
                                   headers=self.headers,
                                   status="*")
        assertions.assertNotFound(self, response)
        self.assertIn("Not able to delete", response.body)

    @ManagedTempRepository("InstancesApiMultiple")
    def testDeleteMultipleinstancesWithInvalidData(self):
        """
    Test for post '/_instances'
    response is validated for appropriate headers, body and status
    invoke delete with invalid Instance id
    """
        params = []
        response = self.app.delete("",
                                   params=params,
                                   headers=self.headers,
                                   status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("Invalid request", response.body)
Beispiel #30
0
class InstancesApiSingleTest(unittest.TestCase):
    """
  Integration tests methods for single instance
  """
    def setUp(self):
        self.app = TestApp(instances_api.app.wsgifunc())
        self.headers = getDefaultHTTPHeaders(grok.app.config)

    @ManagedTempRepository("InstancesApiSingleInstance")
    def testLifecycleForSingleInstance(self):
        """
    Test for Get '/_instances'
    response is validated for appropriate headers, body and status
    Make sure app returns empty list at initial step

    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke post with valid instanceId

    Test for get '/_instances/{instanceId}'
    response is validated for appropriate headers, body and status
    Check if you can invoke get on previously post'ed instance Instance

    Test for delete '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    This invokes delete call on previously monitored instance

    Test for get '/_instances/{instanceId}'
    response is validated for appropriate headers, body and status
    This invokes get call with instanceId which is deleted from monitored list
    """

        # check initial empty response with get request
        initialGetResponse = self.app.get("", headers=self.headers)
        assertions.assertSuccess(self, initialGetResponse)
        initialGetResult = app_utils.jsonDecode(initialGetResponse.body)
        self.assertItemsEqual(initialGetResult, [])

        # Post single instance details to add under monitor
        region = VALID_EC2_INSTANCES["jenkins-master"]["region"]
        namespace = "EC2"
        instanceId = "%s/AWS/%s/%s" % (
            region, namespace,
            VALID_EC2_INSTANCES["jenkins-master"]["instanceId"])
        postResponse = self.app.post("/" + instanceId, headers=self.headers)
        assertions.assertSuccess(self, postResponse)
        postResult = app_utils.jsonDecode(postResponse.body)
        self.assertIsInstance(postResult, dict)
        self.assertEqual(postResult, {"result": "success"})

        # Verify that instance is successfully added under monitor
        getPostCheckResponse = self.app.get("", headers=self.headers)
        assertions.assertSuccess(self, getPostCheckResponse)
        getPostCheckResult = app_utils.jsonDecode(getPostCheckResponse.body)
        self.assertEqual(len(getPostCheckResult), 1)
        instanceResult = getPostCheckResult[0]
        self.assertEqual(region, instanceResult["location"])
        self.assertTrue(instanceId, instanceResult["server"])

        # Delete instance from monitor
        deleteResponse = self.app.delete("/",
                                         headers=self.headers,
                                         params=json.dumps([instanceId]))
        assertions.assertDeleteSuccessResponse(self, deleteResponse)

        # Check get reponse to confirm that instance has been deleted successfully
        getPostDeleteResponse = self.app.get("", headers=self.headers)
        postResult = app_utils.jsonDecode(getPostDeleteResponse.body)
        self.assertEqual(postResult, [])

        # TODO:  Assertion pending MER-1170
        #assertions.assertNotFound(self, getPostDeleteResponse)
        #self.assertEqual("Instance %s was not found" % instanceId,
        # getPostDeleteResponse.body)

    @ManagedTempRepository("InstancesApiSingleInstance")
    def testPostWithInvalidRegion(self):
        """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with region that does not exists
    """
        region = "fake-region"
        namespace = "EC2"
        instanceId = VALID_EC2_INSTANCES["jenkins-master"]["instanceId"]
        response = self.app.post("/%s/AWS/%s/%s" %
                                 (region, namespace, instanceId),
                                 headers=self.headers,
                                 status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("Not supported.", response.body)

    @ManagedTempRepository("InstancesApiSingleInstance")
    def testPostWithInvalidNamespace(self):
        """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with namespace that does not exists
    """
        region = "us-west-2"
        namespace = "foo"
        instanceId = VALID_EC2_INSTANCES["jenkins-master"]["instanceId"]
        response = self.app.post("/%s/AWS/%s/%s" %
                                 (region, namespace, instanceId),
                                 headers=self.headers,
                                 status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("Not supported.", response.body)

    @ManagedTempRepository("InstancesApiSingleInstance")
    def testPostWithInvalidServiceName(self):
        """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with namespace that does not exists. Specifically
    replace AWS with some invalid string making namespace invalid
    """
        region = "us-west-2"
        namespace = "EC2"
        instanceId = VALID_EC2_INSTANCES["jenkins-master"]["instanceId"]
        response = self.app.post("/%s/foo/%s/%s" %
                                 (region, namespace, instanceId),
                                 headers=self.headers,
                                 status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("Not supported.", response.body)

    @ManagedTempRepository("InstancesApiSingleInstance")
    def testPostWithInvalidInstanceId(self):
        """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with instanceId that does not exists

    Expect a 200 OK even when attempting to POST to an invalid instance,
    this saves the overhead of asking AWS if we're dealing with a valid
    instance every POST.

    We expect the CLI user to know what instance ID he/she is looking for.
    """
        region = "us-west-2"
        namespace = "EC2"
        instanceId = "abcd1234"
        response = self.app.post("/%s/AWS/%s/%s" %
                                 (region, namespace, instanceId),
                                 headers=self.headers,
                                 status="*")
        assertions.assertSuccess(self, response)

    @ManagedTempRepository("InstancesApiSingleInstance")
    def testPostInstanceIdToIncorrectNamespace(self):
        """
    Test for post '/_instances/region/namespace/instanceId'
    response is validated for appropriate headers, body and status
    Invoke Api call with instance to incorrect namespace.
    e.g post grok-docs-elb to AWS/EC2

    Expect a 200 OK even when attempting to POST an instance to the wrong
    namespace, this saves the overhead of asking AWS if we're dealing with a
    valid instance in the given namespace with every POST request.

    We expect the CLI user to know what instance ID he/she is looking for.
    """
        region = "us-west-2"
        namespace = "EC2"
        instanceId = "grok-docs-elb"
        response = self.app.post("/%s/AWS/%s/%s" %
                                 (region, namespace, instanceId),
                                 headers=self.headers,
                                 status="*")
        assertions.assertSuccess(self, response)

    @ManagedTempRepository("InstancesApiSingleInstance")
    def testPostWithoutInstanceId(self):
        """
    Test for post '/_instances/region/namespace/instanceId' without instanceId
    response is validated for appropriate headers, body and status
    This invokes post call with without instanceId
    """
        response = self.app.post("/us-west-2/AWS/EC2/",
                                 headers=self.headers,
                                 status="*")
        assertions.assertBadRequest(self, response, "json")
        self.assertIn("Invalid request", response.body)
Beispiel #31
0
class TestRestAPI(unittest.TestCase):

    def setUp(self):
        middleware = []
        self.logger = logging.getLogger('restapi')
        urls = karesansui.urls.urls
        app = web.application(urls, globals(), autoreload=False)

        from karesansui.app import load_sqlalchemy_karesansui,load_sqlalchemy_pysilhouette
        app.add_processor(load_sqlalchemy_karesansui)
        app.add_processor(load_sqlalchemy_pysilhouette)

        self.prefix = ""
        if karesansui.config['application.url.prefix']:
            mapping = (karesansui.config['application.url.prefix'],  app)
            app = web.subdir_application(mapping)
            self.prefix = karesansui.config['application.url.prefix']

        self.app = TestApp(app.wsgifunc(*middleware))

        self.headers = {}
        if username != None and password != None:
            from base64 import b64encode
            base64string =b64encode("%s:%s" % (username, password))
            self.headers = {"Authorization": "Basic %s" % base64string}

        return True

    def tearDown(self):
        return True

    def test_dummy(self):
        self.assertEqual(True,True)
 
    def test_get_index(self):
        r = self.app.get("%s/" % self.prefix,headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('Now Loading')

    def test_get_host_1_index(self):
        r = self.app.get("%s/host/1/" % self.prefix,headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('Now Loading')

    def test_get_host_1_json(self):
        r = self.app.get("%s/host/1.json" % self.prefix,headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')

    def test_get_host_1_guest_2_index(self):
        r = self.app.get("%s/host/1/guest/2/" % self.prefix,headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('Now Loading')

    def test_get_host_1_guest_2_json(self):
        r = self.app.get("%s/host/1/guest/2.json" % self.prefix,headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')

    def test_post_host_1_guest(self):

        params = {}
        params['domain_name'] = 'foobar'
        params['m_name'] = 'foobar'
        params['icon_filename'] = ''
        params['m_hypervisor'] = '1'
        params['note_title'] = 'title'
        params['note_value'] = 'value'
        params['tags'] = ''
        params['nic_type'] = 'phydev'
        params['phydev'] = 'xenbr0'
        params['virnet'] = 'default'
        params['xen_disk_size'] = '4096'
        params['xen_extra'] = ''
        params['xen_initrd'] = '/var/ftp/images/xen/initrd.img'
        params['xen_kernel'] = '/var/ftp/images/xen/vmlinuz'
        params['xen_mac'] = '00:16:3e:4e:4d:e2'
        params['xen_mem_size'] = '256'
        params['xen_graphics_port'] = '5910'
        upload_files=None

        r = self.app.post("%s/host/1/guest.part" % self.prefix,params=params,headers=self.headers,upload_files=upload_files)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')

    def test_del_host_1_guest_2(self):
        r = self.app.delete("%s/host/1/guest/2" % self.prefix,headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')
Beispiel #32
0
class TestRestAPI(unittest.TestCase):
    def setUp(self):
        middleware = []
        self.logger = logging.getLogger('restapi')
        urls = karesansui.urls.urls
        app = web.application(urls, globals(), autoreload=False)

        from karesansui.app import load_sqlalchemy_karesansui, load_sqlalchemy_pysilhouette
        app.add_processor(load_sqlalchemy_karesansui)
        app.add_processor(load_sqlalchemy_pysilhouette)

        self.prefix = ""
        if karesansui.config['application.url.prefix']:
            mapping = (karesansui.config['application.url.prefix'], app)
            app = web.subdir_application(mapping)
            self.prefix = karesansui.config['application.url.prefix']

        self.app = TestApp(app.wsgifunc(*middleware))

        self.headers = {}
        if username != None and password != None:
            from base64 import b64encode
            base64string = b64encode("%s:%s" % (username, password))
            self.headers = {"Authorization": "Basic %s" % base64string}

        return True

    def tearDown(self):
        return True

    def test_dummy(self):
        self.assertEqual(True, True)

    def test_get_index(self):
        r = self.app.get("%s/" % self.prefix, headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('Now Loading')

    def test_get_host_1_index(self):
        r = self.app.get("%s/host/1/" % self.prefix, headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('Now Loading')

    def test_get_host_1_json(self):
        r = self.app.get("%s/host/1.json" % self.prefix, headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')

    def test_get_host_1_guest_2_index(self):
        r = self.app.get("%s/host/1/guest/2/" % self.prefix,
                         headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('Now Loading')

    def test_get_host_1_guest_2_json(self):
        r = self.app.get("%s/host/1/guest/2.json" % self.prefix,
                         headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')

    def test_post_host_1_guest(self):

        params = {}
        params['domain_name'] = 'foobar'
        params['m_name'] = 'foobar'
        params['icon_filename'] = ''
        params['m_hypervisor'] = '1'
        params['note_title'] = 'title'
        params['note_value'] = 'value'
        params['tags'] = ''
        params['nic_type'] = 'phydev'
        params['phydev'] = 'xenbr0'
        params['virnet'] = 'default'
        params['xen_disk_size'] = '4096'
        params['xen_extra'] = ''
        params['xen_initrd'] = '/var/ftp/images/xen/initrd.img'
        params['xen_kernel'] = '/var/ftp/images/xen/vmlinuz'
        params['xen_mac'] = '00:16:3e:4e:4d:e2'
        params['xen_mem_size'] = '256'
        params['xen_graphics_port'] = '5910'
        upload_files = None

        r = self.app.post("%s/host/1/guest.part" % self.prefix,
                          params=params,
                          headers=self.headers,
                          upload_files=upload_files)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')

    def test_del_host_1_guest_2(self):
        r = self.app.delete("%s/host/1/guest/2" % self.prefix,
                            headers=self.headers)
        assert_equal(r.status, 200)
        r.mustcontain('other_url')