From a1132796a0c7d9050bf761e1a04654796b7d5709 Mon Sep 17 00:00:00 2001
From: Greg Dunlap <gdd@heyrocker.com>
Date: Tue, 1 Mar 2011 00:10:40 +0100
Subject: [PATCH 1/2] Issue #1072844 by ygerasimov: XMLRPC server. All possible calls get listed in system.listMethods

---
 tests/functional/ServicesXMLRPCTests.test          |  201 ++++++++++++++++++++
 .../services_test_resource.info                    |    9 +
 .../services_test_resource.module                  |   64 ++++++
 3 files changed, 274 insertions(+), 0 deletions(-)
 create mode 100644 tests/functional/ServicesXMLRPCTests.test
 create mode 100644 tests/services_test_resource/services_test_resource.info
 create mode 100644 tests/services_test_resource/services_test_resource.module

diff --git a/tests/functional/ServicesXMLRPCTests.test b/tests/functional/ServicesXMLRPCTests.test
new file mode 100644
index 0000000..c49d733
--- /dev/null
+++ b/tests/functional/ServicesXMLRPCTests.test
@@ -0,0 +1,201 @@
+<?php
+
+class ServicesXMLRPCTestCase extends DrupalWebTestCase {
+  // Endpoint details.
+  protected $endpoint = NULL;
+  // Session ID.
+  protected $sessid = NULL;
+  // Session name.
+  protected $session_name = NULL;
+
+  /**
+   * Implements getInfo().
+   */
+  public static function getInfo() {
+   return array(
+     'name'        => t('XMLRPC Server'),
+     'description' => t('Test XMLRPC server.'),
+     'group'       => t('Services'),
+   );
+  }
+
+  public function setUp() {
+    parent::setUp('ctools', 'services', 'xmlrpc_server', 'services_test_resource');
+    // Set up endpoint.
+    $this->endpoint =  $this->saveNewEndpoint();
+  }
+
+  /**
+   * Test list.Methods call.
+   *
+   * Regression http://drupal.org/node/1072844.
+   */
+  function testlistMethods() {
+    $result = $this->servicesXMLRPC('system.listMethods', array());
+    $this->assertFalse(in_array('node.index', $result['body']), t('Not able to find not enabled node.index method.'), 'XMLRPC: listMethods');
+  }
+
+  /**
+   * Test user login.
+   */
+  function testUserLogin() {
+    // Create user.
+    $user = $this->drupalCreateUser(array('access user profiles'));
+    $args = array(
+      'username' => $user->name,
+      'password' => $user->pass_raw,
+    );
+    $result = $this->servicesXMLRPC('user.login', $args);
+    $this->assertEqual($result['body']['user']['uid'], $user->uid,
+      t('User %user logged in successfully.', array('%user' => $user->name)), 'XMLRPC: UserLogin');
+
+    $this->sessid = $result['body']['sessid'];
+    $this->session_name = $result['body']['session_name'];
+
+    // Call index method as logged in user.
+    $result = $this->servicesXMLRPC('user.index');
+    // There should be three users available: anonymous, admin and newly created.
+    $this->assertTrue(count($result['body']) == 3, t('Users listed properly.'), 'XMLRPC: UserLogin');
+  }
+
+  /**
+   * Precedence CRUD methods > Actions > Relations > Targeted Actions
+   *
+   * @see http://drupal.org/node/1016350
+   */
+  function testPrecedence() {
+    $args = array('arg1' => $this->randomName());
+    $result = $this->servicesXMLRPC('services_test.retrieve', $args);
+    $this->assertEqual($result['body'], 'CRUD Retrieve ' . $args['arg1'], t('XMLRPC precedence works properly (CRUD higher priority than action).'), 'XMLRPC: Precedence');
+  }
+
+  public function saveNewEndpoint() {
+    $edit = $this->populateEndpointFAPI() ;
+    $endpoint = new stdClass;
+    $endpoint->disabled = FALSE; /* Edit this to true to make a default endpoint disabled initially */
+    $endpoint->api_version = 3;
+    $endpoint->name = $edit['name'];
+    $endpoint->title = $edit['title'];
+    $endpoint->server = $edit['server'];
+    $endpoint->path = $edit['path'];
+    $endpoint->authentication = array();
+    $endpoint->resources = array(
+      'system' => array(
+        'alias' => '',
+        'actions' => array(
+          'connect' => array(
+            'enabled' => 1,
+          ),
+          'get_variable' => array(
+            'enabled' => 1,
+          ),
+          'set_variable' => array(
+            'enabled' => 1,
+          ),
+        ),
+      ),
+      'user' => array(
+        'alias' => '',
+        'operations' => array(
+          'create' => array(
+            'enabled' => 1,
+          ),
+          'retrieve' => array(
+            'enabled' => 1,
+          ),
+          'update' => array(
+            'enabled' => 1,
+          ),
+          'delete' => array(
+            'enabled' => 1,
+          ),
+          'index' => array(
+            'enabled' => 1,
+          ),
+        ),
+        'actions' => array(
+          'login' => array(
+            'enabled' => 1,
+          ),
+          'logout' => array(
+            'enabled' => 1,
+          ),
+        ),
+      ),
+      'services_test' => array(
+        'alias' => '',
+        'operations' => array(
+          'retrieve' => array(
+            'enabled' => 1,
+          ),
+        ),
+        'actions' => array(
+          'retrieve' => array(
+            'enabled' => 1,
+          ),
+        ),
+      ),
+    );
+    $endpoint->debug = 1;
+    services_endpoint_save($endpoint);
+    $endpoint = services_endpoint_load($endpoint->name);
+    $this->assertTrue($endpoint->name == $edit['name'], t('Endpoint successfully created'));
+    return $endpoint;
+  }
+
+  public function populateEndpointFAPI() {
+    return array(
+      'name'   => 'machinename',
+      'title'  => $this->randomName(20),
+      'path'   => $this->randomName(10),
+      'server' => 'xmlrpc_server',
+    );
+  }
+
+  /**
+   * Do XMLRPC call.
+   *
+   * @param string $method
+   *   Name of method to call.
+   * @param array $args
+   *   Arguments to pass to call.
+   * @param bool $sessid
+   *   Add cookies in order to log in.
+   * @param bool $assert_no_error
+   *   Whether assert that no error returned.
+   * @return array
+   *   array(
+   *     'body' -- answer of call
+   *     'error_message' -- error message if any
+   *   )
+   */
+  public function servicesXMLRPC($method, $args = array(), $sessid = TRUE, $assert_no_error = TRUE) {
+    if (!is_array($args)) {
+      $args = array($args);
+    }
+
+    // Set up cookies.
+    $options = array();
+    if ($sessid && !empty($this->sessid)) {
+      $options = array('headers' => array('Cookie' => $this->session_name . '=' . $this->sessid));
+    }
+
+    $output = xmlrpc(url($this->endpoint->path, array('absolute' => TRUE)), array($method => $args), $options);
+
+    $error_message = xmlrpc_error_msg();
+
+    if ($assert_no_error) {
+      $this->assertTrue(empty($error_message), t('XMLRPC call %method run without errors.', array('%method' => $method)), 'XMLRPC call');
+    }
+    $this->verbose('XMLRPC request to: ' . $method .
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($args, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($output, TRUE), TRUE) .
+                   '<hr />Error: ' . $error_message);
+
+    if (!empty($error_message)) {
+      return array('error_message' => $error_message, 'body' => '');
+    }
+
+    return array('error_message' => '', 'body' => $output);
+  }
+}
\ No newline at end of file
diff --git a/tests/services_test_resource/services_test_resource.info b/tests/services_test_resource/services_test_resource.info
new file mode 100644
index 0000000..8967a1b
--- /dev/null
+++ b/tests/services_test_resource/services_test_resource.info
@@ -0,0 +1,9 @@
+name = Services Test Resource
+description = Provide test methods to check different situations.
+package = Services
+core = 7.x
+php = 5.x
+
+files[] = services_test_resource.module
+
+dependencies[] = services
\ No newline at end of file
diff --git a/tests/services_test_resource/services_test_resource.module b/tests/services_test_resource/services_test_resource.module
new file mode 100644
index 0000000..e6b21d8
--- /dev/null
+++ b/tests/services_test_resource/services_test_resource.module
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * Implements hook_services_resources().
+ */
+function services_test_resource_services_resources() {
+  return array(
+    'services_test' => array(
+      'retrieve' => array(
+        'callback' => '_services_test_resource_retrieve',
+        'args' => array(
+          array(
+            'name' => 'arg1',
+            'optional' => FALSE,
+            'source' => array('path' => 0),
+            'type' => 'int',
+            'description' => 'Test argument 1.',
+          ),
+        ),
+        'access callback' => '_services_test_resource_access',
+        'access arguments' => array('view'),
+        'access arguments append' => TRUE,
+      ),
+      'actions' => array(
+        'retrieve' => array(
+          'access callback' => '_services_test_resource_access',
+          'access arguments' => array('view'),
+          'access arguments append' => TRUE,
+          'callback' => '_services_test_resource_action_retrieve',
+          'args' => array(
+            array(
+              'name' => 'arg1',
+              'optional' => FALSE,
+              'source' => array('path' => 0),
+              'type' => 'int',
+              'description' => 'Test argument 1.',
+            ),
+          ),
+        ),
+      ),
+    ),
+  );
+}
+
+/**
+ * CRUD retrieve callback.
+ */
+function _services_test_resource_retrieve($arg1) {
+  return 'CRUD Retrieve ' . $arg1;
+}
+
+/**
+ * Action retrieve callback.
+ */
+function _services_test_resource_action_retrieve($arg1) {
+  return 'Action retrieve' . $arg1;
+}
+
+/**
+ * Access callback.
+ */
+function _services_test_resource_access($op) {
+  return TRUE;
+}
\ No newline at end of file
-- 
1.6.5.1


