def testGETSpecificInstanceFromRegion(self): """ Test for Get '/_metrics/cloudwatch/<region-name>/AWS/<namespace>/instances/<InstancdId>' response is validated for appropriate headers, body and status Test is currently using ec2 box for jenkins-master, this test also validates for retriving all supported metrics with dimensions """ supportedMetrics = ( createCloudwatchDatasourceAdapter().describeSupportedMetrics()) ec2Metrics = supportedMetrics[ResourceTypeNames.EC2_INSTANCE].keys() # Instance used for following test is jenkins-master node response = self.app.get("/us-west-2/AWS/EC2/instances/%s" % VALID_EC2_INSTANCE["InstanceId"], headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertIsInstance(result, list) self.assertGreater(len(ec2Metrics), 0) self.assertGreater(len(result), 0) self.assertEqual(len(ec2Metrics), len(result)) for res in result: self.assertEqual(res["region"], "us-west-2") self.assertEqual(res["namespace"], "AWS/EC2") self.assertEqual(res["datasource"], "cloudwatch") self.assertIn(res["metric"], ec2Metrics) self.assertIsInstance(res["dimensions"], dict) self.assertEqual(res["dimensions"]["InstanceId"], VALID_EC2_INSTANCE["InstanceId"]) ec2Metrics.remove(res["metric"]) self.assertEqual(ec2Metrics, [])
def testCombinationQuota1(self): result = self.cloudwatchApp.get("/us-west-2/AWS/EC2", headers=self.headers) instances = json.loads(result.body) for i in range(0, 10, 5): instance = instances[i] instanceId = "us-west-2/AWS/EC2/%s" % ( instance["dimensions"]["InstanceId"]) postResponse = self.instancesApp.post("/%s" % instanceId, headers=self.headers) assertions.assertSuccess(self, postResponse) self.addCleanup(self.instancesApp.delete, "/", headers=self.headers, params=json.dumps([instanceId])) sock = socket.socket() sock.connect(("localhost", self.plaintextPort)) sock.sendall("CustomMetric1 5.0 1386201600\n") self.gracefullyCloseSocket(sock) self.addCleanup(self.customApp.delete, "/CustomMetric1", headers=self.headers) uid = self.checkMetricCreated("CustomMetric1") with self.assertRaises(AppError) as e: payload = {"uid": uid, "datasource": "custom", "min": 0.0, "max": 100.0} self.modelApp.post("/", json.dumps(payload), headers=self.headers) self.assertIn("Server limit exceeded", e.exception.message)
def testMetricsAPIGETCouldWatch(self, adapterMock): adapterMock.return_value.describeRegions.return_value = [] adapterMock.return_value.describeSupportedMetrics.return_value = {} response = self.app.get("/_metrics/cloudwatch", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, {'regions': {}, 'namespaces': {}})
def testGetModelDataWithModelUIdAndAnomalyScore(self): """ test GET /metricId/data?anomaly=testanomalyScore """ getMetricDataWithAnomalyQueryResponse = self.app.get( "/%s/data?anomaly=%s" % (self.uid, self.testAnomalyScore), headers=self.headers) getMetricDataWithAnomalyQueryResult = utils.jsonDecode( getMetricDataWithAnomalyQueryResponse.body) assertions.assertSuccess(self, getMetricDataWithAnomalyQueryResponse) self.assertIsInstance(getMetricDataWithAnomalyQueryResult, dict) self.assertItemsEqual(getMetricDataWithAnomalyQueryResult.keys(), ["data", "names"]) self.assertGreater(len(getMetricDataWithAnomalyQueryResult["data"]), 0) # we are parsing amomaly scores from reponse and chekcing if each of it # is satisfying value condition set with GET request. # If for some reason this parameter is not applied on DB query, we get # full response for this request # We are making sure each value for anomaly_score in result matches with # condition set in GET request, hence the assertion anomalyScores = \ [row[2] for row in getMetricDataWithAnomalyQueryResult["data"]] failedScores = [a for a in anomalyScores if a < self.testAnomalyScore] self.assertEqual(failedScores, [])
def testMetricsAPIGETDataSources(self, getDatasources): getDatasources.return_value = [] response = self.app.get("/_metrics/datasources", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, []) self.assertTrue(getDatasources.called)
def testMetricDataTimeStampQueryParams(uid): ''' This test makes MetricDataHandler GET calls with from and to params : _models/<uid>/data?from=<>&to=<> ''' with repository.engineFactory().connect() as conn: firstMetricData = conn.execute( sql.select([schema.metric_data]) .where(schema.metric_data.c.uid == uid) .order_by(sql.expression.asc(schema.metric_data.c.timestamp)) .limit(1)).fetchall() lastMetricData = conn.execute( sql.select([schema.metric_data]) .where(schema.metric_data.c.uid == uid) .order_by(sql.expression.desc(schema.metric_data.c.timestamp)) .limit(1)).fetchall() firstTimeStamp = firstMetricData[0].timestamp lastTimeStamp = lastMetricData[0].timestamp response = self.app.get("/%s/data?from=%s&to=%s" % (uid, firstTimeStamp, lastTimeStamp), headers=self.headers) assertions.assertSuccess(self, response) getAllModelsResult = utils.jsonDecode(response.body) for metricData in getAllModelsResult['data']: self.assertGreaterEqual(datetime.strptime(metricData[0], '%Y-%m-%d %H:%M:%S'), firstTimeStamp) self.assertLessEqual(datetime.strptime(metricData[0], '%Y-%m-%d %H:%M:%S'), lastTimeStamp)
def testGetInstanceWithDimension(self, adapterMock): """ Test for Get '/_metrics/cloudwatch/<region-name>/AWS/<namespace>/\ instances/<InstancdId>' with valid InstancceId response is validated for appropriate headers, body and status """ adapterMock.return_value.describeRegions.return_value = self.regions adapterMock.return_value.describeSupportedMetrics.return_value = ( self.resources) adapterMock.return_value.describeResources.return_value = [{ 'grn': u'aws://us-west-2/Instance/i-548acc3a', 'name': u'Bar', 'resID': u'i-548acc3a' }] response = self.app.get("/us-east-1/AWS/EC2/instances/i-548acc3a", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertTrue( all(metric["metric"] in self.resources['AWS::EC2::Instance'] for metric in result))
def testGetInstanceWithDimensionNotFoundEmpty(self, adapterMock): """ Test for Get '/_metrics/cloudwatch/<region-name>/AWS/<namespace>/\ instances/<InstancdId>/Dimenion' with invalid InstancceId response is validated for appropriate headers, body and status Tests scenario when given instance name is not present in ouput from getDimensionsFromRegion """ adapterMock.return_value.describeRegions.return_value = self.regions adapterMock.return_value.describeSupportedMetrics.return_value = ( self.resources) adapterMock.return_value.describeResources.return_value = [{ 'grn': u'aws://us-west-2/Instance/i-548acc3a', 'name': u'Bar', 'resID': u'i-548acc3a' }] response = self.app.get("/us-east-1/AWS/EC2/instances/i-1234567a", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, [])
def testMetricDataForRandomRowID(uid): ''' This tests if the metric data returned by the GET call : _models/<uid>/data has anomaly_score consistent with what is there in the actual database by asserting it against a dao.MetricData.get() call It repeats the process for 5 random sample rows for each uid in the database. Algorithm : - Query the MetricDataHandler GET call for a certain uid - Check if response is OK - Find the last row id for the uid - Select a random row between 1 and last row id - Find the anomaly score for that row id - Assert on the anomaly score ''' response = self.app.get("/%s/data" %uid, headers=self.headers) assertions.assertSuccess(self, response) getAllModelsResult = utils.jsonDecode(response.body) with repository.engineFactory().connect() as conn: lastRowID = repository.getMetric(conn, uid).last_rowid for _ in range(5): randomRowID = randrange(1, lastRowID) with repository.engineFactory().connect() as conn: singleMetricData = repository.getMetricData( conn, uid, rowid=randomRowID).first() metricData = getMetricDataWithRowID(getAllModelsResult['data'], randomRowID) self.assertEqual(metricData[2], singleMetricData.anomaly_score) self.assertEqual(datetime.strptime(metricData[0], '%Y-%m-%d %H:%M:%S'), singleMetricData.timestamp)
def testGetAllModelData(self): """ test GET /data """ getAllMetricDataResponse = self.app.get("/%s/data" % self.uid, headers=self.headers) assertions.assertSuccess(self, getAllMetricDataResponse) getAllMetricDataResult = utils.jsonDecode(getAllMetricDataResponse.body) assertions.assertSuccess(self, getAllMetricDataResponse) self.assertIsInstance(getAllMetricDataResult, dict) self.assertItemsEqual(getAllMetricDataResult.keys(), ["data", "names"]) # Compare http and https response https_response = requests.get( "https://localhost/_models/%s/data" % self.uid, headers=self.headers, verify=False ) httpsData = json.loads(https_response.text) self.assertIsInstance(httpsData, dict) self.assertItemsEqual(httpsData.keys(), ["data", "names"]) self.assertItemsEqual(httpsData["names"], ["timestamp", "value", "anomaly_score", "rowid"]) self.assertIsInstance(httpsData["data"], list) self.assertTrue(all(isinstance(row, list) and len(row) == 4 for row in httpsData["data"])) http_response = requests.get("http://localhost/_models/%s/data" % self.uid, headers=self.headers) httpData = json.loads(http_response.text) self.assertIsInstance(httpData, dict) self.assertItemsEqual(httpData.keys(), ["data", "names"]) self.assertItemsEqual(httpData["names"], ["timestamp", "value", "anomaly_score", "rowid"]) self.assertIsInstance(httpData["data"], list) self.assertTrue(all(isinstance(row, list) and len(row) == 4 for row in httpData["data"]))
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, [])
def testMetricDataQueryParams(uid): ''' This test makes MetricDataHandler GET calls with various params : _models/<uid>/data?from=<>&to=<>&anomaly=<> ''' with repository.engineFactory().connect() as conn: firstMetricData = conn.execute( "SELECT * FROM `metric_data` WHERE `uid`='%s' " "and abs(`anomaly_score` - 0) > 1e-5 " "ORDER BY `timestamp` ASC LIMIT 1" % uid).fetchall() lastMetricData = conn.execute( "SELECT * FROM `metric_data` WHERE `uid`='%s' " "and abs(`anomaly_score` - 0) > 1e-5 " "ORDER BY `timestamp` DESC LIMIT 1" % uid).fetchall() firstTimeStamp = firstMetricData[0].timestamp lastTimeStamp = lastMetricData[0].timestamp anomalyScore = firstMetricData[0].anomaly_score response = self.app.get("/%s/data?from=%s&to=%s&anomaly=%s" % (uid, firstTimeStamp, lastTimeStamp, anomalyScore), headers=self.headers) assertions.assertSuccess(self, response) getAllModelsResult = utils.jsonDecode(response.body) for metricData in getAllModelsResult['data']: self.assertGreaterEqual(metricData[2], anomalyScore) self.assertGreaterEqual(datetime.strptime(metricData[0], '%Y-%m-%d %H:%M:%S'), firstTimeStamp) self.assertLessEqual(datetime.strptime(metricData[0], '%Y-%m-%d %H:%M:%S'), lastTimeStamp)
def testQuery(self, getMetricDataMock, _engineMock): getMetricDataMock.return_value = self.decodeRowTuples( self.metric_data["datalist"]) response = self.app.get("/be9fab-f416-4845-8dab-02d292244112/data?\ from=2013-08-15 21:34:00&to=2013-08-15 21:24:00&anomaly=0.025", headers=self.headers) assertions.assertSuccess(self, response)
def testGetListRegionsEmptyResponse(self, adapterMock): """ Test for Get '/_metrics/cloudwatch/regions' response is validated for appropriate headers, body and status """ adapterMock.return_value.describeRegions.return_value = [] response = self.app.get("/regions", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, {})
def testDefaultGetSpecificSection(self): response = self.app.get("/aws", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertIsInstance(result, dict) for key in set(self.configurable_options["aws"]): if key in settings_api.HIDDEN_SETTINGS["aws"]: self.assertNotIn(key, result) else: self.assertIn(key, result)
def testGetModelDataWithModelUId(self): """ test GET /metricId/data """ getMetricDataResponse = self.app.get("/%s/data" % self.uid, headers=self.headers) assertions.assertSuccess(self, getMetricDataResponse) getMetricDataResult = utils.jsonDecode(getMetricDataResponse.body) self.assertIsInstance(getMetricDataResult, dict) self.assertItemsEqual(getMetricDataResult.keys(), ["data", "names"]) self.assertGreater(len(getMetricDataResult["data"]), 0)
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 testModelsAPIGET(self, getAllMetricsMock, getInstanceStatusHistoryMock, engineFactoryMock, *args): #import pdb; pdb.set_trace() getAllMetricsMock.return_value = [] getInstanceStatusHistoryMock.return_value = [] response = self.app.get("/_models", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, []) self.assertTrue(getAllMetricsMock.called)
def testGETDatasources(self): """ Test for GET for '/_metrics/datasources' response is validated for appropriate headers and body """ response = self.app.get('/datasources', headers=self.headers) assertions.assertSuccess(self, response) self.assertIsInstance(utils.jsonDecode(response.body), list) self.assertSetEqual(set(utils.jsonDecode(response.body)), set(["autostack", "custom", "cloudwatch"]))
def testGetMetricsWithEmptyResponse(self, getDatasourcesMock): """ Test get "/datasources" response is validated for appropriate headers, body and status """ getDatasourcesMock.return_value = tuple() response = self.app.get("/datasources", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, [])
def testMetricDataHandlerGetMetricDataWIthAnomaly(self, getMetricDataMock, _engineMock): getMetricDataMock.return_value = self.decodeRowTuples( self.metric_data['withanomaly']) response = self.app.get( "/be9fab-f416-4845-8dab-02d292244112/data?anomaly=0.01", headers=self.headers) assertions.assertSuccess(self, response) result = jsonDecode(response.body) self.assertEqual([row[1:] for row in self.metric_data['withanomaly']], result["data"])
def testGETListRegions(self): """ Test for Get '/_metrics/cloudwatch/regions' response is validated for appropriate headers, body and status response is validated against json for supported regions """ response = self.app.get("/regions", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertIsInstance(result, dict) self.assertEqual(json.loads(response.body), self.regions)
def testGETListInstancesForRegion(self): """ Test for Get '/_metrics/cloudwatch/<region-name>/AWS/<namespace>/instances' response is validated for appropriate headers, body and status response is validated against response """ response = self.app.get("/us-west-2/AWS/EC2", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertIsInstance(result, list)
def testMetricDataHandlerGetMetricDataWithToTimestamp( self, getMetricDataMock, _engineMock): getMetricDataMock.return_value = self.decodeRowTuples( self.metric_data["withto"]) response = self.app.get( "/be9fab-f416-4845-8dab-02d292244112/data?to=2013-08-15 21:28:00", headers=self.headers) assertions.assertSuccess(self, response) result = jsonDecode(response.body) self.assertEqual([row[1:] for row in self.metric_data['withto']], result["data"])
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 testGETSpecificNamespace(self): """ Test for Get '/_metrics/cloudwatch/AWS/<namespace>' response is validated for appropriate headers, body and status response is validated against available metrics for each namespaces supported """ for namespace in self._supportedAWSNamespaces(): response = self.app.get("/%s" % namespace, headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertIsInstance(result, dict)
def testDefaultGetList(self): response = self.app.get("", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertIsInstance(result, dict) for config in self.configurable_options: self.assertTrue(result.has_key(config)) for key in self.configurable_options[config]: if key in settings_api.HIDDEN_SETTINGS[config]: self.assertNotIn(key, result[config]) else: self.assertIn(key, result[config])
def testGetMetricsWithNonEmptyResponse(self, getDatasourcesMock): """ Test get "/datasources", with non empty response response is validated for appropriate headers, body and status """ getDatasourcesMock.return_value = ("autostack", "cloudwatch", "custom") response = self.app.get("/datasources", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, ["autostack", "cloudwatch", "custom"])
def testGetListNamespaceNoRegions(self, adapterMock): """ Test for Get '/_metrics/cloudwatch/namespaces' response is validated for appropriate headers, body and status """ adapterMock.return_value.describeRegions.return_value = [] response = self.app.get("/namespaces", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) # Added Autostacks namespaces to this list for now, to maintain API # backwards-compatibility during adapter refactor self.assertEqual(result, {'Autostacks': {'metrics': ['InstanceCount']}})
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 testGETNamespaces(self): """ Test for Get '/_metrics/cloudwatch/namespaces' response is validated for appropriate headers, body and status response is validated against known namespaces """ response = self.app.get("/namespaces", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertIsInstance(result, dict) supportedNamespaces = self._supportedAWSNamespaces() | set(["Autostacks"]) self.assertEqual(supportedNamespaces, set(result.keys()))
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)
def testGetListNamespaceNoRegions(self, adapterMock): """ Test for Get '/_metrics/cloudwatch/namespaces' response is validated for appropriate headers, body and status """ adapterMock.return_value.describeRegions.return_value = [] response = self.app.get("/namespaces", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) # Added Autostacks namespaces to this list for now, to maintain API # backwards-compatibility during adapter refactor self.assertEqual(result, {'Autostacks': { 'metrics': ['InstanceCount'] }})
def testGetMetricValidInputEmptyResponse(self, adapterMock): """ Test for Get '/_metrics/cloudwatch/<region-name>/AWS/<namespace>/metricName' response is validated for appropriate headers, body and status """ adapterMock.return_value.describeRegions.return_value = self.regions adapterMock.return_value.describeSupportedMetrics.return_value = ( self.resources) adapterMock.return_value.describeResources.return_value = [] response = self.app.get("/us-east-1/AWS/EC2/CPUUtilization", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, [])
def testGETInstanceForInvalidInstance(self): """ Test for Get '/_metrics/cloudwatch/<region-name>/AWS/<namespace>/instances/<InstancdId>' with invalid InstancceId response is validated for appropriate headers, body and status Expect a 200 OK even when attempting to GET from an invalid instance, this saves the overhead of asking AWS if we're dealing with a valid instance every GET. We expect the CLI user to know what instance ID he/she is looking for. """ response = self.app.get("/us-west-2/AWS/EC2/instances/abcd1234", status="*", headers=self.headers) assertions.assertSuccess(self, response)
def testGetCloudwatch(self, adapterMock): """ Test get "/cloudwatch", with non empty response response is validated for appropriate headers, body and status """ adapterMock.return_value.describeSupportedMetrics = Mock( spec_set=_CloudwatchDatasourceAdapter.describeSupportedMetrics, return_value = {}) adapterMock.return_value.describeRegions = Mock( spec_set=_CloudwatchDatasourceAdapter.describeRegions, return_value = []) response = self.app.get("/cloudwatch", headers=self.headers) assertions.assertSuccess(self, response) result = app_utils.jsonDecode(response.body) self.assertEqual(result, {'regions': {}, 'namespaces': {}})
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)
def testMetricDataAnomalyAsQueryParams(uid): ''' This test makes MetricDataHandler GET calls with anomaly param : _models/<uid>/data?anomaly=<> ''' queryString = ("SELECT * FROM metric_data WHERE uid='%s' " " and abs(anomaly_score - 0) > 1e-5 LIMIT 1") % uid with repository.engineFactory().connect() as conn: sampleMetricData = conn.execute(queryString).first() anomalyScore = sampleMetricData.anomaly_score response = self.app.get("/%s/data?anomaly=%s" % (uid, anomalyScore), headers=self.headers) assertions.assertSuccess(self, response) getAllModelsResult = utils.jsonDecode(response.body) for metricData in getAllModelsResult['data']: self.assertGreaterEqual(metricData[2], anomalyScore)