class StackdriverMetricsServiceTest(unittest.TestCase): def setUp(self): project = 'test-project' instance = 'test-instance' options = { 'project': project, 'zone': 'us-central1-f', 'instance_id': instance, 'fix_stackdriver_labels_unsafe': True } self.mockStub = mock.create_autospec(['projects']) self.mockProjects = mock.create_autospec( ['metricDescriptors', 'timeSeries']) self.mockMetricDescriptors = mock.create_autospec( ['create', 'delete', 'get']) self.mockTimeSeries = mock.create_autospec(['create']) self.mockStub.projects = Mock(return_value=self.mockProjects) self.mockProjects.metricDescriptors = Mock( return_value=self.mockMetricDescriptors) self.mockProjects.timeSeries = Mock(return_value=self.mockTimeSeries) # pylint: disable=invalid-name self.mockCreateTimeSeries = Mock(spec=['execute']) self.mockCreateDescriptor = Mock(spec=['execute']) self.mockGetDescriptor = Mock(spec=['execute']) self.mockDeleteDescriptor = Mock(spec=['execute']) self.mockMetricDescriptors.create = Mock( return_value=self.mockCreateDescriptor) self.mockMetricDescriptors.delete = Mock( return_value=self.mockDeleteDescriptor) self.mockMetricDescriptors.get = Mock( return_value=self.mockGetDescriptor) self.mockTimeSeries.create = Mock( return_value=self.mockCreateTimeSeries) self.service = StackdriverMetricsService(lambda: self.mockStub, options) def test_find_problematic_elements(self): content = """{ "error": { "code": 400, "message": "Field timeSeries[1].metric.labels[2] had an invalid value of \\"application\\": Unrecognized metric label.", "errors": [ { "message": "Field timeSeries[1].metric.labels[2] had an invalid value of \\"application\\": Unrecognized metric label.", "domain": "global", "reason": "badRequest" } ], "status": "INVALID_ARGUMENT" } }""" Error = collections.namedtuple('Error', ['content']) error = Error(content) all_ts = [ { 'metric': { 'type': 'typeA', 'name': 'nameA' } }, { 'metric': { 'type': 'FOUND-TYPE', 'name': 'nameFound' } }, { 'metric': { 'type': 'typeC', 'name': 'nameC' } }, ] found = self.service.find_problematic_elements(error, all_ts) self.assertEquals([(self.service.add_label_and_retry, 'application', 'FOUND-TYPE', all_ts[1])], found) def test_add_label_and_retry_no_descriptor(self): timeseries = 'OPAQUE' status = ResponseStatus(404, 'Not Found') self.mockMetricDescriptors.get.side_effect = HttpError( status, 'Not Found') self.service.add_label_and_retry('NewLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(1, self.mockMetricDescriptors.get.call_count) self.assertEquals(0, self.mockMetricDescriptors.delete.call_count) self.assertEquals(0, self.mockMetricDescriptors.create.call_count) self.assertEquals(0, self.mockTimeSeries.create.call_count) def test_add_label_already_present(self): timeseries = 'OPAQUE' original_descriptor = { 'type': 'TYPE', 'labels': [{ 'key': 'TestLabel' }] } self.mockGetDescriptor.execute.side_effect = [original_descriptor] self.service.add_label_and_retry('TestLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(1, self.mockMetricDescriptors.get.call_count) self.assertEquals(0, self.mockMetricDescriptors.delete.call_count) self.assertEquals(0, self.mockMetricDescriptors.create.call_count) self.assertEquals(1, self.mockTimeSeries.create.call_count) def test_add_label_and_retry_cannot_delete(self): timeseries = 'OPAQUE' original_descriptor = { 'labels': [{ 'key': 'TestLabel' }], 'type': 'TYPE' } new_descriptor = dict(copy.deepcopy(original_descriptor)) new_descriptor['labels'].append({'key': 'NewLabel'}) self.mockGetDescriptor.execute.side_effect = [ original_descriptor, new_descriptor ] self.mockDeleteDescriptor.execute.side_effect = HttpError( ResponseStatus(404, 'Not Found'), 'Not Found') self.mockCreateDescriptor.execute.side_effect = [new_descriptor] self.service.add_label_and_retry('NewLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(2, self.mockMetricDescriptors.get.call_count) self.assertEquals(1, self.mockMetricDescriptors.delete.call_count) self.assertEquals(1, self.mockMetricDescriptors.create.call_count) self.assertEquals(1, self.mockTimeSeries.create.call_count) def test_add_label_and_retry_cannot_create(self): timeseries = 'OPAQUE' original_descriptor = { 'labels': [{ 'key': 'TestLabel' }], 'type': 'TYPE' } self.mockGetDescriptor.execute.side_effect = [original_descriptor] self.mockDeleteDescriptor.execute.side_effect = ResponseStatus( 200, 'ok') self.mockCreateDescriptor.execute.side_effect = HttpError( ResponseStatus(404, 'Not Found'), 'Not Found') self.service.add_label_and_retry('NewLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(1, self.mockMetricDescriptors.get.call_count) self.assertEquals(1, self.mockMetricDescriptors.delete.call_count) self.assertEquals(1, self.mockMetricDescriptors.create.call_count) self.assertEquals(0, self.mockTimeSeries.create.call_count)
class StackdriverMetricsServiceTest(unittest.TestCase): def setUp(self): project = 'test-project' instance = 'test-instance' options = {'project': project, 'zone': 'us-central1-f', 'instance_id': instance, 'fix_stackdriver_labels_unsafe': True} self.mockStub = mock.create_autospec(['projects']) self.mockProjects = mock.create_autospec( ['metricDescriptors', 'timeSeries']) self.mockMetricDescriptors = mock.create_autospec( ['create', 'delete', 'get']) self.mockTimeSeries = mock.create_autospec(['create']) self.mockStub.projects = Mock(return_value=self.mockProjects) self.mockProjects.metricDescriptors = Mock( return_value=self.mockMetricDescriptors) self.mockProjects.timeSeries = Mock(return_value=self.mockTimeSeries) # pylint: disable=invalid-name self.mockCreateTimeSeries = Mock(spec=['execute']) self.mockCreateDescriptor = Mock(spec=['execute']) self.mockGetDescriptor = Mock(spec=['execute']) self.mockDeleteDescriptor = Mock(spec=['execute']) self.mockMetricDescriptors.create = Mock( return_value=self.mockCreateDescriptor) self.mockMetricDescriptors.delete = Mock( return_value=self.mockDeleteDescriptor) self.mockMetricDescriptors.get = Mock( return_value=self.mockGetDescriptor) self.mockTimeSeries.create = Mock(return_value=self.mockCreateTimeSeries) self.service = StackdriverMetricsService(lambda: self.mockStub, options) def test_find_problematic_elements(self): content = """{ "error": { "code": 400, "message": "Field timeSeries[1].metric.labels[2] had an invalid value of \\"application\\": Unrecognized metric label.", "errors": [ { "message": "Field timeSeries[1].metric.labels[2] had an invalid value of \\"application\\": Unrecognized metric label.", "domain": "global", "reason": "badRequest" } ], "status": "INVALID_ARGUMENT" } }""" Error = collections.namedtuple('Error', ['content']) error = Error(content) all_ts = [ {'metric': {'type': 'typeA', 'name': 'nameA'}}, {'metric': {'type': 'FOUND-TYPE', 'name': 'nameFound'}}, {'metric': {'type': 'typeC', 'name': 'nameC'}}, ] found = self.service.find_problematic_elements(error, all_ts) self.assertEquals([(self.service.add_label_and_retry, 'application', 'FOUND-TYPE', all_ts[1])], found) def test_add_label_and_retry_no_descriptor(self): timeseries = 'OPAQUE' status = ResponseStatus(404, 'Not Found') self.mockMetricDescriptors.get.side_effect = HttpError( status, 'Not Found') self.service.add_label_and_retry('NewLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(1, self.mockMetricDescriptors.get.call_count) self.assertEquals(0, self.mockMetricDescriptors.delete.call_count) self.assertEquals(0, self.mockMetricDescriptors.create.call_count) self.assertEquals(0, self.mockTimeSeries.create.call_count) def test_add_label_already_present(self): timeseries = 'OPAQUE' original_descriptor = {'type': 'TYPE', 'labels': [{'key': 'TestLabel'}]} self.mockGetDescriptor.execute.side_effect = [original_descriptor] self.service.add_label_and_retry('TestLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(1, self.mockMetricDescriptors.get.call_count) self.assertEquals(0, self.mockMetricDescriptors.delete.call_count) self.assertEquals(0, self.mockMetricDescriptors.create.call_count) self.assertEquals(1, self.mockTimeSeries.create.call_count) def test_add_label_and_retry_cannot_delete(self): timeseries = 'OPAQUE' original_descriptor = {'labels': [{'key': 'TestLabel'}], 'type': 'TYPE' } new_descriptor = dict(copy.deepcopy(original_descriptor)) new_descriptor['labels'].append({'key': 'NewLabel'}) self.mockGetDescriptor.execute.side_effect = [ original_descriptor, new_descriptor] self.mockDeleteDescriptor.execute.side_effect = HttpError( ResponseStatus(404, 'Not Found'), 'Not Found') self.mockCreateDescriptor.execute.side_effect = [new_descriptor] self.service.add_label_and_retry('NewLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(2, self.mockMetricDescriptors.get.call_count) self.assertEquals(1, self.mockMetricDescriptors.delete.call_count) self.assertEquals(1, self.mockMetricDescriptors.create.call_count) self.assertEquals(1, self.mockTimeSeries.create.call_count) def test_add_label_and_retry_cannot_create(self): timeseries = 'OPAQUE' original_descriptor = {'labels': [{'key': 'TestLabel'}], 'type': 'TYPE' } self.mockGetDescriptor.execute.side_effect = [original_descriptor] self.mockDeleteDescriptor.execute.side_effect = ResponseStatus( 200, 'ok') self.mockCreateDescriptor.execute.side_effect = HttpError( ResponseStatus(404, 'Not Found'), 'Not Found') self.service.add_label_and_retry('NewLabel', 'ExistingType', timeseries) self.assertEquals(0, self.mockStub.projects.list.call_count) self.assertEquals(1, self.mockMetricDescriptors.get.call_count) self.assertEquals(1, self.mockMetricDescriptors.delete.call_count) self.assertEquals(1, self.mockMetricDescriptors.create.call_count) self.assertEquals(0, self.mockTimeSeries.create.call_count)