From f63243f1823104862bb641854f27391e1c4ca37a Mon Sep 17 00:00:00 2001
From: Greg Dunlap <gdd@heyrocker.com>
Date: Tue, 1 Mar 2011 00:12:44 +0100
Subject: [PATCH 2/2] Issue #1072844 by ygerasimov: XMLRPC server. All possible calls get listed in system.listMethods

---
 servers/xmlrpc_server/xmlrpc_server.module |   20 ++++++++++----------
 services.info                              |    1 +
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/servers/xmlrpc_server/xmlrpc_server.module b/servers/xmlrpc_server/xmlrpc_server.module
index ee1b696..5387115 100644
--- a/servers/xmlrpc_server/xmlrpc_server.module
+++ b/servers/xmlrpc_server/xmlrpc_server.module
@@ -3,11 +3,11 @@
  * @file
  *  Enable XML-RPC for services module.
  *
- * Resource definitions get converted to RPC-style procedure names, but 
- * otherwise this is really just a wrapper around the core xmlrpc server. 
- * These procedures are renamed as <resource>.<method>. So the node 
+ * Resource definitions get converted to RPC-style procedure names, but
+ * otherwise this is really just a wrapper around the core xmlrpc server.
+ * These procedures are renamed as <resource>.<method>. So the node
  * resource's retrieve method has an XMLRPC procedure name of node.retrieve,
