fs-test.c

来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,863 行 · 第 1/5 页

C
1,863
字号
/* fs-test.c --- tests for the filesystem
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */

#include <stdlib.h>
#include <string.h>
#include <apr_pools.h>
#include <apr_time.h>
#include <apr_md5.h>

#include "svn_pools.h"
#include "svn_error.h"
#include "svn_time.h"
#include "svn_fs.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_md5.h"

#include "../fs-helpers.h"

#include "../../libsvn_fs/fs-loader.h"

#include "../../libsvn_fs_base/fs.h"
#include "../../libsvn_fs_base/dag.h"
#include "../../libsvn_fs_base/node-rev.h"
#include "../../libsvn_fs_base/trail.h"

#include "../../libsvn_fs_base/bdb/rev-table.h"
#include "../../libsvn_fs_base/bdb/txn-table.h"
#include "../../libsvn_fs_base/bdb/nodes-table.h"

#include "../../libsvn_delta/delta.h"

#define SET_STR(ps, s) ((ps)->data = (s), (ps)->len = strlen(s))


/*-----------------------------------------------------------------*/

/** The actual fs-tests called by `make check` **/

/* Create a filesystem.  */
static svn_error_t *
create_berkeley_filesystem (const char **msg,
                            svn_boolean_t msg_only,
                            apr_pool_t *pool)
{
  svn_fs_t *fs;

  *msg = "svn_fs_create_berkeley";

  if (msg_only)
    return SVN_NO_ERROR;

  /* Create and close a repository. */
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-berkeley", pool));
  
  return SVN_NO_ERROR;
}


/* Generic Berkeley DB error handler function. */
static void
berkeley_error_handler (const char *errpfx, char *msg)
{
  fprintf (stderr, "%s%s\n", errpfx ? errpfx : "", msg);
}


/* Helper:  commit TXN, expecting either success or failure:
 *
 * If EXPECTED_CONFLICT is null, then the commit is expected to
 * succeed.  If it does succeed, set *NEW_REV to the new revision;
 * else return error.
 *
 * If EXPECTED_CONFLICT is non-null, it is either the empty string or
 * the expected path of the conflict.  If it is the empty string, any
 * conflict is acceptable.  If it is a non-empty string, the commit
 * must fail due to conflict, and the conflict path must match
 * EXPECTED_CONFLICT.  If they don't match, return error.
 *
 * If a conflict is expected but the commit succeeds anyway, return
 * error.
 */
static svn_error_t *
test_commit_txn (svn_revnum_t *new_rev,
                 svn_fs_txn_t *txn,
                 const char *expected_conflict,
                 apr_pool_t *pool)
{
  const char *conflict;
  svn_error_t *err;

  err = svn_fs_commit_txn (&conflict, new_rev, txn, pool);

  if (err && (err->apr_err == SVN_ERR_FS_CONFLICT))
    {
      if (! expected_conflict)
        {
          return svn_error_createf
            (SVN_ERR_FS_CONFLICT, NULL,
             "commit conflicted at '%s', but no conflict expected",
             conflict ? conflict : "(missing conflict info!)");
        }
      else if (conflict == NULL)
        {
          return svn_error_createf
            (SVN_ERR_FS_CONFLICT, NULL,
             "commit conflicted as expected, "
             "but no conflict path was returned ('%s' expected)",
             expected_conflict);
        }
      else if ((strcmp (expected_conflict, "") != 0)
               && (strcmp (conflict, expected_conflict) != 0))
        {
          return svn_error_createf
            (SVN_ERR_FS_CONFLICT, NULL,
             "commit conflicted at '%s', but expected conflict at '%s')",
             conflict, expected_conflict);
        }
      svn_error_clear (err);
    }
  else if (err)   /* commit failed, but not due to conflict */
    {
      return svn_error_quick_wrap 
        (err, "commit failed due to something other than a conflict");
    }
  else            /* err == NULL, so commit succeeded */
    {
      if (expected_conflict)
        {
          return svn_error_createf
            (SVN_ERR_FS_GENERAL, NULL,
             "commit succeeded that was expected to fail at '%s'",
             expected_conflict);
        }
    }

  return SVN_NO_ERROR;
}



/* Open an existing filesystem.  */
static svn_error_t *
open_berkeley_filesystem (const char **msg,
                          svn_boolean_t msg_only,
                          apr_pool_t *pool)
{
  svn_fs_t *fs, *fs2;

  *msg = "open an existing Berkeley DB filesystem";

  if (msg_only)
    return SVN_NO_ERROR;

  /* Create and close a repository (using fs). */
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-open-berkeley", pool));

  /* Create a different fs object, and use it to re-open the
     repository again.  */
  SVN_ERR (svn_test__fs_new (&fs2, pool));
  SVN_ERR (svn_fs_open_berkeley (fs2, "test-repo-open-berkeley"));

  /* Provide a handler for Berkeley DB error messages.  */
  SVN_ERR (svn_fs_set_berkeley_errcall (fs2, berkeley_error_handler));

  return SVN_NO_ERROR;
}


