diff --git a/apachesolr.admin.inc b/apachesolr.admin.inc
index dd3425e..9fd810a 100644
--- a/apachesolr.admin.inc
+++ b/apachesolr.admin.inc
@@ -877,7 +877,6 @@ function apachesolr_index_action_form_delete_confirm_submit($form, &$form_state)
 
 /**
  * Submit a batch job to index the remaining, unindexed content.
- * @todo Make the env_id have an impact if we want multi environment indexing
  */
 function apachesolr_index_batch_index_remaining($env_id) {
   $batch = array(
diff --git a/apachesolr.info b/apachesolr.info
index a34f6ba..f8adc61 100644
--- a/apachesolr.info
+++ b/apachesolr.info
@@ -16,5 +16,8 @@ files[] = plugins/facetapi/query_type_date.inc
 files[] = plugins/facetapi/query_type_term.inc
 files[] = plugins/facetapi/query_type_numeric_range.inc
 files[] = tests/Dummy_Solr.php
+files[] = tests/apachesolr_base.test
 files[] = tests/solr_index_and_search.test
 files[] = tests/solr_base_query.test
+files[] = tests/solr_base_subquery.test
+files[] = tests/solr_document.test
diff --git a/apachesolr.interface.inc b/apachesolr.interface.inc
new file mode 100644
index 0000000..fb45c31
--- /dev/null
+++ b/apachesolr.interface.inc
@@ -0,0 +1,313 @@
+<?php
+
+/**
+ * The interface for all 'query' objects.
+ */
+interface DrupalSolrQueryInterface {
+  /**
+   * Returns all filters matching $name, if set; otherwise, returns all filters.
+   *
+   * @param string $name
+   *   The facet field name to match. If NULL, all filters will be returned.
+   *
+   * @return array
+   *   All matching filters.
+   */
+  function getFilters($name = NULL);
+
+  /**
+   * Tests whether a filter is already present in the query.
+   *
+   * @param string $name
+   *   The facet field name to check.
+   * @param string $value
+   *   The facet value to check.
+   * @param boolean $exclude
+   *   Optional, defaults to FALSE, must match the filter.
+   *
+   * @return boolean
+   *   TRUE or FALSE.
+   */
+  function hasFilter($name, $value, $exclude = FALSE);
+
+  /**
+   * Adds a filter to the query.
+   *
+   * @param string $name
+   *   The facet field name.
+   * @param string $value
+   *   The facet field value.
+   * @param boolean $exclude
+   *   Set to TRUE to filter out documents matching $value.
+   * @param string $local
+   *   Solr LocalParams.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function addFilter($name, $value, $exclude = FALSE, $local = '');
+
+  /**
+   * Removes a filter from the query.
+   *
+   * @param string $name
+   *   The name of the facet field to remove.
+   * @param string $value
+   *   The value of the facet field to remove. If NULL, all filters matching
+   *   $name are removed.
+   * @param boolean $exclude
+   *   If $value is not NULL, only filters matching both $value and $exclude are
+   *   removed. Ignored if $value is NULL.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function removeFilter($name, $value = NULL, $exclude = FALSE);
+
+  /**
+   * Returns all subqueries to the query.
+   *
+   * @return array
+   *   All subqueries to the query.
+   */
+  function getFilterSubQueries();
+
+  /**
+   * Adds a subquery to the query.
+   *
+   * @param SolrFilterSubQuery $query
+   *   The query to add to the orginal query - may have keywords or filters.
+   * @param string $fq_operator
+   *   The operator to use within the filter part of the subquery
+   * @param string $q_operator
+   *   The operator to use in joining the subquery to the main keywords. Note:
+   *   this is unlikely to work with the Dismax handler when the main query is
+   *   only keywords.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function addFilterSubQuery(SolrFilterSubQuery $query);
+
+  /**
+   * Removes a specific subquery.
+   *
+   * @param DrupalSolrQueryInterface $query
+   *   The query to remove.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function removeFilterSubQuery(SolrFilterSubQuery $query);
+
+  /**
+   * Removes all subqueries.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function removeFilterSubQueries();
+
+  /**
+   * Transforms a single filter in a form suitable for use in a Solr query.
+   *
+   * @param array $filter
+   *   A filter as an array with the keys '#name', for the facet field name,
+   *   '#value', for the facet field value, '#local', for Solr LocalParams, and
+       '#exclude' set to TRUE if it is an exclusion filter.
+   *
+   * @return string
+   *   A Solr fq parameter value.
+   */
+  function makeFilterQuery(array $filter);
+
+  /**
+   * Gets the value of a parameter.
+   *
+   * @param string $name
+   *   The parameter name.
+   *
+   * @return
+   *   The value of the parameter.
+   */
+  function getParam($name);
+
+  /**
+   * Gets all parameters in normalized form.
+   *
+   * @return array
+   *   All parameters as key-value pairs.
+   */
+  function getParams();
+
+  /**
+   * Gets parameters in a form suitable for use in a Solr query.
+   *
+   * @return array
+   *   All parameters as key-value pairs, where values have been transformed
+   *   into Solr parameter values.
+   */
+  function getSolrParams();
+
+  /**
+   * Adds a param to be sent when running the Solr search.
+   *
+   * If the param is single-valued, this will replace rather than add the value.
+   *
+   * @param string $name
+   *   A Solr param name, e.g. 'q' or 'fl'.
+   * @param $value
+   *   A Solr param value: an array of values, or a string for a single value.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function addParam($name, $value);
+
+  /**
+   * Adds multiple params to be sent when running the Solr search.
+   *
+   * If the param is single-valued, this will replace rather than add the value.
+   *
+   * @param $params
+   *   An array where the keys are param names, and the values may be strings or
+   *   arrays of strings.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function addParams(array $params);
+
+  /**
+   * Removes all values for one Solr param.
+   *
+   * @param string $name
+   *   A Solr param name, e.g. 'q' or 'fl'.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function removeParam($name);
+
+  /**
+   * Replaces a param to be sent when running the Solr search.
+   *
+   * Basically a shortcut for removeParam() plus addParam().
+   *
+   * @param string $name
+   *   A Solr param name, e.g. 'q' or 'fl'.
+   * @param $value
+   *   A Solr param value: an array of values, or a string for a single value.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function replaceParam($name, $value);
+
+  /**
+   * Handles aliases for field to make nicer URLs.
+   *
+   * @param $field_map
+   *   An array keyed with aliases with the real Solr index field name as value.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function addFieldAliases($field_map);
+
+  function getFieldAliases();
+
+  function clearFieldAliases();
+
+  function getAvailableSorts();
+
+  /**
+   * Adds an available sort.
+   *
+   * @param string $name
+   *  The name of the field in the Solr index to sort on.
+   * @param array $sort
+   *  An array with the keys 'title', for the human name of the sort, and
+   *  'default', for the default sort direction ('asc' or 'desc').
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function setAvailableSort($name, $sort);
+
+  /**
+   * Removes an available sort.
+   *
+   * @param string $name
+   *  The name of the field in the Solr index to sort on.
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function removeAvailableSort($name);
+
+  /**
+   * Gets the current sort.
+   *
+   * @return array
+   *   The current sort as an array with the keys '#name', for the name of
+   *   the field, and '#direction', for the sort direction ('asc' or 'desc').
+   */
+  function getSolrsort();
+
+  /**
+   * Sets the sort.
+   *
+   * @param string $field
+   *  The name of the field in the Solr index to sort on.
+   * @param string $direction
+   *  'asc' or 'desc'
+   *
+   * @return DrupalSolrQueryInterface
+   *   The called object.
+   */
+  function setSolrsort($name, $direction);
+
+  /**
+   * Returns an array representing the URL query string for the current sort.
+   *
+   * @return array
+   *   The URL query string for the current sort.
+   */
+  function getSolrsortUrlQuery();
+
+  /**
+   * Returns the search path (including the search keywords).
+   *
+   * @param string $new_keywords
+   *   Optional. When set, this string overrides the query's current keywords.
+   *
+   * @return string
+   *   The search path.
+   */
+  function getPath($new_keywords = NULL);
+
+  /**
+   * Sends the search request to Solr, unless $query->abort_search is TRUE.
+   *
+   * @param string $keys
+   *   The search keys.
+   *
+   * @return
+   *   A stdClass response object.
+   */
+  function search($keys = NULL);
+
+  /**
+   * Calls a method, without arguments, on the Solr object with which the query
+   * object was initialized.
+   *
+   * @param string $method
+   *   The method to call on the Solr object.
+   *
+   * @return
+   *   Any method return.
+   */
+  function solr($method);
+}
+
diff --git a/apachesolr.module b/apachesolr.module
index 8871e48..d8f4565 100644
--- a/apachesolr.module
+++ b/apachesolr.module
@@ -1398,8 +1398,17 @@ function apachesolr_static_response_cache($searcher, $response = NULL) {
  * @throws Exception
  */
 function apachesolr_drupal_query($name, $params = array(), $solrsort = '', $base_path = '', $solr = NULL) {
-  $class = variable_get('apachesolr_query_class', 'SolrBaseQuery');
-
+  if (!interface_exists('DrupalSolrQueryInterface')) {
+    require_once(dirname(__FILE__) . '/apachesolr.interface.inc');
+  }
+  $class_info = variable_get('apachesolr_query_class', array(
+    'file' => 'Solr_Base_Query',
+    'module' => 'apachesolr',
+    'class' => 'SolrBaseQuery'));
+  $class = $class_info['class'];
+  if (!class_exists($class_info['class']) && isset($class_info['file']) && isset($class_info['module'])) {
+    module_load_include('php', $class_info['module'], $class_info['file']);
+  }
   if (empty($solr)) {
     $solr = apachesolr_get_solr();
   }
@@ -1407,6 +1416,33 @@ function apachesolr_drupal_query($name, $params = array(), $solrsort = '', $base
 }
 
 /**
+ * Factory function for query objects.
+ *
+ * @param $operator
+ *   Wether the subquery should be added to another query as OR or AND
+ *
+ * @return
+ *   DrupalSolrQueryInterface object.
+ *
+ * @throws Exception
+ */
+function apachesolr_drupal_subquery($operator = 'OR') {
+  if (!interface_exists('DrupalSolrQueryInterface')) {
+    require_once(dirname(__FILE__) . '/apachesolr.interface.inc');
+  }
+
+  $class_info = variable_get('apachesolr_subquery_class', array(
+    'file' => 'Solr_Base_Query',
+    'module' => 'apachesolr',
+    'class' => 'SolrFilterSubQuery'));
+  $class = $class_info['class'];
+  if (!class_exists($class_info['class']) && isset($class_info['file']) && isset($class_info['module'])) {
+    module_load_include('php', $class_info['module'], $class_info['file']);
+  }
+  return new $class($operator);
+}
+
+/**
  * Static getter/setter for the current query. Only set once per page.
  */
 function apachesolr_current_query($env_id, DrupalSolrQueryInterface $query = NULL) {
@@ -2320,316 +2356,4 @@ function theme_apachesolr_settings_title($vars) {
   }
 
   return $output;
-}
-
-/**
- * The interface for all 'query' objects.
- */
-interface DrupalSolrQueryInterface {
-  /**
-   * Returns all filters matching $name, if set; otherwise, returns all filters.
-   *
-   * @param string $name
-   *   The facet field name to match. If NULL, all filters will be returned.
-   *
-   * @return array
-   *   All matching filters.
-   */
-  function getFilters($name = NULL);
-
-  /**
-   * Tests whether a filter is already present in the query.
-   *
-   * @param string $name
-   *   The facet field name to check.
-   * @param string $value
-   *   The facet value to check.
-   * @param boolean $exclude
-   *   Optional, defaults to FALSE, must match the filter.
-   *
-   * @return boolean
-   *   TRUE or FALSE.
-   */
-  function hasFilter($name, $value, $exclude = FALSE);
-
-  /**
-   * Adds a filter to the query.
-   *
-   * @param string $name
-   *   The facet field name.
-   * @param string $value
-   *   The facet field value.
-   * @param boolean $exclude
-   *   Set to TRUE to filter out documents matching $value.
-   * @param string $local
-   *   Solr LocalParams.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function addFilter($name, $value, $exclude = FALSE, $local = '');
-
-  /**
-   * Removes a filter from the query.
-   *
-   * @param string $name
-   *   The name of the facet field to remove.
-   * @param string $value
-   *   The value of the facet field to remove. If NULL, all filters matching
-   *   $name are removed.
-   * @param boolean $exclude
-   *   If $value is not NULL, only filters matching both $value and $exclude are
-   *   removed. Ignored if $value is NULL.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function removeFilter($name, $value = NULL, $exclude = FALSE);
-
-  /**
-   * Returns all subqueries to the query.
-   *
-   * @return array
-   *   All subqueries to the query.
-   */
-  function getFilterSubQueries();
-
-  /**
-   * Adds a subquery to the query.
-   *
-   * @param SolrFilterSubQuery $query
-   *   The query to add to the orginal query - may have keywords or filters.
-   * @param string $fq_operator
-   *   The operator to use within the filter part of the subquery
-   * @param string $q_operator
-   *   The operator to use in joining the subquery to the main keywords. Note:
-   *   this is unlikely to work with the Dismax handler when the main query is
-   *   only keywords.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function addFilterSubQuery(SolrFilterSubQuery $query);
-
-  /**
-   * Removes a specific subquery.
-   *
-   * @param DrupalSolrQueryInterface $query
-   *   The query to remove.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function removeFilterSubQuery(SolrFilterSubQuery $query);
-
-  /**
-   * Removes all subqueries.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function removeFilterSubQueries();
-
-  /**
-   * Transforms a single filter in a form suitable for use in a Solr query.
-   *
-   * @param array $filter
-   *   A filter as an array with the keys '#name', for the facet field name,
-   *   '#value', for the facet field value, '#local', for Solr LocalParams, and
-       '#exclude' set to TRUE if it is an exclusion filter.
-   *
-   * @return string
-   *   A Solr fq parameter value.
-   */
-  function makeFilterQuery(array $filter);
-
-  /**
-   * Gets the value of a parameter.
-   *
-   * @param string $name
-   *   The parameter name.
-   *
-   * @return
-   *   The value of the parameter.
-   */
-  function getParam($name);
-
-  /**
-   * Gets all parameters in normalized form.
-   *
-   * @return array
-   *   All parameters as key-value pairs.
-   */
-  function getParams();
-
-  /**
-   * Gets parameters in a form suitable for use in a Solr query.
-   *
-   * @return array
-   *   All parameters as key-value pairs, where values have been transformed
-   *   into Solr parameter values.
-   */
-  function getSolrParams();
-
-  /**
-   * Adds a param to be sent when running the Solr search.
-   *
-   * If the param is single-valued, this will replace rather than add the value.
-   *
-   * @param string $name
-   *   A Solr param name, e.g. 'q' or 'fl'.
-   * @param $value
-   *   A Solr param value: an array of values, or a string for a single value.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function addParam($name, $value);
-
-  /**
-   * Adds multiple params to be sent when running the Solr search.
-   *
-   * If the param is single-valued, this will replace rather than add the value.
-   *
-   * @param $params
-   *   An array where the keys are param names, and the values may be strings or
-   *   arrays of strings.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function addParams(array $params);
-
-  /**
-   * Removes all values for one Solr param.
-   *
-   * @param string $name
-   *   A Solr param name, e.g. 'q' or 'fl'.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function removeParam($name);
-
-  /**
-   * Replaces a param to be sent when running the Solr search.
-   *
-   * Basically a shortcut for removeParam() plus addParam().
-   *
-   * @param string $name
-   *   A Solr param name, e.g. 'q' or 'fl'.
-   * @param $value
-   *   A Solr param value: an array of values, or a string for a single value.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function replaceParam($name, $value);
-
-  /**
-   * Handles aliases for field to make nicer URLs.
-   *
-   * @param $field_map
-   *   An array keyed with aliases with the real Solr index field name as value.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function addFieldAliases($field_map);
-
-  function getFieldAliases();
-
-  function clearFieldAliases();
-
-  function getAvailableSorts();
-
-  /**
-   * Adds an available sort.
-   *
-   * @param string $name
-   *  The name of the field in the Solr index to sort on.
-   * @param array $sort
-   *  An array with the keys 'title', for the human name of the sort, and
-   *  'default', for the default sort direction ('asc' or 'desc').
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function setAvailableSort($name, $sort);
-
-  /**
-   * Removes an available sort.
-   *
-   * @param string $name
-   *  The name of the field in the Solr index to sort on.
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function removeAvailableSort($name);
-
-  /**
-   * Gets the current sort.
-   *
-   * @return array
-   *   The current sort as an array with the keys '#name', for the name of
-   *   the field, and '#direction', for the sort direction ('asc' or 'desc').
-   */
-  function getSolrsort();
-
-  /**
-   * Sets the sort.
-   *
-   * @param string $field
-   *  The name of the field in the Solr index to sort on.
-   * @param string $direction
-   *  'asc' or 'desc'
-   *
-   * @return DrupalSolrQueryInterface
-   *   The called object.
-   */
-  function setSolrsort($name, $direction);
-
-  /**
-   * Returns an array representing the URL query string for the current sort.
-   *
-   * @return array
-   *   The URL query string for the current sort.
-   */
-  function getSolrsortUrlQuery();
-
-  /**
-   * Returns the search path (including the search keywords).
-   *
-   * @param string $new_keywords
-   *   Optional. When set, this string overrides the query's current keywords.
-   *
-   * @return string
-   *   The search path.
-   */
-  function getPath($new_keywords = NULL);
-
-  /**
-   * Sends the search request to Solr, unless $query->abort_search is TRUE.
-   *
-   * @param string $keys
-   *   The search keys.
-   *
-   * @return
-   *   A stdClass response object.
-   */
-  function search($keys = NULL);
-
-  /**
-   * Calls a method, without arguments, on the Solr object with which the query
-   * object was initialized.
-   *
-   * @param string $method
-   *   The method to call on the Solr object.
-   *
-   * @return
-   *   Any method return.
-   */
-  function solr($method);
-}
-
+}
\ No newline at end of file
diff --git a/apachesolr_access/apachesolr_access.module b/apachesolr_access/apachesolr_access.module
index c3a47ac..3574179 100644
--- a/apachesolr_access/apachesolr_access.module
+++ b/apachesolr_access/apachesolr_access.module
@@ -39,7 +39,7 @@ function apachesolr_access_build_subquery($account) {
   if (!user_access('access content', $account)) {
     throw new Exception('No access');
   }
-  $node_access_query = new SolrFilterSubQuery();
+  $node_access_query = apachesolr_drupal_subquery();
   if (user_access('bypass node access', $account)) {
     // Access all content from the current site, or public content.
     $node_access_query->addFilter('access__all', 0);
diff --git a/apachesolr_search.admin.inc b/apachesolr_search.admin.inc
index 396608c..89f51a5 100644
--- a/apachesolr_search.admin.inc
+++ b/apachesolr_search.admin.inc
@@ -763,6 +763,7 @@ function apachesolr_search_result_bias_form($env_id) {
  * Form builder function to set query field weights.
  */
 function apachesolr_search_field_bias_form($fields, $env_id) {
+  $form = array();
   // get the current weights
   $defaults = array(
     'content' => '1.0',
diff --git a/apachesolr_search.module b/apachesolr_search.module
index 3dd46bc..551b85f 100644
--- a/apachesolr_search.module
+++ b/apachesolr_search.module
@@ -814,7 +814,8 @@ function apachesolr_search_conditions_default($search_page) {
     foreach($conditions['fq'] as $condition_id => $condition) {
       // If the user input does not pass our validation we do not allow
       // it to query solr
-      if (!SolrBaseQuery::validFilterValue($condition)) {
+      $test_query = apachesolr_drupal_subquery('Test');
+      if (!$test_query->validFilterValue($condition)) {
         unset($conditions['fq'][$condition_id]);
       }
     }
diff --git a/tests/apachesolr_base.test b/tests/apachesolr_base.test
new file mode 100644
index 0000000..ce11f3c
--- /dev/null
+++ b/tests/apachesolr_base.test
@@ -0,0 +1,385 @@
+<?php
+/**
+ * @file
+ *   Unit test class that provides tests for base functionality of the Apachesolr
+ *   Module without having the need of a Solr Server
+ */
+class DrupalSolrOfflineEnvironmentWebTestCase extends DrupalWebTestCase {
+  /**
+   * A global basic user who can search.
+   */
+  var $basic_user;
+
+  /**
+   * A global administrative user who can administer search.
+   */
+  var $admin_user;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Solr Search Environments',
+      'description' => 'Tests search environments functionality of the Solr module',
+      'group' => 'ApacheSolr',
+    );
+  }
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    parent::setUp('apachesolr', 'search', 'apachesolr_test');
+    // Create a basic user, which is subject to moderation.
+    $permissions = array(
+      'access content',
+      'search content',
+    );
+    $basic_user = $this->drupalCreateUser($permissions);
+
+    // Create an admin user that can bypass revision moderation.
+    $permissions = array(
+      'access content',
+      'search content',
+      'administer nodes',
+      'administer search',
+    );
+    $admin_user = $this->drupalCreateUser($permissions);
+
+    // Assign users to their test suite-wide properties.
+    $this->basic_user = $basic_user;
+    $this->admin_user = $admin_user;
+  }
+
+  /**
+   *	Asserts that the module was installed and that a notice appears that the server is offline
+   */
+  function testServerOffline() {
+    // Load the default server.
+    $env_id = apachesolr_default_environment();
+    $environment = apachesolr_environment_load($env_id);
+    $environment['url'] = 'http://localhost/solr/core_that_should_not_exist';
+    apachesolr_environment_save($environment);
+    $status = apachesolr_server_status($environment['url']);
+    $this->assertFalse($status, t('A false URL could not be loaded and is offline'));
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr');
+    $text = t('The server seems to be unavailable. Please verify the server settings');
+    $this->assertText($text, t('When checking the status of the server it gives the correct message to inform the user that the server is not reachable'));
+  }
+
+  /**
+   *	Asserts that the module was installed and that a notice appears that the server is offline
+   */
+  function testIndexFileIncluded() {
+    $paths = array(
+      'user',
+      'node',
+      'admin/config/search/apachesolr',
+      'admin/config/search/apachesolr/search-pages',
+      'admin/config/search/apachesolr/search-pages/core_search/edit',
+      'admin/structure/block/manage/apachesolr_search/mlt-001/configure',
+      'admin/config/search/apachesolr/settings/solr/bias',
+      'admin/config/search/apachesolr/settings/solr/index',
+      'admin/config/search/apachesolr/settings/solr/edit',
+      'admin/reports/apachesolr',
+      'admin/reports/apachesolr/conf',
+      'search/site',
+    );
+    $this->drupalLogin($this->admin_user);
+    foreach ($paths as $path) {
+      $this->drupalGet($path);
+      $text = 'apachesolr.index.inc was included';
+      $this->assertNoText($text, t('Apachesolr.index.inc was not included'));
+    }
+  }
+
+  /**
+   *	Asserts that we can edit a search environment
+   */
+  function testEditSearchEnvironment() {
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    $this->clickLink(t('Edit'));
+    $this->assertText(t('Example: http://localhost:8983/solr'), t('Edit page was succesfully loaded'));
+    $edit = array('name' => 'new description foo bar', 'url' => 'http://localhost:8983/solr/core_does_not_exists');
+    $this->drupalPost($this->getUrl(), $edit, t('Save'));
+    $this->assertResponse(200);
+    drupal_static_reset('apachesolr_load_all_environments');
+    drupal_static_reset('apachesolr_get_solr');
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    $this->assertText(t('new description foo bar'), t('Search environment description was succesfully edited'));
+    $this->assertText('http://localhost:8983/solr/core_does_not_exists', t('Search environment url was succesfully edited'));
+  }
+
+  /**
+   *	Asserts that we can edit a search environment
+   */
+  function testCloneSearchEnvironment() {
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    $this->assertText(t('Clone'), t('Clone button is available'));
+    $this->drupalGet('admin/config/search/apachesolr/settings/solr/clone');
+    $this->assertText(t('Are you sure you want to clone search environment localhost server'), t('Clone confirmation page was succesfully loaded'));
+    $this->drupalPost($this->getUrl(), array(), t('Clone'));
+    $this->assertResponse(200);
+    drupal_static_reset('apachesolr_load_all_environments');
+    drupal_static_reset('apachesolr_get_solr');
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    $this->assertText(t('localhost server [cloned]'), t('Search Environment was succesfully cloned'));
+  }
+
+  /**
+   *	Asserts that we can edit a search environment
+   */
+  function testCreateNewSearchEnvironment() {
+    // Create a new environment
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    $this->assertText(t('Add search environment'), t('Create new environment link is available'));
+    $this->clickLink(t('Add search environment'));
+    $this->assertText(t('Make this Solr search environment the default'), t('Environment creation page succesfully added'));
+    $edit = array('url' => 'http://localhost:8983/solr', 'name' => 'my test description', 'env_id' => 'solr_test');
+    $this->drupalPost($this->getUrl(), $edit, t('Save'));
+    $this->assertResponse(200);
+    drupal_static_reset('apachesolr_load_all_environments');
+    drupal_static_reset('apachesolr_get_solr');
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    $this->assertText(t('my test description'), t('Search Environment was succesfully created'));
+
+    // Make this new search environment the default
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    // Click on the second environment edit link
+    $this->clickLink(t('Edit'), 1);
+    $this->assertText(t('Example: http://localhost:8983/solr'), t('Edit page was succesfully loaded'));
+    $edit = array('make_default' => 1, 'conf[apachesolr_read_only]' => APACHESOLR_READ_ONLY);
+    $this->drupalPost($this->getUrl(), $edit, t('Save'));
+    $this->assertResponse(200);
+    drupal_static_reset('apachesolr_load_all_environments');
+    drupal_static_reset('apachesolr_get_solr');
+    $this->drupalGet('admin/config/search/apachesolr/settings');
+    $this->assertText(t('my test description (Default)'), t('New Search environment was succesfully changed to default environment'));
+    // Load it, to fill our cache.
+    apachesolr_environment_load('solr_test');
+    $mode = apachesolr_environment_variable_get('solr_test', 'apachesolr_read_only', APACHESOLR_READ_WRITE);
+    $this->assertEqual($mode, APACHESOLR_READ_ONLY, t('Environment succesfully changed to read only'));
+  }
+
+  function tearDown() {
+    parent::tearDown();
+  }
+}
+
+/**
+ * @file
+ *   Unit test class that provides tests for base functionality of the Apachesolr
+ *   Module without having the need of a Solr Server
+ */
+class DrupalSolrOfflineSearchPagesWebTestCase extends DrupalWebTestCase {
+  /**
+   * A global basic user who can search.
+   */
+  var $basic_user;
+
+  /**
+   * A global administrative user who can administer search.
+   */
+  var $admin_user;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Solr Search Pages',
+      'description' => 'Tests search pages functionality of the Solr module',
+      'group' => 'ApacheSolr',
+    );
+  }
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    parent::setUp('apachesolr', 'apachesolr_search', 'search', 'apachesolr_test');
+    // Create a basic user, which is subject to moderation.
+    $permissions = array(
+      'access content',
+      'search content',
+    );
+    $basic_user = $this->drupalCreateUser($permissions);
+
+    // Create an admin user that can bypass revision moderation.
+    $permissions = array(
+      'access content',
+      'search content',
+      'administer nodes',
+      'administer search',
+    );
+    $admin_user = $this->drupalCreateUser($permissions);
+
+    // Assign users to their test suite-wide properties.
+    $this->basic_user = $basic_user;
+    $this->admin_user = $admin_user;
+  }
+
+  /**
+   *	Asserts that we can edit a search environment
+   */
+  function testCheckCoreSearchPage() {
+    // Create a new environment
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->assertText(t('Core Search'), t('Core Search page is available'));
+  }
+
+  /**
+   *	Asserts that we can edit a search environment
+   */
+  function testEditSearchPage() {
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->clickLink(t('Edit'));
+    $this->assertText(t('The human-readable name of the search page configuration'), t('Edit page was succesfully loaded'));
+    $edit = array(
+      'label' => 'Test Search Page',
+      'description' => 'Test Description',
+      'page_title' => 'Test Title',
+      'search_path' => 'search/searchdifferentpath',
+    );
+    $this->drupalPost($this->getUrl(), $edit, t('Save configuration'));
+    $this->assertResponse(200);
+    // Make sure the menu is recognized
+    drupal_static_reset('apachesolr_search_page_load');
+    menu_cache_clear_all();
+    menu_rebuild();
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->assertText(t('Test Search Page'), t('Search page was succesfully edited'));
+    $this->assertText('search/searchdifferentpath', t('Search path was updated'));
+    $this->drupalGet('search/searchdifferentpath');
+    $this->assertText(t('The Apache Solr search engine is not available. Please contact your site administrator.'), t('Search path was sucessfully created and is accessible'));
+  }
+
+  /**
+   *	Asserts that we can edit a search environment
+   */
+  function testCloneSearchPage() {
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->assertText(t('Clone'), t('Clone button is available'));
+    $this->drupalGet('admin/config/search/apachesolr/search-pages/core_search/clone');
+    $this->assertText(t('Are you sure you want to clone search page Core Search?'), t('Clone confirmation page was succesfully loaded'));
+    $this->drupalPost($this->getUrl(), array(), t('Clone'));
+    $this->assertResponse(200);
+    drupal_static_reset('apachesolr_search_page_load');
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->assertText(t('Core Search [cloned]'), t('Search Environment was succesfully cloned'));
+  }
+
+  /**
+   *	Asserts that we can edit a search environment
+   */
+  function testNewAndRemoveSearchPage() {
+    // Create a new search page
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->assertText(t('Add search page'), t('Create new search page link is available'));
+    $this->clickLink(t('Add search page'));
+    $this->assertText(t('The human-readable name of the search page configuration.'), t('Search page creation page succesfully added'));
+    $edit = array(
+      'page_id' => 'solr_testingsuite',
+      'env_id' => 'solr',
+      'label' => 'Test Search Page',
+      'description' => 'Test Description',
+      'page_title' => 'Test Title',
+      'search_path' => 'search/searchdifferentpath',
+    );
+    $this->drupalPost($this->getUrl(), $edit, t('Save configuration'));
+    $this->assertResponse(200);
+    // Make sure the menu is recognized
+    drupal_static_reset('apachesolr_search_page_load');
+    menu_cache_clear_all();
+    menu_rebuild();
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->assertText(t('Test Search Page'), t('Search Page was succesfully created'));
+
+    // Remove the same environment
+    $this->clickLink(t('Delete'));
+    $this->assertText(t('search page configuration will be deleted.This action cannot be undone.'), t('Delete confirmation page was succesfully loaded'));
+    $this->drupalPost($this->getUrl(), array(), t('Delete page'));
+    $this->assertResponse(200);
+    drupal_static_reset('apachesolr_search_page_load');
+    $this->drupalGet('admin/config/search/apachesolr/search-pages');
+    $this->assertNoText(t('Test Search Page'), t('Search Environment was succesfully deleted'));
+  }
+
+  function tearDown() {
+    parent::tearDown();
+  }
+}
+
+class DrupalSolrOfflineUnitTestCase extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Solr Base Framework Tests Unit Test',
+      'description' => 'Unit test functionality of the Solr module',
+      'group' => 'ApacheSolr',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+    require_once dirname(dirname(realpath(__FILE__))) . '/apachesolr.module';
+
+    $this->script_content = <<<EOF
+<p>GOOD_CONTENT</p>
+<script type="text/javascript" >
+$(document).ready(function(){
+  $('.accordion_teachers').accordion({ collapsible:true, autoHeight:false });
+});
+</script>
+
+EOF;
+
+    $this->embed_content = <<<EOF
+<p>GOOD_CONTENT</p>
+<object width="425" height="349"><param name="movie" value="http://www.youtube.com/v/8Vmnq5dBF7Y?version=3&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/8Vmnq5dBF7Y?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="425" height="349" allowscriptaccess="always" allowfullscreen="true"></embed></object>
+OTHER_CONTENT
+
+EOF;
+
+    $this->iframe_content = <<<EOF
+<iframe width="425" height="349" src="http://www.youtube.com/embed/8Vmnq5dBF7Y" frameborder="0" allowfullscreen></iframe>
+<p><a href="#">GOOD_CONTENT</a></p><iframe></iframe>
+
+EOF;
+
+    $this->comment_content = <<<EOF
+<p><em>GOOD_CONTENT</em></p><!-- COMMENT -->
+OTHER_CONTENT
+
+EOF;
+  }
+
+  /**
+   * Test ordering of parsed filter positions.
+   *
+   * Regression test for http://drupal.org/node/891962
+   */
+  function testContentFilters() {
+    $cleaned = apachesolr_clean_text($this->script_content);
+    $this->assertFalse(strpos($cleaned, 'script'), 'Script tags removed');
+    $this->assertFalse(strpos($cleaned, 'accordion_teachers'), 'Script tags conent removed');
+    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
+
+    $cleaned = apachesolr_clean_text($this->embed_content);
+    $this->assertFalse(strpos($cleaned, 'object'), 'object tags removed');
+    $this->assertFalse(strpos($cleaned, 'embed'), 'embed tags removed');
+    $this->assertFalse(strpos($cleaned, '8Vmnq5dBF7Y'), 'object tags conent removed');
+    $this->assertFalse(strpos($cleaned, 'shockwave-flash'), 'embed tags conent removed');
+    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
+    $this->assertTrue(strpos($cleaned, 'OTHER_CONTENT') > 0, 'Other content retained');
+
+    $cleaned = apachesolr_clean_text($this->iframe_content);
+    $this->assertFalse(strpos($cleaned, 'iframe'), 'iframe tags removed');
+    $this->assertFalse(strpos($cleaned, '8Vmnq5dBF7Y'), 'iframe tags conent removed');
+    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
+
+    $cleaned = apachesolr_clean_text($this->comment_content);
+    $this->assertFalse(strpos($cleaned, 'COMMENT'), 'html comment content removed ');
+    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
+  }
+}
\ No newline at end of file
diff --git a/tests/apachesolr_test/apachesolr_test.info b/tests/apachesolr_test/apachesolr_test.info
new file mode 100644
index 0000000..50b2549
--- /dev/null
+++ b/tests/apachesolr_test/apachesolr_test.info
@@ -0,0 +1,5 @@
+name = Apache Solr helper module for tests
+description = Support module for apachesolr module testing.
+package = Search Toolkit
+core = 7.x
+hidden = TRUE
diff --git a/tests/apachesolr_test/apachesolr_test.module b/tests/apachesolr_test/apachesolr_test.module
new file mode 100644
index 0000000..d4cc898
--- /dev/null
+++ b/tests/apachesolr_test/apachesolr_test.module
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * Implements hook_page_alter().
+ *
+ */
+function apachesolr_test_page_alter(&$page) {
+  $included_files = get_included_files();
+  $filename = dirname(dirname(dirname(realpath(__FILE__)))) . '/apachesolr.index.inc';
+  if (in_array($filename, $included_files)) {
+    $page['page_bottom']['solr']= array(
+      '#type' => 'markup',
+      '#markup' => 'apachesolr.index.inc was included',
+    );
+  }
+}
\ No newline at end of file
diff --git a/tests/solr_base_query.test b/tests/solr_base_query.test
index 5968b60..b3a5600 100644
--- a/tests/solr_base_query.test
+++ b/tests/solr_base_query.test
@@ -1,99 +1,37 @@
 <?php
 
 /**
- * @file
- *   Unit tests for query object methods.
- *
- *
+ * Unit tests for query object methods.
  */
-class SolrIndexHelperTests extends DrupalUnitTestCase {
+class SolrBaseQueryTests extends DrupalUnitTestCase {
   public static function getInfo() {
-    return array(
-      'name' => 'Indexing helper functionality',
-      'description' => 'Unit test of text parsing/cleaning',
+        return array(
+      'name' => 'SolrBaseQuery Unit tests',
+      'description' => 'Unit Tests for queries.',
       'group' => 'ApacheSolr',
     );
   }
 
-  protected function setUp() {
+  function setUp() {
     parent::setUp();
     require_once dirname(dirname(realpath(__FILE__))) . '/apachesolr.module';
-
-    $this->script_content = <<<EOF
-<p>GOOD_CONTENT</p>
-<script type="text/javascript" >
-$(document).ready(function(){
-  $('.accordion_teachers').accordion({ collapsible:true, autoHeight:false });
-});
-</script>
-
-EOF;
-
-    $this->embed_content = <<<EOF
-<p>GOOD_CONTENT</p>
-<object width="425" height="349"><param name="movie" value="http://www.youtube.com/v/8Vmnq5dBF7Y?version=3&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/8Vmnq5dBF7Y?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="425" height="349" allowscriptaccess="always" allowfullscreen="true"></embed></object>
-OTHER_CONTENT
-
-EOF;
-
-    $this->iframe_content = <<<EOF
-<iframe width="425" height="349" src="http://www.youtube.com/embed/8Vmnq5dBF7Y" frameborder="0" allowfullscreen></iframe>
-<p><a href="#">GOOD_CONTENT</a></p><iframe></iframe>
-
-EOF;
-
-    $this->comment_content = <<<EOF
-<p><em>GOOD_CONTENT</em></p><!-- COMMENT -->
-OTHER_CONTENT
-
-EOF;
+    require_once dirname(dirname(realpath(__FILE__))) . '/apachesolr.interface.inc';
+    require_once dirname(dirname(realpath(__FILE__))) . '/Solr_Base_Query.php';
+    require_once dirname(dirname(realpath(__FILE__))) . '/Drupal_Apache_Solr_Service.php';
   }
 
   /**
-   * Test ordering of parsed filter positions.
-   *
-   * Regression test for http://drupal.org/node/891962
+   * Helper function to simulate the auto loading and other non-needed functions
+   * that otherwise require a database
+   * @see apachesolr_drupal_query().
+   * @return SolrBaseQuery
    */
-  function testContentFilters() {
-    $cleaned = apachesolr_clean_text($this->script_content);
-    $this->assertFalse(strpos($cleaned, 'script'), 'Script tags removed');
-    $this->assertFalse(strpos($cleaned, 'accordion_teachers'), 'Script tags conent removed');
-    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
-
-    $cleaned = apachesolr_clean_text($this->embed_content);
-    $this->assertFalse(strpos($cleaned, 'object'), 'object tags removed');
-    $this->assertFalse(strpos($cleaned, 'embed'), 'embed tags removed');
-    $this->assertFalse(strpos($cleaned, '8Vmnq5dBF7Y'), 'object tags conent removed');
-    $this->assertFalse(strpos($cleaned, 'shockwave-flash'), 'embed tags conent removed');
-    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
-    $this->assertTrue(strpos($cleaned, 'OTHER_CONTENT') > 0, 'Other content retained');
-
-    $cleaned = apachesolr_clean_text($this->iframe_content);
-    $this->assertFalse(strpos($cleaned, 'iframe'), 'iframe tags removed');
-    $this->assertFalse(strpos($cleaned, '8Vmnq5dBF7Y'), 'iframe tags conent removed');
-    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
-
-    $cleaned = apachesolr_clean_text($this->comment_content);
-    $this->assertFalse(strpos($cleaned, 'COMMENT'), 'html comment content removed ');
-    $this->assertTrue(strpos(trim($cleaned), 'GOOD_CONTENT') === 0, 'Real content retained');
-  }
-
-}
-
-/**
- * Unit tests for query object methods.
- */
-class SolrBaseQueryTests extends DrupalWebTestCase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Query object base functionality',
-      'description' => 'Tests SolrBaseQuery methods',
-      'group' => 'ApacheSolr',
-    );
+  private function _apachesolr_drupal_query($name, $params = array(), $solrsort = '', $base_path = '', $solr = 'DrupalApacheSolrService') {
+    return new SolrBaseQuery($name, $solr, $params, $solrsort, $base_path);
   }
 
-  protected function setUp() {
-    parent::setUp('search', 'apachesolr');
+  private function _apachesolr_drupal_subquery($operator = 'OR') {
+    return new SolrFilterSubQuery($operator);
   }
 
   /**
@@ -104,7 +42,7 @@ class SolrBaseQueryTests extends DrupalWebTestCase {
   function testParseFilters() {
     $fq = array('tid:3', 'sort_label:hello', 'tid:11', 'tid:1', 'tid:12', 'label:hello');
     // Setup dummy Solr object.
-    $query = new SolrBaseQuery("apachesolr_tests", new DummySolr(), array('q' => 'mykeys', 'fq' => $fq), 'sort_label asc', 'search/test');
+    $query = $this->_apachesolr_drupal_query("apachesolr_tests", array('q' => 'mykeys', 'fq' => $fq), 'sort_label asc', 'search/test');
     // Check sortsort
     $this->assertEqual(array('solrsort' => 'sort_label asc'), $query->getSolrsortUrlQuery());
     $query->setSolrsort('sort_name', 'desc');
@@ -137,12 +75,12 @@ class SolrBaseQueryTests extends DrupalWebTestCase {
     $this->assertEqual(count($filters), 2, count($filters) . ' filters found, expected 2 filters');
     $this->assertEqual(array('sort_label:hello', 'label:hello'), $query->getParam('fq'));
 
-    $subquery = new SolrFilterSubQuery();
+    $subquery = $this->_apachesolr_drupal_subquery();
     $subquery->addFilter('access__all', 0);
-    $subquery->addFilter('hash', apachesolr_site_hash());
+    $subquery->addFilter('hash', 'randomhash');
     $query->addFilterSubQuery($subquery);
     $this->assertEqual(count($query->getParam('fq')), 3, count($query->getParam('fq')) . ' fq params found, expected 3 after adding subquery');
-    $this->assertEqual(array('sort_label:hello', 'label:hello', '(access__all:0 OR hash:' . apachesolr_site_hash() . ')'), $query->getParam('fq'));
+    $this->assertEqual(array('sort_label:hello', 'label:hello', '(access__all:0 OR hash:randomhash' . ')'), $query->getParam('fq'));
   }
 
   function testAddParams() {
@@ -208,7 +146,7 @@ class SolrBaseQueryTests extends DrupalWebTestCase {
       '#value' => '[1970-12-31T23:59:59Z TO NOW]',
     );
 
-    $query = new SolrBaseQuery("apachesolr_tests", new DummySolr());
+    $query = $this->_apachesolr_drupal_query("apachesolr_tests");
     foreach ($examples as $fq => $example) {
       $name = (!empty($example['#name'])) ? $example['#name'] : '_QUERY_';
       $value = (!empty($example['#value'])) ? $example['#value'] : '_VALUE_';
diff --git a/tests/solr_base_subquery.test b/tests/solr_base_subquery.test
index 8094b43..e7d916a 100644
--- a/tests/solr_base_subquery.test
+++ b/tests/solr_base_subquery.test
@@ -4,61 +4,102 @@
  * @file
  *   Unit tests for subquery object methods.
  */
-class DrupalSolrSubQueryTests extends DrupalWebTestCase {
+class DrupalSolrFilterSubQueryTests extends DrupalUnitTestCase {
+
   public static function getInfo() {
     return array(
-      'name' => 'Subquery handling',
-      'description' => 'Tests for subqueries.',
+      'name' => 'SolrFilterSubQuery Unit tests',
+      'description' => 'Unit Tests for subqueries.',
       'group' => 'ApacheSolr',
     );
   }
 
   function setUp() {
-    parent::setUp('search', 'apachesolr');
+    parent::setUp();
+    require_once dirname(dirname(realpath(__FILE__))) . '/apachesolr.module';
+    require_once dirname(dirname(realpath(__FILE__))) . '/apachesolr.interface.inc';
+    require_once dirname(dirname(realpath(__FILE__))) . '/Solr_Base_Query.php';
+    require_once dirname(dirname(realpath(__FILE__))) . '/Drupal_Apache_Solr_Service.php';
+  }
+
+  /**
+   * Helper function to simulate the auto loading and other non-needed functions
+   * that otherwise require a database
+   * @see apachesolr_drupal_query().
+   * @return SolrBaseQuery
+   */
+  private function _apachesolr_drupal_query($name, $params = array(), $solrsort = '', $base_path = '', $solr = 'DrupalApacheSolrService') {
+    return new SolrBaseQuery($name, $solr, $params, $solrsort, $base_path);
+  }
+
+  private function _apachesolr_drupal_subquery($operator = 'OR') {
+    return new SolrFilterSubQuery($operator);
   }
 
   function testSubQueriesQuery() {
-    $query1 = apachesolr_drupal_query('foo');
-    $query2 = apachesolr_drupal_query('bar');
-    $query3 = apachesolr_drupal_query('baz');
+    $query1 = $this->_apachesolr_drupal_query('DrupalTest');
+    $query1->addFilter('label', 'foo');
 
-    $query1->add_subquery($query2);
-    $this->assertEqual($query1->get_query_basic(), 'foo AND (bar)', 'foo AND (bar)');
+    $query2 = $this->_apachesolr_drupal_subquery();
+    $query2->addFilter('label', 'bar');
 
-    $query1->remove_subquery($query2);
-    $this->assertEqual($query1->get_query_basic(), 'foo', t('Remove bar query'));
+    $query3 = $this->_apachesolr_drupal_subquery();
+    $query3->addFilter('label', 'baz');
 
-    $query1->add_subquery($query2);
-    $query1->add_subquery($query2);
-    $query1->add_subquery($query2);
-    $this->assertEqual($query1->get_query_basic(), 'foo AND (bar)', t('Add bar several times; should only appear once.'));
+    $query1->addFilterSubQuery($query2);
+    $params = $query1->getParam('fq');
+    $this->assertEqual($params[0], 'label:foo', t('First field should be label:foo'));
+    $this->assertEqual($params[1], '(label:bar)', t('Second field should be label:bar'));
 
-    $query1->remove_subquery($query2);
-    $query1->add_subquery($query2, '', 'OR');
-    $this->assertEqual($query1->get_query_basic(), 'foo OR (bar)', 'foo OR (bar)');
+    $query1->removeFilterSubQuery($query2);
+    $params = $query1->getParam('fq');
+    $this->assertFalse(isset($params[1]), t('Second field should be empty'));
 
-    $query1->add_subquery($query3);
-    $query1->remove_subquery($query2);
-    $this->assertEqual($query1->get_query_basic(), 'foo AND (baz)', 'foo AND (baz)');
-  }
+    $query1->addFilterSubQuery($query2);
+    $query1->addFilterSubQuery($query2);
+    $query1->addFilterSubQuery($query2);
+    $params = $query1->getParam('fq');
+    $this->assertEqual($params[0], 'label:foo', t('First field should be label:foo'));
+    $this->assertEqual($params[1], '(label:bar)', t('Second field should be label:bar'));
+    $this->assertEqual(count($params), 2, t('Add bar several times; should only appear once.'));
+
+    // Empty out query1
+    $query1 = $this->_apachesolr_drupal_query('DrupalTest');
+    $query2 = $this->_apachesolr_drupal_subquery('DrupalTest');
+    $query2->operator = 'OR';
+    $query2->addFilter('label', 'bar');
+    $query2->addFilter('label', 'baz');
+    $query1->addFilterSubQuery($query2);
+    $params = $query1->getParam('fq');
+    $this->assertEqual($params[0], '(label:bar OR label:baz)', '(label:bar OR label:baz)');
+
+    // Empty out query1
+    $query1 = $this->_apachesolr_drupal_query('DrupalTest');
+    $query2 = $this->_apachesolr_drupal_subquery('DrupalTest');
+    $query2->operator = 'AND';
+    $query2->addFilter('label', 'bar');
+    $query2->addFilter('label', 'baz');
+    $query1->addFilterSubQuery($query2);
+    $params = $query1->getParam('fq');
+    $this->assertEqual($params[0], '(label:bar AND label:baz)', '(label:bar AND label:baz)');
 
-  function testSubQueriesFilter() {
-    $query1 = apachesolr_drupal_query('', 'is_uid:1 tid:5');
-    $query2 = apachesolr_drupal_query('', 'is_uid:10');
-    $query3 = apachesolr_drupal_query('', 'is_uid:2');
-    $query4 = apachesolr_drupal_query('', 'label:baz');
+    // Test with multiple filters in first query
+    $query1 = $this->_apachesolr_drupal_query('DrupalTest');
+    $query1->addFilter('is_uid', '10');
 
-    $query2->add_subquery($query1, 'OR');
-    $queryvalues = $query2->get_url_queryvalues();
-    $this->assertEqual($queryvalues, array('filters' => 'is_uid:10 (is_uid:1 OR tid:5)'));
+    $query2 = $this->_apachesolr_drupal_subquery();
+    $query2->addFilter('is_uid', '1');
+    $query2->addFilter('tid', '5');
+    $query1->addFilterSubQuery($query2);
 
-    $query3->add_subquery($query1, 'AND');
-    $query3->add_subquery($query4);
-    $queryvalues = $query3->get_url_queryvalues();
-    $this->assertEqual($queryvalues, array('filters' => 'is_uid:2 (is_uid:1 AND tid:5)'));
+    $params = $query1->getParam('fq');
+    $this->assertEqual($params[0], 'is_uid:10', 'First field value is is_uid:10');
+    $this->assertEqual($params[1], '(is_uid:1 OR tid:5)', 'Second field value is (is_uid:1 OR tid:5)');
 
-    $query3->remove_subquery($query1);
-    $queryvalues = $query3->get_url_queryvalues();
-    $this->assertEqual($queryvalues, array('filters' => 'is_uid:2 (label:baz)'));
+    $query2->operator = 'AND';
+    $query1->addFilterSubQuery($query2);
+    $params = $query1->getParam('fq');
+    $this->assertEqual($params[0], 'is_uid:10', 'First field value is is_uid:10');
+    $this->assertEqual($params[1], '(is_uid:1 AND tid:5)', 'Second field value is (is_uid:1 AND tid:5)');
   }
 }
diff --git a/tests/solr_document.test b/tests/solr_document.test
new file mode 100644
index 0000000..8b2a833
--- /dev/null
+++ b/tests/solr_document.test
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ *   Unit tests for query object methods.
+ *
+ *
+ */
+class DrupalSolrDocumentTest extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'ApacheSolrDocument Unit tests',
+      'description' => 'Unit test of ApacheSolrDocument',
+      'group' => 'ApacheSolr',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+    require_once dirname(dirname(realpath(__FILE__))) . '/apachesolr.module';
+    require_once dirname(dirname(realpath(__FILE__))) . '/Apache_Solr_Document.php';
+  }
+
+  function testSolrDocument() {
+    $document = new ApacheSolrDocument();
+
+    $document->addField('ss_testing', 'testingvalue');
+    $field_value = $document->getField('ss_testing');
+    $this->assertEqual($field_value['value'][0], 'testingvalue', t('The field was correctly added and verified'));
+    $document->clear();
+
+    $document->addField('ss_testing', 'testingvalue', 10);
+    $field_value = $document->getField('ss_testing');
+    $this->assertEqual($field_value['value'][0], 'testingvalue', t('The field and boost were correctly added and verified'));
+    $field_boost = $document->getFieldBoost('ss_testing');
+    $this->assertEqual($field_boost, 10, t('The field boost was correctly added and verified'));
+    $document->clear();
+
+    $document->setMultiValue('sm_testing', 'testingvalue1');
+    $document->setMultiValue('sm_testing', 'testingvalue2');
+    $field_value = $document->getField('sm_testing');
+    $this->assertTrue(in_array('testingvalue1', $field_value['value']), t('The multivalued field value was correctly added and verified'));
+    $this->assertTrue(in_array('testingvalue2', $field_value['value']), t('The second multivalued field value was correctly added and verified'));
+    $document->clear();
+
+    $document->setMultiValue('sm_testing', 'testingvalue1', 10);
+    $document->setMultiValue('sm_testing', 'testingvalue2', 20);
+    $field_value = $document->getField('sm_testing');
+    $this->assertTrue(in_array('testingvalue1', $field_value['value']), t('The multivalued field value and boost were correctly added and verified'));
+    $this->assertTrue(in_array('testingvalue2', $field_value['value']), t('The second multivalued field value and boost were correctly added and verified'));
+    $field_boost = $document->getFieldBoost('sm_testing');
+    $this->assertEqual($field_boost, 200, t('The field boost was correctly multiplied and retrieved'));
+
+    $document_field_names = $document->getFieldNames();
+    $this->assertTrue(in_array('sm_testing', $document_field_names), t('The field name was found in the document'));
+
+    $document_field_names = $document->getFieldValues();
+    $this->assertTrue(in_array('testingvalue1', $document_field_names[0]), t('The field value was found in the document'));
+
+    // Clear the complete document
+    $document->clear();
+
+    // Set and Get the document boost
+    $document->setBoost('10');
+    $document_boost = $document->getBoost();
+    $this->assertEqual($document_boost, 10, t('The document boost was correctly added and verified'));
+
+    $document->clear();
+    $document_boost = $document->getBoost();
+    $document_fields = $document->getFieldNames();
+    $document_field_boosts = $document->getFieldBoosts();
+    $this->assertFalse($document_boost, t('Document boost was succesfully emptied'));
+    $this->assertFalse($document_fields, t('Document fields were succesfully emptied'));
+    $this->assertFalse($document_field_boosts, t('Document field boosts were succesfully emptied'));
+  }
+
+  function tearDown() {
+    parent::tearDown();
+  }
+}
diff --git a/tests/solr_index_and_search.test b/tests/solr_index_and_search.test
index 0f74516..a41bd8f 100755
--- a/tests/solr_index_and_search.test
+++ b/tests/solr_index_and_search.test
@@ -1,12 +1,6 @@
 <?php
 
-/**
- * @file
- *   Unit test class that provides the setUp and tearDown of a solr core on the
- *   default localhost server. This server must be configured for multiple cores
- *   with a solr.xml file.
- */
-class DrupalSolrWebTestCase extends DrupalWebTestCase {
+class DrupalSolrOnlineWebTestCase extends DrupalWebTestCase {
   /**
    * Implementation of setUp().
    */
@@ -105,10 +99,10 @@ class DrupalSolrWebTestCase extends DrupalWebTestCase {
   }
 }
 
-class DrupalSolrMatchTestCase extends DrupalSolrWebTestCase {
+class DrupalSolrMatchTestCase extends DrupalSolrOnlineWebTestCase {
   public static function getInfo() {
     return array(
-      'name' => 'Solr Index Queries',
+      'name' => 'Solr Index Data and test live queries',
       'description' => 'Indexes content and queries it.',
       'group' => 'ApacheSolr',
     );
