Home | History | Annotate | Download | only in tests
      1 // Copyright (c) 2009, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 //
     30 // BreakpadFramework_Test.mm
     31 // Test case file for Breakpad.h/mm.
     32 //
     33 
     34 #import "GTMSenTestCase.h"
     35 #import "Breakpad.h"
     36 
     37 #include <mach/mach.h>
     38 
     39 @interface BreakpadFramework_Test : GTMTestCase {
     40  @private
     41   int last_exception_code_;
     42   int last_exception_type_;
     43   mach_port_t last_exception_thread_;
     44   // We're not using Obj-C BOOL because we need to interop with
     45   // Breakpad's callback.
     46   bool shouldHandleException_;
     47 }
     48 
     49 // This method is used by a callback used by test cases to determine
     50 // whether to return true or false to Breakpad when handling an
     51 // exception.
     52 - (bool)shouldHandleException;
     53 // This method returns a minimal dictionary that has what
     54 // Breakpad needs to initialize.
     55 - (NSMutableDictionary *)breakpadInitializationDictionary;
     56 // This method is used by the exception handling callback
     57 // to communicate to test cases the properites of the last
     58 // exception.
     59 - (void)setLastExceptionType:(int)type andCode:(int)code
     60                    andThread:(mach_port_t)thread;
     61 @end
     62 
     63 // Callback for Breakpad exceptions
     64 bool myBreakpadCallback(int exception_type,
     65                         int exception_code,
     66                         mach_port_t crashing_thread,
     67                         void *context);
     68 
     69 bool myBreakpadCallback(int exception_type,
     70                         int exception_code,
     71                         mach_port_t crashing_thread,
     72                         void *context) {
     73   BreakpadFramework_Test *testCaseClass =
     74     (BreakpadFramework_Test *)context;
     75   [testCaseClass setLastExceptionType:exception_type
     76                               andCode:exception_code
     77                             andThread:crashing_thread];
     78   bool shouldHandleException =
     79     [testCaseClass shouldHandleException];
     80   NSLog(@"Callback returning %d", shouldHandleException);
     81   return shouldHandleException;
     82 }
     83 const int kNoLastExceptionCode = -1;
     84 const int kNoLastExceptionType = -1;
     85 const mach_port_t kNoLastExceptionThread = MACH_PORT_NULL;
     86 
     87 @implementation BreakpadFramework_Test
     88 - (void) initializeExceptionStateVariables {
     89   last_exception_code_ = kNoLastExceptionCode;
     90   last_exception_type_ = kNoLastExceptionType;
     91   last_exception_thread_ = kNoLastExceptionThread;
     92 }
     93 
     94 - (NSMutableDictionary *)breakpadInitializationDictionary {
     95   NSMutableDictionary *breakpadParams =
     96     [NSMutableDictionary dictionaryWithCapacity:3];
     97 
     98   [breakpadParams setObject:@"UnitTests" forKey:@BREAKPAD_PRODUCT];
     99   [breakpadParams setObject:@"1.0" forKey:@BREAKPAD_VERSION];
    100   [breakpadParams setObject:@"http://staging" forKey:@BREAKPAD_URL];
    101   return breakpadParams;
    102 }
    103 
    104 - (bool)shouldHandleException {
    105   return shouldHandleException_;
    106 }
    107 
    108 - (void)setLastExceptionType:(int)type 
    109 		     andCode:(int)code
    110                    andThread:(mach_port_t)thread {
    111   last_exception_type_ = type;
    112   last_exception_code_ = code;
    113   last_exception_thread_ = thread;
    114 }
    115 
    116 // Test that the parameters mark required actually enable Breakpad to
    117 // be initialized.
    118 - (void)testBreakpadInstantiationWithRequiredParameters {
    119   BreakpadRef b = BreakpadCreate([self breakpadInitializationDictionary]);
    120   STAssertNotNULL(b, @"BreakpadCreate failed with required parameters");
    121   BreakpadRelease(b);
    122 }
    123 
    124 // Test that Breakpad fails to initialize cleanly when required
    125 // parameters are not present.
    126 - (void)testBreakpadInstantiationWithoutRequiredParameters {
    127   NSMutableDictionary *breakpadDictionary =
    128     [self breakpadInitializationDictionary];
    129 
    130   // Skip setting version, so that BreakpadCreate fails.
    131   [breakpadDictionary removeObjectForKey:@BREAKPAD_VERSION];
    132   BreakpadRef b = BreakpadCreate(breakpadDictionary);
    133   STAssertNULL(b, @"BreakpadCreate did not fail when missing a required"
    134                " parameter!");
    135 
    136   breakpadDictionary = [self breakpadInitializationDictionary];
    137   // Now test with no product
    138   [breakpadDictionary removeObjectForKey:@BREAKPAD_PRODUCT];
    139   b = BreakpadCreate(breakpadDictionary);
    140   STAssertNULL(b, @"BreakpadCreate did not fail when missing a required"
    141                " parameter!");
    142 
    143   breakpadDictionary = [self breakpadInitializationDictionary];
    144   // Now test with no URL
    145   [breakpadDictionary removeObjectForKey:@BREAKPAD_URL];
    146   b = BreakpadCreate(breakpadDictionary);
    147   STAssertNULL(b, @"BreakpadCreate did not fail when missing a required"
    148                " parameter!");
    149   BreakpadRelease(b);
    150 }
    151 
    152 // Test to ensure that when we call BreakpadAddUploadParameter,
    153 // it's added to the dictionary correctly(this test depends on
    154 // some internal details of Breakpad, namely, the special prefix
    155 // that it uses to figure out which key/value pairs to upload).
    156 - (void)testAddingBreakpadServerVariable {
    157   NSMutableDictionary *breakpadDictionary =
    158     [self breakpadInitializationDictionary];
    159 
    160   BreakpadRef b = BreakpadCreate(breakpadDictionary);
    161   STAssertNotNULL(b, @"BreakpadCreate failed with valid dictionary!");
    162 
    163   BreakpadAddUploadParameter(b,
    164                              @"key",
    165                              @"value");
    166 
    167   // Test that it did not add the key/value directly, e.g. without
    168   // prepending the key with the prefix.
    169   STAssertNil(BreakpadKeyValue(b, @"key"),
    170               @"AddUploadParameter added key directly to dictionary"
    171               " instead of prepending it!");
    172 
    173   NSString *prependedKeyname =
    174     [@BREAKPAD_SERVER_PARAMETER_PREFIX stringByAppendingString:@"key"];
    175     
    176   STAssertEqualStrings(BreakpadKeyValue(b, prependedKeyname),
    177                        @"value",
    178                        @"Calling BreakpadAddUploadParameter did not prepend "
    179                        "key name");
    180   BreakpadRelease(b);
    181 }
    182 
    183 // Test that when we do on-demand minidump generation,
    184 // the exception code/type/thread are set properly.
    185 - (void)testFilterCallbackReturnsFalse {
    186   NSMutableDictionary *breakpadDictionary =
    187     [self breakpadInitializationDictionary];
    188 
    189   BreakpadRef b = BreakpadCreate(breakpadDictionary);
    190   STAssertNotNULL(b, @"BreakpadCreate failed with valid dictionary!");
    191   BreakpadSetFilterCallback(b, &myBreakpadCallback, self);
    192 
    193   // This causes the callback to return false, meaning
    194   // Breakpad won't take the exception
    195   shouldHandleException_ = false;
    196 
    197   [self initializeExceptionStateVariables];
    198   STAssertEquals(last_exception_type_, kNoLastExceptionType,
    199                  @"Last exception type not initialized correctly.");
    200   STAssertEquals(last_exception_code_, kNoLastExceptionCode,
    201                  @"Last exception code not initialized correctly.");
    202   STAssertEquals(last_exception_thread_, kNoLastExceptionThread,
    203                  @"Last exception thread is not initialized correctly.");
    204 
    205   // Cause Breakpad's exception handler to be invoked.
    206   BreakpadGenerateAndSendReport(b);
    207 
    208   STAssertEquals(last_exception_type_, 0,
    209                  @"Last exception type is not 0 for on demand");
    210   STAssertEquals(last_exception_code_, 0,
    211                  @"Last exception code is not 0 for on demand");
    212   STAssertEquals(last_exception_thread_, mach_thread_self(),
    213                  @"Last exception thread is not mach_thread_self() "
    214                  "for on demand");
    215 }
    216 
    217 @end
    218