--- services/services.info	22 Oct 2009 03:23:44 -0000	1.5.2.2.4.1
+++ services/services.info	1 Nov 2009 16:34:45 -0000
@@ -5,6 +5,8 @@
 files[] = services_admin_browse.inc
 files[] = services.resource-translation.inc
 files[] = services.install
+files[] = services.test
+files[] = services_xmlrpc.test
 package = Services
 core = 7.x
 php = 5.x
\ No newline at end of file
--- services/services.module	22 Oct 2009 03:23:44 -0000	1.8.2.88.2.8.2.1
+++ services/services.module	1 Nov 2009 23:19:17 -0000
@@ -108,7 +108,7 @@
 function services_theme() {
   return array(
     'services_admin_browse_test' => array(
-      'arguments' => array('form' => NULL),
+      'render element' => 'form',
     ),
   );
 }
@@ -189,11 +189,12 @@
 function services_error($message, $code = 0, $exception = NULL) {
   $server_info = services_get_server_info();
 
+//  return call_user_func_array('xmlrpc_server_server_error', array($message, $code, $exception));
   // Look for custom error handling function.
   // Should be defined in each server module.
-  if ($server_info && module_hook($server_info->module, 'server_error')) {
-    return module_invoke($server_info->module, 'server_error', $message, $code, $exception);
-  }
+  //if (module_hook($server_info->module, 'server_error')) {
+//    return module_invoke($server_info->module, 'server_error', $message, $code, $exception);
+  //}
 
   // No custom error handling function found.
   return $message;
@@ -658,7 +659,7 @@
 
   // Load session data
   session_id($sessid);
-  sess_read($sessid);
+  _drupal_session_read($sessid);
 
   // Check if it really loaded user and, for additional security, if user was logged from the same IP. If not, then revert automatically.
   if ($user->sid != $sessid) {
--- services/services_admin_browse.inc	22 Oct 2009 03:23:44 -0000	1.5.2.45.2.2.2.1
+++ services/services_admin_browse.inc	1 Nov 2009 16:59:20 -0000
@@ -78,9 +78,10 @@
   $output .= '</dl>';
 
   // Allow testing of methods
-  $output .= '<h3>' . t('Call method') . '</h3>';
+  // $output .= '<h3>' . t('Call method') . '</h3>';
   // @TODO this is a hack we should be trying to return a structure array if it is possible - this is just to fix existing behaviour
-  $output .= drupal_render(drupal_get_form('services_admin_browse_test'));
+  // TEST INTERFACE REMOVED FOR NOW, as we have provide simpletest cases.
+  // $output .= theme('form', array('form' => drupal_get_form('services_admin_browse_test')));
 
   // Display results
   if ($_services_admin_browse_test_submit_result) {
@@ -102,7 +103,7 @@
 
   foreach ($method['#args'] as $key => $arg) {
     $form['name'][$key] = array(
-      '#value' => $arg['#name']
+      '#value' => " " . $arg['#name']
     );
     $form['optional'][$key] = array(
       '#value' => ($arg['#optional']) ? t('optional') : t('required')
@@ -213,7 +214,9 @@
   return $return;
 }
 
-function theme_services_admin_browse_test($form) {
+function theme_services_admin_browse_test($variables) {
+  $form = $variables['form'];
+  
   $output = '';
   $output .= drupal_render($form['test']);
 
--- services/services.test
+++ services/services.test
@@ -0,0 +1,127 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * TestCases for the services module.
+ */
+
+/**
+ * Drupal interface testcase
+ * - Check presence and status of Services pages
+ * - ...
+ */
+class ServicesInterfaceTest extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Services Drupal interface'),
+      'description' => t('Test services web interface: admin and settings pages.'),
+      'group' => t('Services')
+    );
+  }
+
+  function setUp() {
+    parent::setUp('services');
+    // Create and login an user
+    $admin_user = $this->drupalCreateUser(array('administer services'));
+    $this->drupalLogin($admin_user);
+  }
+
+  //TODO: assert no errors, ..
+  function testAdminServicesPage() {
+    //Main services page
+    $this->drupalGet('admin/build/services');
+    $this->assertResponse(200, t('Access granted to services page.'));
+    $this->assertText('Servers');
+    //...
+  }
+
+  //TODO: assert no errors, ..
+  function testAdminServicesSettings() {
+    $this->drupalGet('admin/build/services/settings');
+    $this->assertResponse(200, t('Access granted to settings page.'));
+    //$this->assertField('xxx', t('xx.'));
+  }
+}
+
+
+/**
+ * Drupal Services Crossdomain testcase
+ */
+class ServicesCrossdomainTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Crossdomain tests'),
+      'description' => t('Test crossdomain avialability.'),
+      'group' => t('Services')
+    );
+  }
+
+  function setUp() {
+    parent::setUp('services');
+  }
+
+  //TODO: check xml presence in the response.
+  //TODO: assert no errors
+  function testCrossDomainPage() {
+    $this->drupalGet('crossdomain.xml');
+    $this->assertResponse(200, t('Access granted to crossdomain.xml'));
+    //..
+  }
+
+  //TODO: check xml validity and some CSS domain cases
+  function testCrossDomainAPI() {
+    $xml = services_crossdomain_xml();
+    //...
+  }
+}
+
+class ServicesAPIMiscTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Miscellaneous Tests'),
+      'description' => t('Tests implementation for some functionality issues of services module.'),
+      'group' => t('Services'),
+    );
+  }
+
+  function setUp() {
+    //Default initialization, enable both modules
+    parent::setUp('services', 'system_service');
+
+    //Remove existing auth configuration, just in case..
+    variable_del('services_auth_module');
+    variable_del('services_key_expiry');
+    variable_del('services_use_key');
+    variable_del('services_user_sessid');
+  }
+
+  // Test calling an invalid method.
+  // Note: Should we check if user is authenticated first
+  function testInvalidMethod() {
+    $method = $this->randomName();
+    $result = services_method_call($method, array());
+    $this->assertEqual($result, t('Method %name does not exist', array('%name' => $method)), 'Check for invalid method call');
+  }
+
+  // Test calling with invalid arguments
+  // Note: Should we check if user is authenticated first?
+  function testInvalidArguments() {
+    $args = array();
+    //system.getVariable requires at least one argument
+    $result = services_method_call('system.getVariable', $args);
+    $this->assertEqual($result, 'Missing required arguments.', 'Check for invalid arguments');
+  }
+
+  // Test authentication not enabled
+  // Note: If no authentication method is enabled, all services should return TRUE :?
+  function testNoauthMethod() {
+    $this->assertTrue(services_method_call('system.connect'), 'Invalid auth method call: system.connect');
+    //Try another API
+    $args = array( 'drupal_private_key', NULL);
+    $this->assertTrue(services_method_call('system.getVariable', $args), 'Invalid auth method call: system.getVariable');
+  }
+}

