diff --git tests/functional/ServicesResourceNodeTests.test tests/functional/ServicesResourceNodeTests.test
index fd381a5..6837779 100644
--- tests/functional/ServicesResourceNodeTests.test
+++ tests/functional/ServicesResourceNodeTests.test
@@ -1,303 +1,254 @@
 <?php
- /**
+// $Id$
+
+/**
  * @file
  * Call the endpoint tests when no authentication is being used.
  *
  */
 
 require_once('ServicesWebTestCase.php') ;
+
 /**
  * Run test cases for the endpoint with no authentication turned on.
  *
  */
- class ServicesResourceNodeTests extends ServicesWebTestCase {
- // Class variables
+class ServicesResourceNodetests extends ServicesWebtestCase {
+  // Class variables
   protected $privilegedUser = NULL ;
+  // Endpoint details.
+  protected $endpoint = NULL;
 
-   /**
-    * Implementation of setUp().
-    */
-   public function setUp() {
-     parent::setUp(
+  /**
+   * Implementation of setUp().
+   */
+  public function setUp() {
+    parent::setUp(
       'autoload',
-     	'ctools',
-     	'services',
+      'ctools',
+      'services',
       'rest_server',
       'services_sessauth',
       'inputstream'
-     );
-   }
+    );
+    // Set up endpoint.
+    $this->endpoint =  $this->saveNewEndpoint();
+  }
 
-   /**
-    * Implementation of getInfo().
-    */
-   public static function getInfo() {
-     return array(
-       'name'        => t('Resource Node tests, no auth'),
-       'description' =>
-         t('Test the resource NODE methods and actions.'),
-       'group'       => t('Services'),
-     );
-   }
-/**
-    * testing node_resource Index
-    */
-   public function testNewEndpointResourceNodeIndex() {
+  /**
+   * Implementation of getInfo().
+   */
+  public static function getInfo() {
+   return array(
+     'name'        => t('Resource Node tests, no auth'),
+     'description' =>
+       t('test the resource NODE methods and actions.'),
+     'group'       => t('Services'),
+   );
+  }
+
+  /**
+   * testing node_resource Index
+   */
+  public function testNewEndpointResourceNodeIndex() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
+      'administer services',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
+
     $node = $this->drupalCreateNode();
-    $responseArray = $this->servicesGet($endpoint->path.'/node');
-    $nodeResourceIndex = json_decode($responseArray['body']);
-    if($node->title == $nodeResourceIndex[0]->title) {
-      $this->pass('Successfully received Node info', 'NodeResource: Index');
-    } else {
-      $this->fail(t('Something went wrong. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Index');
-    }
-   }
+    $responseArray = $this->servicesGet($this->endpoint->path . '/node');
+    $this->assertTrue($node->title == $responseArray['body'][0]->title, t('Successfully received Node info'), 'NodeResource: Index');
+  }
+
   /**
-    * testing node_resource Get
-    */
-   public function testNewEndpointResourceNodeGet() {
-     // Create and log in our privileged user.
-     $this->privilegedUser = $this->drupalCreateUser(array(
-         'administer services',
-     ));
-     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
+   * testing node_resource Get
+   */
+  public function testNewEndpointResourceNodeGet() {
+    // Create and log in our privileged user.
+    $this->privilegedUser = $this->drupalCreateUser(array(
+      'administer services',
+    ));
+    $this->drupalLogin($this->privilegedUser);
     $node = $this->drupalCreateNode();
-    $responseArray = $this->servicesGet($endpoint->path.'/node/'. $node->nid);
-    $nodeResourceGet = json_decode($responseArray['body']);
-    if($node->title == $nodeResourceGet->title) {
-      $this->pass('Successfully received Node info', 'NodeResource: Retrieve');
-    } else {
-      $this->fail(t('Something went wrong. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Retrieve');
-    }
-    //Verify node not Found
+    $responseArray = $this->servicesGet($this->endpoint->path . '/node/' . $node->nid);
+    $this->assertTrue($node->title == $responseArray['body']->title, t('Successfully received Node info'), 'NodeResource: Retrieve');
+    //Verify node not found.
     unset($node);
-    $responseArray = $this->servicesGet($endpoint->path.'/node/99');
-    if($responseArray['code'] == '404') {
-      $this->pass('Successfully was rejected to non existent node', 'NodeResource: Retrieve');
-    } else {
-      $this->pass('I didnt get rejected, bad news!', 'NodeResource: Retrieve');
-    }
-   }
+    $responseArray = $this->servicesGet($this->endpoint->path . '/node/99');
+    $this->assertTrue($responseArray['code'] == '404', t('Successfully was rejected to non existent node'), 'NodeResource: Retrieve');
+  }
+
   /**
-    * testing node_resource Create
-    */
-   public function testEndpointResourceNodeCreate() {
+   * testing node_resource Create
+   */
+  public function testEndpointResourceNodeCreate() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer nodes',
+      'administer services',
+      'administer nodes',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = array(
-      'node[title]' => 'testing',
-      'node[body]' => 'bodytest',
-      'node[type]' => 'story',
-      'node[name]' => $this->privilegedUser->name,
+      'title' => 'testing',
+      'body' => 'bodytest',
+      'type' => 'story',
+      'name' => $this->privilegedUser->name,
     );
-    
-    $data = $this->services_build_postfields($node);
-    $responseArray = $this->servicesPost($endpoint->path.'/node', $data, array('Accept: application/json'));
-    $nodeResourceCreateReturn = json_decode($responseArray['body']);
-    
-    if(isset($nodeResourceCreateReturn->nid)) {
-      $this->pass('Node was successfully created',  'NodeResource: Create');
+
+    $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+    $nodeResourceCreateReturn = $responseArray['body'];
+
+    $this->assertTrue(isset($nodeResourceCreateReturn->nid), t('Node was successfully created'), 'NodeResource: Create');
+    if (isset($nodeResourceCreateReturn->nid)) {
       $newNode = node_load($nodeResourceCreateReturn->nid);
-      if($newNode->title = $node['node[title]']) {
-        $this->pass('Title was the same',  'NodeResource: Create');
-      } else {
-        $this->fail('Title was different', 'NodeResource: Create');
-      }
-      if($newNode->body = $node['node[body]']) {
-        $this->pass('Body was the same', 'NodeResource: Create');
-      } else {
-        $this->fail('Body was different', 'NodeResource: Create');
-      }
-    } else {
-      $this->fail(t('Creating the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Create');
+      $this->assertTrue($newNode->title = $node['title'], t('Title was the same'), 'NodeResource: Create');
+      $this->assertTrue($newNode->body = $node['body'], t('Body was the same'), 'NodeResource: Create');
     }
   }
+
   /**
-    * testing node_resource Created make ure it fails with no perms
-    */
-   public function testEndpointResourceNodeCreateFail() {
+   * testing node_resource Created make ure it fails with no perms
+   */
+  public function testEndpointResourceNodeCreateFail() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
+      'administer services',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = array(
-      'node[title]' => 'testing',
-      'node[body]' => 'bodytest',
-      'node[type]' => 'story',
-      'node[name]' => $this->privilegedUser->name,
+      'title' => 'testing',
+      'body' => 'bodytest',
+      'type' => 'story',
+      'name' => $this->privilegedUser->name,
     );
-    
-    $data = $this->services_build_postfields($node);
-    $responseArray = $this->servicesPost($endpoint->path.'/node', $data, array('Accept: application/json'));
-    $nodeResourceCreateReturn = json_decode($responseArray['body']);
-    
-    if($responseArray['code'] = 401) {
-      $this->pass('User with permissions cannot create node',  'NodeResource: Create');
-    } else {
-      $this->fail(t('User was able to create nodes without permission. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Create');
-    }
+
+    $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+
+    $this->assertTrue($responseArray['code'] == 401, t('User with not sufficient permissions cannot create node'), 'NodeResource: Create');
   }
+
   /**
-    * testing node_resource Validate missing Title
-    */
-   public function testEndpointResourceNodeCreateMissingTitle() {
+   * testing node_resource Validate missing Title
+   */
+  public function testEndpointResourceNodeCreateMissingTitle() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer nodes',
+      'administer services',
+      'administer nodes',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
-    $node = $this->drupalCreateNode();
-    $node_update = array(
-      'node[title]' => '',
-      'node[body]' => 'bodytest',
-      'node[name]' => $this->privilegedUser->name,
-      'node[type]' => 'story',
+
+    $node = array(
+      'title' => '',
+      'body' => 'bodytest',
+      'name' => $this->privilegedUser->name,
+      'type' => 'page',
     );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPost($endpoint->path.'/node', $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
+
+    $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+
+    $nodeResourceUpdateReturn = $responseArray['body'];
     $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(strpos($responseArray['status'], 'Title field is required.')) {
-      $this->pass('Node was not created, no title. ', 'NodeResource: Created');
-    }
+    $this->assertTrue(strpos($responseArray['status'], 'Title field is required.'), t('Node was not created without title. '), 'NodeResource: Created');
   }
+
   /**
-    * testing node_resource Update
-    */
-   public function testEndpointResourceNodeUpdate() {
+  * testing node_resource Update
+  */
+  public function testEndpointResourceNodeUpdate() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer nodes',
+      'administer services',
+      'administer nodes',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = $this->drupalCreateNode();
     $node_update = array(
-      'node[title]' => 'testing',
-      'node[body]' => 'bodytest',
-      'node[type]' => 'story',
-      'node[name]' => $this->privilegedUser->name,
+      'title' => 'testing',
+      'body' => 'bodytest',
+      'type' => 'story',
+      'name' => $this->privilegedUser->name,
     );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPut($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(isset($nodeAfterUpdate->nid)) {
-      $this->pass('Node was successfully updated',  'NodeResource: Updated');
-      if($nodeAfterUpdate->title = $node_update['node[title]']) {
-        $this->pass('Title was the same',  'NodeResource: Update');
-      } else {
-        $this->fail('Title was different', 'NodeResource: Update');
-      }
-      if($nodeAfterUpdate->body = $node_update['node[body]']) {
-        $this->pass('Body was the same', 'NodeResource: Update');
-      } else {
-        $this->fail('Body was different', 'NodeResource: Update');
-      }
-    } else {
-      $this->fail(t('Updating the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Update');
+
+    $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+    $nodeAfterUpdate = node_load($responseArray['body']);
+    $this->assertTrue(isset($nodeAfterUpdate->nid), t('Node was successfully updated'), 'NodeResource: Updated');
+    if (isset($nodeAfterUpdate->nid)) {
+      $this->assertTrue($nodeAfterUpdate->title == $node_update['title'], t('Title was the same'), 'NodeResource: Update');
+      $this->assertTrue($nodeAfterUpdate->body == $node_update['body'], t('Body was the same'), 'NodeResource: Update');
     }
   }
+
   /**
-    * testing node_resource Update fail with no permissions
-    */
-   public function testEndpointResourceNodeUpdatePermFail() {
+  * testing node_resource Update fail with no permissions
+  */
+  public function testEndpointResourceNodeUpdatePermFail() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'create story content',
-       'edit own story content',
+      'administer services',
+      'create story content',
+      'edit own story content',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
+
+    // Create node from user no 1.
     $node = $this->drupalCreateNode(array('uid' => 1));
+
+    // Try to update this node with different user not
+    // having permission to edit any story content.
     $node_update = array(
-      'node[title]' => 'testing',
-      'node[body]' => 'bodytest',
-      'node[type]' => 'story',
+      'title' => 'testing',
+      'body' => 'bodytest',
+      'type' => 'story',
     );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPut($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(isset($nodeAfterUpdate->nid)) {
-      $this->fail(t('Updating the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Update');
-    } else {
-      $this->pass(t('Updating the node failed. This is good!'), 'NodeResource: Update');
-    }
+    $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+
+    $this->assertTrue(strpos($responseArray['status'], 'Access denied for user'), t('Updating the node failed without needed permissions. This is good!'), 'NodeResource: Update');
   }
+
   /**
-    * testing node_resource Update verify missing title
-    */
-   public function testEndpointResourceNodeUpdateMissingTitle() {
+   * testing node_resource Update verify missing title
+   */
+  public function testEndpointResourceNodeUpdateMissingTitle() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer nodes',
+      'administer services',
+      'administer nodes',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = $this->drupalCreateNode();
     $node_update = array(
-      'node[title]' => '',
-      'node[body]' => 'bodytest',
-      'node[name]' => $this->privilegedUser->name,
+      'title' => '',
+      'body' => 'bodytest',
+      'name' => $this->privilegedUser->name,
+      'type' => 'story',
     );
-    
-    $data = $this->services_build_postfields($node_update);
-    $responseArray = $this->servicesPut($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    $nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
-    if(strpos($responseArray['status'], 'Title field is required.')) {
-      $this->pass('Node was not created, no title. ', 'NodeResource: Update');
-    }
+
+    $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+    $this->assertTrue(strpos($responseArray['status'], 'Title field is required.'), t('Node was not updated without title.'), 'NodeResource: Update');
   }
+
   /**
-    * testing node_resource Delete
-    */
-   public function testEndpointResourceNodeDelete() {
+   * testing node_resource Delete
+   */
+  public function testEndpointResourceNodeDelete() {
     // Create and log in our privileged user.
     $this->privilegedUser = $this->drupalCreateUser(array(
-       'administer services',
-       'administer nodes',
+      'administer services',
+      'administer nodes',
     ));
     $this->drupalLogin($this->privilegedUser);
-    $endpoint =  $this->saveNewEndpoint();
     $node = $this->drupalCreateNode();
     $data = '';
-    $responseArray = $this->servicesDelete($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    if($responseArray['code'] == 200) {
-      $this->pass('Node was deleted.', 'NodeResource: Deleted');
-    } else {
-      $this->fail(t('Deleting the node failed. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Delete');
-    }
-    $responseArray = $this->servicesDelete($endpoint->path.'/node/'.$node->nid, $data, array('Accept: application/json'));
-    $nodeResourceUpdateReturn = json_decode($responseArray['body']);
-    if($responseArray['code'] == 200) {
-      $this->fail('Node was deleted. It shoudlnt have been because it doesnt exist', 'NodeResource: Deleted');
-    } else {
-      $this->pass(t('Was not abled to delete node because it doesnt exist. StatusCode: !status', array('!status' => $responseArray['status'])), 'NodeResource: Delete');
-    }
+
+    $responseArray = $this->servicesDelete($this->endpoint->path . '/node/' . $node->nid, $data);
+    $deleted_node = node_load($node->nid, NULL, TRUE);
+    $this->assertTrue(empty($deleted_node), t('Node was deleted.'), 'NodeResource: Deleted');
+
+    $responseArray = $this->servicesDelete($this->endpoint->path . '/node/' . $node->nid, $data);
+
+    $this->assertFalse($responseArray['code'] == 200, t('Node was deleted. It shoudlnt have been because it doesnt exist'), 'NodeResource: Deleted');
   }
-}
\ No newline at end of file
+}
diff --git tests/functional/ServicesResourceUserTests.test tests/functional/ServicesResourceUserTests.test
new file mode 100644
index 0000000..11e2c7c
--- /dev/null
+++ tests/functional/ServicesResourceUserTests.test
@@ -0,0 +1,236 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Call the endpoint tests when no authentication is being used.
+ *
+ */
+
+require_once('ServicesWebTestCase.php') ;
+
+/**
+ * Run test cases for the endpoint with no authentication turned on.
+ *
+ */
+class ServicesResourceUsertests extends ServicesWebtestCase {
+  // Class variables
+  protected $privileged_user = NULL ;
+  // Endpoint details.
+  protected $endpoint = NULL;
+
+  /**
+   * Implementation of setUp().
+   */
+  public function setUp() {
+    parent::setUp(
+      'autoload',
+      'ctools',
+      'services',
+      'rest_server',
+      'services_sessauth',
+      'inputstream'
+    );
+    // Set up endpoint.
+    $this->endpoint =  $this->saveNewEndpoint();
+    // Set up privileged user and login.
+    $this->privileged_user = $this->drupalCreateUser(array('administer users', 'access user profiles'));
+    $this->drupalLogin($this->privileged_user);
+  }
+
+  /**
+   * Implementation of getInfo().
+   */
+  public static function getInfo() {
+   return array(
+     'name'        => t('Resource User tests, no auth'),
+     'description' =>
+       t('Test the resource User methods and actions.'),
+     'group'       => t('Services'),
+   );
+  }
+
+  /**
+   * Test create method.
+   *
+   * Create user, load user, try ti create user without email.
+   */
+  function testCreateUser() {
+    // Create user.
+    $user = array();
+    $user['name']   = $this->randomName();
+    $user['mail']   = $user['name'] . '@example.com';
+    $user['pass']   = user_password();
+    $user['status'] = 1;
+
+    $response = $this->servicesPost($this->endpoint->path . '/user', array('account' => $user));
+    $account = $response['body'];
+    $this->assertTrue(!empty($account->uid), t('User has been create successfully.'), 'UserResource: Create');
+
+    // Load user.
+    $user_load = user_load($account->uid);
+    $this->assertTrue(!empty($user_load), t('Newly created user has been loaded successfully.'), 'UserResource: Create');
+
+    // Try to create user without email.
+    $user = array();
+    $user['name']   = $this->randomName();
+    $user['pass']   = user_password();
+    $user['status'] = 1;
+    $response = $this->servicesPost($this->endpoint->path . '/user', array('account' => $user));
+    $this->assertTrue(strpos($response['status'], 'E-mail address field is required') !== FALSE, t('It is not possible to create user without email.'), 'UserResource: Create');
+  }
+
+  /**
+   * Test retrieve method.
+   */
+  function testRetrieveUser() {
+    $response = $this->servicesGET($this->endpoint->path . '/user/' . $this->privileged_user->uid);
+    $account = $response['body'];
+
+    $users_are_the_same =  ($account->name == $this->privileged_user->name)
+                        && ($account->mail = $this->privileged_user->mail)
+                        && ($account->roles = $this->privileged_user->roles);
+    $this->assertTrue($users_are_the_same, t('Retrieved user is the same as created.'), 'UserResource: Retrieve');
+  }
+
+  /**
+   * Test update method.
+   *
+   * Create user, update email.
+   */
+  function testUpdateUser() {
+    // Create user.
+    $account = $this->drupalCreateUser();
+
+    // Update mail of the user. Note: roles is required attribute as update
+    // method does drupal_execute of user_profile_form form.
+    $updated_account = array(
+      'uid' => $account->uid,
+      'name' => $account->name,
+      'roles' => $account->roles,
+      'mail' => $this->randomName() . '@example.com',
+    );
+    $response = $this->servicesPut($this->endpoint->path . '/user/' . $account->uid, array('data' => $updated_account));
+
+    $user_load = user_load($account->uid);
+    $this->assertEqual($updated_account['mail'], $user_load->mail, t('User details have been updated successfully'), 'UserResource: Update');
+  }
+
+  /**
+   * Test delete method.
+   */
+  function testDeleteUser() {
+    // Create user.
+    $account = $this->drupalCreateUser();
+
+    // Delete user.
+    $response = $this->servicesDelete($this->endpoint->path . '/user/' . $account->uid);
+
+    $user_load = user_load($account->uid);
+    $this->assertTrue(empty($user_load), t('User has been deleted successfully.'), 'UserResource: Delete');
+  }
+
+  /**
+   * Test index method.
+   *
+   * Create several users list them. List one user by name.
+   */
+  function testUserIndex() {
+    // Create several users.
+    $accounts = array();
+    for ($i = 0; $i < 5; $i++) {
+      $account = $this->drupalCreateUser();
+      $accounts[$account->uid] = $account;
+    }
+
+    $accounts_copy = $accounts;
+
+    $response = $this->servicesGet($this->endpoint->path . '/user');
+    $response_accounts = $response['body'];
+
+    foreach ($response_accounts as $response_account) {
+      // We do not check anonymous and admin users.
+      if ($response_account->uid < 2) {
+        continue;
+      }
+      // If name and email are the same we believe that accounts are the same.
+      if (isset($accounts[$response_account->uid])) {
+        $saved_account = $accounts[$response_account->uid];
+        if ($response_account->name == $saved_account->name && $response_account->mail == $saved_account->mail) {
+          unset($accounts_copy[$response_account->uid]);
+        }
+      }
+    }
+
+    $this->assertTrue(empty($accounts_copy), t('Users were listed properly.'), 'UserResource: Index');
+
+    $accounts_copy = $accounts;
+    $account = array_pop($accounts_copy);
+
+    // Get user with specific name.
+    $response = $this->servicesGet($this->endpoint->path . '/user', array('parameters' => array('name' => $account->name)));
+    $response_accounts = $response['body'];
+
+    $proper_answer = count($response_accounts) == 1
+                  && isset($response_accounts[$account->uid])
+                  && $response_accounts[$account->uid]->name == $account->name;
+    $this->assertTrue($proper_answer, t('User was listed by name properly.'), 'UserResource: Index');
+  }
+
+  /**
+   * Test login method.
+   *
+   * Create user. Login. Try to login with another user (to get error).
+   * Login with wrong credentials (to get error).
+   */
+  function testUserLogin() {
+    $account = $this->drupalCreateUser();
+
+    // Logout first.
+    $this->drupalLogout();
+
+    $response = $this->servicesPost($this->endpoint->path . '/user/login', array('name' => $account->name, 'pass' => $account->pass_raw));
+
+    $response_data = $response['body'];
+
+    $proper_answer = isset($response_data->sessid)
+                  && isset($response_data->user)
+                  && $response_data->user->name == $account->name;
+    $this->assertTrue($proper_answer, t('User successfully logged in.'), 'UserResource: Login');
+
+    // Save session details.
+    $this->session_id = $response_data->sessid;
+    $this->session_name = $response_data->session_name;
+    $this->loggedInUser = $response_data->user;
+
+    // Try to login with another user to get error.
+    $account2 = $this->drupalCreateUser();
+    $response = $this->servicesPost($this->endpoint->path . '/user/login', array('name' => $account2->name, 'pass' => $account2->pass_raw));
+    $this->assertTrue(strpos($response['status'], 'Already logged in as ' . $account->name) !== FALSE, t('Session is properly opened for logged in user.'), 'UserResource: Login');
+
+    // Logout.
+    $this->drupalLogout();
+
+    // Try to login with wrong credentials.
+    $response = $this->servicesPost($this->endpoint->path . '/user/login', array('name' => $account->name, 'pass' => $this->randomString()));
+    $this->assertTrue(strpos($response['status'], 'Wrong username or password') !== FALSE, t('User cannot login with wrong username / password.'), 'UserResource: Login');
+  }
+
+  /**
+   * Test logout method.
+   */
+  function testUserLogout() {
+    // Logout via REST call.
+    $response = $this->servicesPost($this->endpoint->path . '/user/logout');
+    // Try logout second time.
+    $this->drupalLogout();
+    $this->assertText(t('You are not authorized to access this page'), t('User logout successfully.'), 'UserResource: Logout');
+    // Login again.
+    $this->drupalLogin($this->privileged_user);
+    // Logout via REST call.
+    $response = $this->servicesPost($this->endpoint->path . '/user/logout');
+    // Try to logout second time via REST call.
+    $response = $this->servicesPost($this->endpoint->path . '/user/logout');
+    $this->assertTrue(strpos($response['status'], 'User is not logged in'), t('User cannot logout when is anonymous'), 'UserResource: Logout');
+  }
+}
diff --git tests/functional/ServicesWebTestCase.php tests/functional/ServicesWebTestCase.php
index 871d04b..7b45207 100644
--- tests/functional/ServicesWebTestCase.php
+++ tests/functional/ServicesWebTestCase.php
@@ -1,97 +1,158 @@
 <?php
- class ServicesWebTestCase extends DrupalWebTestCase {
-  protected function servicesGet($url, $data = NULL, $parameters = NULL) {
-    $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $content = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($url, $options), CURLOPT_NOBODY => FALSE, CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_HEADER => TRUE, CURLOPT_HTTPHEADER => array("Accept: application/json")));
-    $info = curl_getinfo($this->curlHandle);
-    $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
-    $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
+// $Id$
+
+class ServicesWebTestCase extends DrupalWebTestCase {
+
+  protected function servicesGet($url, $data = NULL, $headers = array()) {
+    $options = array('query' => $data);
+    $url = url($this->getAbsoluteUrl($url) . '.php', $options);
+    $headers = array();
+    $content = $this->curlExec(array(
+      CURLOPT_HTTPGET => TRUE,
+      CURLOPT_URL => $url,
+      CURLOPT_NOBODY => FALSE,
+      CURLOPT_RETURNTRANSFER => TRUE,
+      CURLOPT_HEADER => TRUE,
+      CURLOPT_HTTPHEADER => $headers
+    ));
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
     $this->verbose('GET request to: ' . $url .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
     return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
   }
-  protected function servicesPost($url, $data = NULL, $headers = array()) {
+
+  protected function servicesPost($url, $data = array(), $headers = array()) {
     $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $content = $this->curlExec(array(CURLOPT_URL => $url, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $data, CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => TRUE));
-    $info = curl_getinfo($this->curlHandle);
-    $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
-    $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
+    // Add .php to get serialized response.
+    $url = $this->getAbsoluteUrl($url) . '.php';
+
+    // Otherwise Services will reject arguments.
+    $headers = array("Content-type: application/x-www-form-urlencoded");
+    // Prepare arguments.
+    $post = http_build_query($data, '', '&');
+
+    $content = $this->curlExec(array(
+      CURLOPT_URL => $url,
+      CURLOPT_POST => TRUE,
+      CURLOPT_POSTFIELDS => $post,
+      CURLOPT_HTTPHEADER => $headers,
+      CURLOPT_HEADER => TRUE,
+      CURLOPT_RETURNTRANSFER => TRUE
+    ));
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
     $this->verbose('POST request to: ' . $url .
-                    'data: ' . $data .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Curl info: ' . highlight_string('<?php ' . var_export($info, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
     return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
   }
+
   protected function servicesPut($url, $data = NULL, $headers = array()) {
     $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $putData = tmpfile();
-    // Write the string to the temporary file
-    fwrite($putData, $data);
+    $url = $this->getAbsoluteUrl($url) . '.php';
+
+    $serialize_args = serialize($data);
+
+    // Set up headers so arguments will be unserialized.
+    $headers = array("Content-type: application/vnd.php.serialized; charset=iso-8859-1");
+
+    // Emulate file.
+    $putData = fopen('php://memory', 'rw+');
+    fwrite($putData, $serialize_args);
     fseek($putData, 0);
-    $content = $this->curlExec(array(CURLOPT_URL => $url,CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_POSTFIELDS => $data, CURLOPT_HTTPHEADER => $headers, CURLOPT_INFILE =>$putData, CURLOPT_INFILESIZE => strlen($data)));
-    $info = curl_getinfo($this->curlHandle);
-    $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
-    $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
-    $this->verbose('PUT request to: ' . $url .
-                    'data: ' . $data .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
+
+    $content = $this->curlExec(array(
+      CURLOPT_URL => $url,
+      CURLOPT_RETURNTRANSFER => TRUE,
+      CURLOPT_PUT => TRUE,
+      CURLOPT_HEADER => TRUE,
+      CURLOPT_HTTPHEADER => $headers,
+      CURLOPT_INFILE => $putData,
+      CURLOPT_INFILESIZE => strlen($serialize_args)
+    ));
     fclose($putData);
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
+    $this->verbose('PUT request to: ' . $url .
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Curl info: ' . highlight_string('<?php ' . var_export($info, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
     return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
   }
+
   protected function servicesDelete($url, $data = NULL, $headers = array()) {
-    $options = array();
-    $url = $this->getAbsoluteUrl($url);
-    $this->pass($url, 'URL');
-    $content = $this->curlExec(array(CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => "DELETE", CURLOPT_HTTPHEADER => $headers, CURLOPT_RETURNTRANSFER => TRUE));
+    $options = array('query' => $data);
+    $url = url($this->getAbsoluteUrl($url) . '.php', $options);
+
+    $content = $this->curlExec(array(
+      CURLOPT_URL => $url,
+      CURLOPT_CUSTOMREQUEST => "DELETE",
+      CURLOPT_HTTPHEADER => $headers,
+      CURLOPT_RETURNTRANSFER => TRUE
+    ));
+
+    // Parse response.
+    list($info, $header, $status, $code, $body) = $this->parseHeader($content);
+
+    $this->verbose('DELETE request to: ' . $url .
+                   '<hr />Arguments: ' . highlight_string('<?php ' . var_export($data, TRUE), TRUE) .
+                   '<hr />Response: ' . highlight_string('<?php ' . var_export($body, TRUE), TRUE) .
+                   '<hr />Curl info: ' . highlight_string('<?php ' . var_export($info, TRUE), TRUE) .
+                   '<hr />Raw response: ' . $content);
+    return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
+  }
+
+  /*
+  ------------------------------------
+  HELPER METHODS
+  ------------------------------------
+  */
+
+  /**
+   * Parse header.
+   *
+   * @param type $content
+   * @return type
+   */
+  function parseHeader($content) {
     $info = curl_getinfo($this->curlHandle);
     $header = substr($content, 0, $info['header_size']);
-    $status = strtok($header, "\r\n");  
+    $header = str_replace("HTTP/1.1 100 Continue\r\n\r\n", '', $header);
+    $status = strtok($header, "\r\n");
     $code = $info['http_code'];
-    $body = substr($content, -$info['download_content_length']);  
-    $this->verbose('DELETE request to: ' . $url .
-                    'data: ' . $data .
-                   '<hr />Ending URL: ' . $this->getUrl() .
-                   '<hr />' . $content);
-    return array('header' => $header, 'status' => $status, 'code' => $code, 'body' => $body);
+    $body = unserialize(substr($content, -$info['download_content_length']));
+    return array($info, $header, $status, $code, $body);
   }
 
-   /*
-    ------------------------------------
-    HELPER METHODS
-    ------------------------------------
+  /**
+   * Creates a data array for populating an endpoint creation form.
+   *
+   * @return
+   * An array of fields for fully populating an endpoint creation form.
    */
+  public function populateEndpointFAPI() {
+    return array(
+      'name'   => 'machinename',
+      'title'  => $this->randomName(20),
+      'path'   => $this->randomName(10),
+      'server' => 'rest_server',
+      'services_use_content_permissions' => TRUE,
+    );
+  }
 
-   /**
-    * Creates a data array for populating an endpoint creation form.
-    *
-    * @return
-    * An array of fields for fully populating an endpoint creation form.
-    */
-   public function populateEndpointFAPI() {
-     return array(
-       'name'   => 'mchnname',
-       'title'  => $this->randomName(20),
-       'path'   => $this->randomName(10),
-       'server' => 'rest_server',
-       'services_use_content_permissions' => TRUE,
-     ) ;
-   }
-
-   public function saveNewEndpoint() {
+  public function saveNewEndpoint() {
     $edit = $this->populateEndpointFAPI() ;
     $endpoint = new stdClass;
     $endpoint->disabled = FALSE; /* Edit this to true to make a default endpoint disabled initially */
@@ -270,38 +331,63 @@
     $endpoint->status = 1;
     services_endpoint_save($endpoint);
     $endpoint = services_endpoint_load($endpoint->name);
-    if($endpoint->name == $edit['name']) {
-      $this->pass('Endpoint successfully created');  
-    } else {
-       $this->fail('Endpoint creation failed');  
+    $this->assertTrue($endpoint->name == $edit['name'], t('Endpoint successfully created'));
+    return $endpoint;
+  }
+
+  /**
+   * Performs a cURL exec with the specified options after calling curlConnect().
+   *
+   * @param $curl_options
+   *   Custom cURL options.
+   * @return
+   *   Content returned from the exec.
+   */
+  protected function curlExec($curl_options) {
+    $this->curlInitialize();
+    $url = empty($curl_options[CURLOPT_URL]) ? curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL) : $curl_options[CURLOPT_URL];
+    if (!empty($curl_options[CURLOPT_POST])) {
+      // This is a fix for the Curl library to prevent Expect: 100-continue
+      // headers in POST requests, that may cause unexpected HTTP response
+      // codes from some webservers (like lighttpd that returns a 417 error
+      // code). It is done by setting an empty "Expect" header field that is
+      // not overwritten by Curl.
+      $curl_options[CURLOPT_HTTPHEADER][] = 'Expect:';
+    }
+    curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
+
+    // Reset headers and the session ID.
+    $this->session_id = NULL;
+    $this->headers = array();
+
+    $this->drupalSetContent(curl_exec($this->curlHandle), curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL));
+
+    // Analyze the method for log message.
+    $method = '';
+    if (!empty($curl_options[CURLOPT_NOBODY])) {
+      $method = 'HEAD';
     }
-     $this->servicesGet($endpoint->path);
-     return $endpoint;
-   }
- /**
- * Builds out our post fields
- *
- */
-  public function services_build_postfields($data = array()) {
-    $post_data = '';  
-    if (is_array($data) && !empty($data)) {
-      array_walk($data, array($this, 'services_flatten_fields'));
-      $post_data = implode('&', $data);
+
+    if (empty($method) && !empty($curl_options[CURLOPT_PUT])) {
+      $method = 'PUT';
     }
-    if(is_object($data) && !empty($data)) {
-      array_walk(get_object_vars($data), array($this, 'services_flatten_fields'));
-      $post_data = implode('&', $data);
+
+    if (empty($method) && !empty($curl_options[CURLOPT_CUSTOMREQUEST])) {
+      $method = $curl_options[CURLOPT_CUSTOMREQUEST];
     }
-    return $post_data;
-  }
-/**
- * Modifies our array data so we can turn it into a querystring
- * 
- * @param string $item - array value
- * @param string $key  - key of the array element
- */
-  public function services_flatten_fields(&$item, $key) {
-    $item = $key .'='. $item;
+
+    if (empty($method)) {
+      $method = empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST';
+    }
+
+    $message_vars = array(
+      '!method' => $method,
+      '@url'    => $url,
+      '@status' => curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE),
+      '!length' => format_size(strlen($this->content))
+    );
+    $message = t('!method @url returned @status (!length).', $message_vars);
+    $this->assertTrue($this->content !== FALSE, $message, t('Browser'));
+    return $this->drupalGetContent();
   }
 }
-?>
\ No newline at end of file
