SessionProvider::mergeMetadata: Log additional data
authorBryan Davis <bd808@wikimedia.org>
Thu, 11 Feb 2016 16:55:37 +0000 (09:55 -0700)
committerBryan Davis <bd808@wikimedia.org>
Thu, 11 Feb 2016 21:21:14 +0000 (14:21 -0700)
Add the data values and types to the exception raised when mismatched
session data is processed. This is done by passing the old and new
values on via a new MetadataMergeException class. The attached data is
added to the debug logging context info when caught.

Change-Id: If8a7174399289bc284ca1b36052ba515c8857c50

autoload.php
includes/session/MetadataMergeException.php [new file with mode: 0644]
includes/session/SessionManager.php
includes/session/SessionProvider.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/session/SessionProviderTest.php

index d6e4077..ab6c5e0 100644 (file)
@@ -796,6 +796,7 @@ $wgAutoloadLocalClasses = array(
        'MediaWiki\\Session\\BotPasswordSessionProvider' => __DIR__ . '/includes/session/BotPasswordSessionProvider.php',
        'MediaWiki\\Session\\CookieSessionProvider' => __DIR__ . '/includes/session/CookieSessionProvider.php',
        'MediaWiki\\Session\\ImmutableSessionProviderWithCookie' => __DIR__ . '/includes/session/ImmutableSessionProviderWithCookie.php',
+       'MediaWiki\\Session\\MetadataMergeException' => __DIR__ . '/includes/session/MetadataMergeException.php',
        'MediaWiki\\Session\\PHPSessionHandler' => __DIR__ . '/includes/session/PHPSessionHandler.php',
        'MediaWiki\\Session\\Session' => __DIR__ . '/includes/session/Session.php',
        'MediaWiki\\Session\\SessionBackend' => __DIR__ . '/includes/session/SessionBackend.php',
diff --git a/includes/session/MetadataMergeException.php b/includes/session/MetadataMergeException.php
new file mode 100644 (file)
index 0000000..9f42c27
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/**
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Session
+ */
+
+namespace MediaWiki\Session;
+
+use UnexpectedValueException;
+
+/**
+ * Subclass of UnexpectedValueException that can be annotated with additional
+ * data for debug logging.
+ *
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2016 Bryan Davis and Wikimedia Foundation.
+ * @since 1.27
+ */
+class MetadataMergeException extends UnexpectedValueException {
+       /** @var array $context */
+       protected $context;
+
+       /**
+        * @param string $message
+        * @param int $code
+        * @param Exception|null $previous
+        * @param array $context Additional context data
+        */
+       public function __construct(
+               $message = '',
+               $code = 0,
+               Exception $previous = null,
+               array $context = []
+       ) {
+               parent::__construct( $message, $code, $previous );
+               $this->context = $context;
+       }
+
+       /**
+        * Get context data.
+        * @return array
+        */
+       public function getContext() {
+               return $this->context;
+       }
+
+       /**
+        * Set context data.
+        * @param array $context
+        */
+       public function setContext( array $context ) {
+               $this->context = $context;
+       }
+}
index 83c30ab..6e4f99c 100644 (file)
@@ -744,13 +744,14 @@ final class SessionManager implements SessionManagerInterface {
                                                if ( $newProviderMetadata !== $providerMetadata ) {
                                                        $newParams['metadata'] = $newProviderMetadata;
                                                }
-                                       } catch ( \UnexpectedValueException $ex ) {
+                                       } catch ( MetadataMergeException $ex ) {
                                                $this->logger->warning(
                                                        'Session "{session}": Metadata merge failed: {exception}',
                                                        array(
                                                                'session' => $info,
                                                                'exception' => $ex,
-                                               ) );
+                                                       ) + $ex->getContext()
+                                               );
                                                return false;
                                        }
                                }
index 0fd3a71..db6294d 100644 (file)
@@ -186,12 +186,17 @@ abstract class SessionProvider implements SessionProviderInterface, LoggerAwareI
         * @param array $savedMetadata Saved provider metadata
         * @param array $providedMetadata Provided provider metadata
         * @return array Resulting metadata
-        * @throws \UnexpectedValueException If the metadata cannot be merged
+        * @throws MetadataMergeException If the metadata cannot be merged
         */
        public function mergeMetadata( array $savedMetadata, array $providedMetadata ) {
                foreach ( $providedMetadata as $k => $v ) {
                        if ( array_key_exists( $k, $savedMetadata ) && $savedMetadata[$k] !== $v ) {
-                               throw new \UnexpectedValueException( "Key \"$k\" changed" );
+                               $e = new MetadataMergeException( "Key \"$k\" changed" );
+                               $e->setContext( [
+                                       'old_value' => $savedMetadata[$k],
+                                       'new_value' => $v,
+                               ] );
+                               throw $e;
                        }
                }
                return $providedMetadata;
index 16beb72..94bf184 100644 (file)
@@ -1112,7 +1112,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                $provider->expects( $this->any() )->method( 'mergeMetadata' )
                        ->will( $this->returnCallback( function ( $a, $b ) {
                                if ( $b === array( 'Throw' ) ) {
-                                       throw new \UnexpectedValueException( 'no merge!' );
+                                       throw new MetadataMergeException( 'no merge!' );
                                }
                                return array( 'Merged' );
                        } ) );
index d7aebcd..7d9004a 100644 (file)
@@ -89,8 +89,10 @@ class SessionProviderTest extends MediaWikiTestCase {
                                array( 'bar' => 2, 'baz' => '3' )
                        );
                        $this->fail( 'Expected exception not thrown' );
-               } catch ( \UnexpectedValueException $ex ) {
+               } catch ( MetadataMergeException $ex ) {
                        $this->assertSame( 'Key "baz" changed', $ex->getMessage() );
+                       $this->assertSame(
+                               [ 'old_value' => 3, 'new_value' => '3' ], $ex->getContext() );
                }
 
                $res = $provider->mergeMetadata(