--- services/services_xmlrpc.test
+++ services/services_xmlrpc.test
@@ -0,0 +1,140 @@
+<?php
+// $Id$
+
+/**
+ * @author Services Dev Team
+ * @file
+ *  Test xmlrpc_server implementation.
+ */
+
+class ServicesXmlRpcTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Services functionality',
+      'description' => 'Test xmlrpc server implementation using xmlr server.',
+      'group' => t('Services')
+    );
+  }
+
+  protected $account;
+  protected $session;
+
+  /*
+   * Enable the module and configure the basics for the test.
+   */
+  function setUp() {
+    parent::setUp('services', 'services_keyauth', 'user_service', 'system_service', 'xmlrpc_server');
+
+    //Configure authentication of services using session id and no key
+    variable_set('services_auth_module', 'services_keyauth');
+    variable_set('services_key_expiry', 0);
+    variable_set('services_use_key', FALSE);
+    variable_set('services_use_sessid', TRUE);
+  }
+
+  function testServicesFunctionality() {
+    // Init common variables.
+    $xmlrpc = url('services/xmlrpc', array('absolute' => TRUE));
+    $this->pass($xmlrpc);
+
+    // Test that xmlrpc service is available.
+    $this->drupalGet('services/xmlrpc');
+    $this->assertText('XML-RPC server accepts POST requests only.', t('XMLRPC service enabled and accepting POST requests only'));
+
+    // Get a session
+    $result  = xmlrpc($xmlrpc, 'system.connect');
+    $this->assertTrue(isset($result['sessid']), t('Got a connection session from the server.'));
+    $this->assertTrue(empty($result['user']['uid']), t('Currently status is unauthenticated user.'));
+
+    // Save current session id, required for subsequent calls.
+    $session = $result['sessid'];
+
+    // Create user with permissions to use all services.
+    $permissions = array(
+      'set variable from remote',
+      'get variable from remote',
+      'check module exists from remote',
+      'get any user data',
+      'update any user data',
+      'create new users',
+    );
+    $account = $this->drupalCreateUser($permissions);
+
+    // Try some login operations..
+
+    // Invalid arguments login
+    $result  = xmlrpc($xmlrpc, 'user.login', $account->name);
+    $this->assertTrue(empty($result['user']['uid']), t('Invalid call does not authenticate.'));
+    // Replace with appropiate assert including expected message.
+    $this->assertTrue(!empty($result), t('Expected invalid call message'));
+
+    // Invalid arguments login
+    $result  = xmlrpc($xmlrpc, 'user.login', $session, $account->name);
+    $this->assertTrue(empty($result['user']['uid']), t('Invalid call does not authenticate.'));
+    // Replace with appropiate assert including expected message.
+    $this->assertTrue(!empty($result), t('Expected invalid call message'));
+
+    // Invalid credentials login
+    $result  = xmlrpc($xmlrpc, 'user.login', $session, $account->name, $this->randomName());
+    $this->assertTrue(empty($result['user']['uid']), t('Invalid call does not authenticate.'));
+    // Replace with appropiate assert including expected message.
+    $this->assertTrue(!empty($result), t('Expected invalid call message'));
+
+    // valid login
+    $result  = xmlrpc($xmlrpc, 'user.login', $session, $account->name, $account->pass_raw);
+    $this->assertEqual($result['user']['uid'], $account->uid, t('Successfully authenticated.'));
+    $this->assertTrue(!empty($result['sessid']), t('Authenticated session found.'));
+
+    // Save authenticated session
+    $session = $result['sessid'];
+
+    // Prepare information for system.setVariable and system.getVariable methods
+    $name = $this->randomName();
+    $value = $this->randomName();
+
+    // Use system.setVariable
+    $result  = xmlrpc($xmlrpc, 'system.setVariable', $session, $name, $value);
+    // Check system.getVariable and system.setVariable requesting the variable
+    $result  = xmlrpc($xmlrpc, 'system.getVariable', $session, $name);
+    $this->assertEqual($result, $value, t('system.setVariable and system.getVariable successfully verified.'));
+
+    // check system.moduleExists with valid module
+    $result  = xmlrpc($xmlrpc, 'system.moduleExists', $session, $name, 'services');
+    $this->assertEqual('services', $result, t("system.moduleExists for valid module successfully verified."));
+
+    // check system.moduleExists with invalid module
+    $result  = xmlrpc($xmlrpc, 'system.moduleExists', $session, $this->randomName());
+    $this->assertTrue(empty($result), t('system.moduleExists for invalid module successfully verified.'));
+
+    // Prepare user object to test user services
+    $newuser = drupal_anonymous_user();
+    $newuser->name = $this->randomName();
+
+    // check user.save to create a user
+    // check system.moduleExists with invalid module
+    $result  = xmlrpc($xmlrpc, 'user.save', $session, $newuser);
+    $this->assertTrue($result, t('user.save (uid %uid) creating user successfully verified.', array('%uid' => $result)));
+
+    $uid = $result;
+    // check user.get to load the new created user
+    $result  = xmlrpc($xmlrpc, 'user.get', $session, $uid);
+    $this->assertEqual($result['uid'], $uid, t('user.get successfully verified.'));
+
+    // check user.save to update the user
+//    $newuser = user_load($result['uid']);
+    $newuser->uid = $uid;
+    $newuser->name = $this->randomName();
+
+    $result  = xmlrpc($xmlrpc, 'user.save', $session, $newuser);
+    $this->assertEqual($result, $newuser->uid, t('user.save return user successfully updated.'));
+
+    // check user.delete with the testing user
+    $deleted  = xmlrpc($xmlrpc, 'user.delete', $session, $result['uid']);
+    $this->assertTrue($deleted, t('user.delete return user has been deleted.'));
+
+    // check user.get with the deleted user.
+    $result  = xmlrpc($xmlrpc, 'user.get', $session, $result['uid']);
+    $this->assertEqual(t('There is no user with such ID.'), $result, t('user.delete successfully verified.'));
+  }
+}


