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)
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")
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")
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")
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")
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)
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"])
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))
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)
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)
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 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')
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')