Skip to content

Commit

Permalink
bug 1066058; add Support Reason API crashstorage type
Browse files Browse the repository at this point in the history
  • Loading branch information
phrawzty committed Sep 19, 2014
1 parent 3b864a8 commit f7d4888
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 6 deletions.
52 changes: 50 additions & 2 deletions socorro/external/ceph/crashstorage.py
Expand Up @@ -323,7 +323,6 @@ def _get_or_create_bucket(self, conn, bucket_name):
)
return self._bucket_cache[bucket_name]


#--------------------------------------------------------------------------
def _submit_to_boto_s3(self, crash_id, name_of_thing, thing):
"""submit something to ceph.
Expand Down Expand Up @@ -355,7 +354,7 @@ def _submit_to_boto_s3(self, crash_id, name_of_thing, thing):

#--------------------------------------------------------------------------
def _fetch_from_boto_s3(self, crash_id, name_of_thing):
"""submit something to ceph.
"""retreive something from ceph.
"""
conn = self._connect()

Expand Down Expand Up @@ -453,3 +452,52 @@ def is_operational_exception(self, msg):
def force_reconnect(self):
del self.connection
self._bucket_cache = {}


#==============================================================================
class SupportReasonAPIStorage(BotoS3CrashStorage):
"""Used to send a small subset of processed crash data the Support Reason
API back-end. This is effectively a highly lossy S3 storage mechanism.
bug 1066058
"""

#--------------------------------------------------------------------------
@staticmethod
def _create_bucket_name_for_crash_id(crash_id):
"""The name of this bucket is not dynamic.
"""
return 'mozilla-support-reason'

#--------------------------------------------------------------------------
@staticmethod
def _do_save_processed(self, processed_crash):
"""Replaces the function of the same name in the parent class.
"""
crash_id = processed_crash['uuid']
reason = processed_crash['classifications']['support']['classification']

try:
# Set up the data chunk to be passed to S3.
content = {
# Unfortunate mixing of uuid and crash_id terminology. :(
'uuid': crash_id,
'reasons': [reason]
}
except KeyError:
# No classifier was found for this crash.
return

# Submit the data chunk to S3.
self._submit_to_boto_s3(
crash_id,
'support_reason',
json.dumps(content)
)

#--------------------------------------------------------------------------
def save_raw_crash(self, raw_crash, dumps, crash_id):
"""There are no scenarios in which the raw crash could possibly be of
interest to the Support Reason API, therefore this function does
nothing; however it is necessary for compatibility purposes.
"""
pass
75 changes: 71 additions & 4 deletions socorro/unittest/external/ceph/test_crashstorage.py
Expand Up @@ -9,7 +9,10 @@

from socorro.lib.util import DotDict
from socorro.external.crashstorage_base import Redactor
from socorro.external.ceph.crashstorage import BotoS3CrashStorage
from socorro.external.ceph.crashstorage import (
BotoS3CrashStorage,
SupportReasonAPIStorage
)
from socorro.database.transaction_executor import (
TransactionExecutor,
TransactionExecutorWithLimitedBackoff,
Expand Down Expand Up @@ -85,7 +88,11 @@ def _fake_unredacted_processed_crash_as_string(self):
s = json.dumps(d)
return s

def setup_mocked_s3_storage(self, executor=TransactionExecutor):
def setup_mocked_s3_storage(
self,
executor=TransactionExecutor,
storage_class='BotoS3CrashStorage'):

config = DotDict({
'source': {
'dump_field': 'dump'
Expand All @@ -104,7 +111,10 @@ def setup_mocked_s3_storage(self, executor=TransactionExecutor):
'/i/am/hiding/junk/files/here',
'dump_file_suffix': '.dump',
})
s3 = BotoS3CrashStorage(config)
if storage_class == 'BotoS3CrashStorage':
s3 = BotoS3CrashStorage(config)
elif storage_class == 'SupportReasonAPIStorage':
s3 = SupportReasonAPIStorage(config)
s3._connect_to_endpoint = mock.Mock()
s3._mocked_connection = s3._connect_to_endpoint.return_value
s3._calling_format = mock.Mock()
Expand Down Expand Up @@ -352,6 +362,64 @@ def test_save_processed(self):
any_order=True,
)

def test_save_processed_support_reason(self):
boto_s3_store = self.setup_mocked_s3_storage(
storage_class='SupportReasonAPIStorage'
)

# the tested call
report = {
'uuid': '3c61f81e-ea2b-4d24-a3ce-6bb9d2140915',
'classifications': {
'support': {
'classification': 'SIGSEGV'
}
}
}
boto_s3_store.save_processed(report)

# what should have happened internally
self.assertEqual(boto_s3_store._calling_format.call_count, 1)
boto_s3_store._calling_format.assert_called_with()

self.assertEqual(boto_s3_store._connect_to_endpoint.call_count, 1)
self.assert_s3_connection_parameters(boto_s3_store)

self.assertEqual(
boto_s3_store._mocked_connection.get_bucket.call_count,
1
)
boto_s3_store._mocked_connection.get_bucket.assert_called_with(
'mozilla-support-reason'
)

bucket_mock = boto_s3_store._mocked_connection.get_bucket \
.return_value
self.assertEqual(bucket_mock.new_key.call_count, 1)
bucket_mock.new_key.assert_has_calls(
[
mock.call(
'3c61f81e-ea2b-4d24-a3ce-6bb9d2140915.support_reason'
),
],
)

storage_key_mock = bucket_mock.new_key.return_value
self.assertEqual(
storage_key_mock.set_contents_from_string.call_count,
1
)

storage_key_mock.set_contents_from_string.assert_has_calls(
[
mock.call(
'{"reasons": ["SIGSEGV"],'
' "uuid": "3c61f81e-ea2b-4d24-a3ce-6bb9d2140915"}'
),
],
any_order=True,
)

def test_save_raw_and_processed(self):
boto_s3_store = self.setup_mocked_s3_storage()

Expand Down Expand Up @@ -551,7 +619,6 @@ def test_get_raw_dump_upload_file_minidump(self):

self.assertEqual(result, 'this is a raw dump')


def test_get_raw_dump_empty_string(self):
"""test fetching the raw dump, naming it with empty string"""
# setup some internal behaviors and fake outs
Expand Down

0 comments on commit f7d4888

Please sign in to comment.