/* Begin a txn, check its name, then close it */
static svn_error_t *
trivial_transaction (const char **msg,
                     svn_boolean_t msg_only,
                     apr_pool_t *pool)
{
  svn_fs_t *fs;
  svn_fs_txn_t *txn;
  const char *txn_name;

  *msg = "begin a txn, check its name, then close it";

  if (msg_only)
    return SVN_NO_ERROR;

  SVN_ERR (svn_test__create_fs (&fs, "test-repo-trivial-txn", pool));

  /* Begin a new transaction that is based on revision 0.  */
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
      
  /* Test that the txn name is non-null. */
  SVN_ERR (svn_fs_txn_name (&txn_name, txn, pool));
  
  if (! txn_name)
    return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
                             "Got a NULL txn name.");

  return SVN_NO_ERROR;
}



/* Open an existing transaction by name. */
static svn_error_t *
reopen_trivial_transaction (const char **msg,
                            svn_boolean_t msg_only,
                            apr_pool_t *pool)
{
  svn_fs_t *fs;
  svn_fs_txn_t *txn;
  const char *txn_name;
  apr_pool_t *subpool = svn_pool_create (pool);

  *msg = "open an existing transaction by name";

  if (msg_only)
    return SVN_NO_ERROR;

  SVN_ERR (svn_test__create_fs (&fs, "test-repo-reopen-trivial-txn", pool));

  /* Begin a new transaction that is based on revision 0.  */
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));

  /* Don't use the subpool, txn_name must persist beyond the current txn */
  SVN_ERR (svn_fs_txn_name (&txn_name, txn, pool));

  /* Close the transaction. */
  svn_pool_clear (subpool);

  /* Reopen the transaction by name */
  SVN_ERR (svn_fs_open_txn (&txn, fs, txn_name, subpool));

  /* Close the transaction ... again. */
  svn_pool_destroy (subpool);

  return SVN_NO_ERROR;
}



/* Create a file! */
static svn_error_t *
create_file_transaction (const char **msg,
                         svn_boolean_t msg_only,
                         apr_pool_t *pool)
{
  svn_fs_t *fs;
  svn_fs_txn_t *txn;
  svn_fs_root_t *txn_root;

  *msg = "begin a txn, get the txn root, and add a file";

  if (msg_only)
    return SVN_NO_ERROR;

  SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-file-txn", pool));

  /* Begin a new transaction that is based on revision 0.  */
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));

  /* Get the txn root */
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
  
  /* Create a new file in the root directory. */
  SVN_ERR (svn_fs_make_file (txn_root, "beer.txt", pool));

  return SVN_NO_ERROR;
}


/* Make sure we get txn lists correctly. */
static svn_error_t *
verify_txn_list (const char **msg,
                 svn_boolean_t msg_only,
                 apr_pool_t *pool)
{
  svn_fs_t *fs;
  apr_pool_t *subpool;
  svn_fs_txn_t *txn1, *txn2;
  const char *name1, *name2;
  apr_array_header_t *txn_list;

  *msg = "create 2 txns, list them, and verify the list";

  if (msg_only)
    return SVN_NO_ERROR;

  SVN_ERR (svn_test__create_fs (&fs, "test-repo-verify-txn-list", pool));

  /* Begin a new transaction, get its name (in the top pool), close it.  */
  subpool = svn_pool_create (pool);
  SVN_ERR (svn_fs_begin_txn (&txn1, fs, 0, subpool));
  SVN_ERR (svn_fs_txn_name (&name1, txn1, pool));
  svn_pool_destroy (subpool);

  /* Begin *another* transaction, get its name (in the top pool), close it.  */
  subpool = svn_pool_create (pool);
  SVN_ERR (svn_fs_begin_txn (&txn2, fs, 0, subpool));
  SVN_ERR (svn_fs_txn_name (&name2, txn2, pool));
  svn_pool_destroy (subpool);

  /* Get the list of active transactions from the fs. */
  SVN_ERR (svn_fs_list_transactions (&txn_list, fs, pool));

  /* Check the list. It should have *exactly* two entries. */
  if (txn_list->nelts != 2)
    goto all_bad;
  
  /* We should be able to find our 2 txn names in the list, in some
     order. */
  if ((! strcmp (name1, APR_ARRAY_IDX (txn_list, 0, const char *)))
      && (! strcmp (name2, APR_ARRAY_IDX (txn_list, 1, const char *))))
    goto all_good;
  
  else if ((! strcmp (name2, APR_ARRAY_IDX (txn_list, 0, const char *)))
           && (! strcmp (name1, APR_ARRAY_IDX (txn_list, 1, const char *))))
    goto all_good;
  
 all_bad:

  return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
                           "Got a bogus txn list.");
 all_good:
  
  return SVN_NO_ERROR;
}



/* Test writing & reading a file's contents. */
static svn_error_t *
write_and_read_file (const char **msg,
                     svn_boolean_t msg_only,
                     apr_pool_t *pool)
{
  svn_fs_t *fs;
  svn_fs_txn_t *txn;
  svn_fs_root_t *txn_root;
  svn_stream_t *rstream;
  svn_stringbuf_t *rstring;
  svn_stringbuf_t *wstring;

  *msg = "write and read a file's contents";

  if (msg_only)
    return SVN_NO_ERROR;

  wstring = svn_stringbuf_create ("Wicki wild, wicki wicki wild.", pool);
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-read-and-write-file", pool));
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
  
  /* Add an empty file. */
  SVN_ERR (svn_fs_make_file (txn_root, "beer.txt", pool));

  /* And write some data into this file. */
  SVN_ERR (svn_test__set_file_contents (txn_root, "beer.txt", 
                                        wstring->data, pool));
  
  /* Now let's read the data back from the file. */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?