- * the user resource's login action has an XMLRPC procedure name of 
+ * the user resource's login action has an XMLRPC procedure name of
  * user.login, etc.
  */
 
@@ -27,7 +27,7 @@ function xmlrpc_server_server() {
   require_once './includes/xmlrpc.inc';
   require_once './includes/xmlrpcs.inc';
 
-  // 
+  //
   return xmlrpc_server(xmlrpc_server_xmlrpc());
 }
 
@@ -38,8 +38,8 @@ function xmlrpc_server_server() {
  */
 function xmlrpc_server_xmlrpc() {
   $callbacks = array();
-  
-  $resources = services_get_resources();
+
+  $resources = services_get_resources(services_get_server_info('endpoint', ''));
   if (!empty($resources)) {
     // Translate all resources
     foreach ($resources as $name => $def) {
@@ -56,7 +56,7 @@ function xmlrpc_server_xmlrpc() {
  * Pass XMLRPC server requests to the appropriate services method.
  *
  * This function can take varying parameters as are appropriate to
- * the service in question. 
+ * the service in question.
  */
 function xmlrpc_server_call_wrapper() {
   $xmlrpc_server = xmlrpc_server_get();
@@ -66,8 +66,8 @@ function xmlrpc_server_call_wrapper() {
   $controller = services_controller_get($method_name, $endpoint);
 
   try {
-    return services_controller_execute($controller, $args);  
-  } 
+    return services_controller_execute($controller, $args);
+  }
   catch (Exception $e) {
     $code = $e->getCode();
     switch($code) {
diff --git a/services.info b/services.info
index 44a5b10..d916d1f 100644
--- a/services.info
+++ b/services.info
@@ -18,6 +18,7 @@ files[] = tests/functional/ServicesResourceUserTests.test
 files[] = tests/functional/ServicesResourceSystemTests.test
 files[] = tests/functional/ServicesResourceCommentTests.test
 files[] = tests/functional/ServicesEndpointTests.test
+files[] = tests/functional/ServicesXMLRPCTests.test
 files[] = tests/unit/TestServicesModule.test
 files[] = tests/services.test
 
-- 
1.6.5.1

