1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2025-09-16 09:26:30 +02:00

PBCKP-80 Add unit tests

This commit is contained in:
Sergey Fukanchik
2022-12-19 12:28:16 +03:00
committed by Yura Sokolov
parent c77b50b7b1
commit 7365f24bc5
11 changed files with 995 additions and 8 deletions

View File

@@ -31,18 +31,16 @@ top_pbk_srcdir := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
PROGRAM := pg_probackup
# pg_probackup sources
OBJS := src/utils/configuration.o src/utils/json.o src/utils/logger.o \
PGPOBJS := src/utils/configuration.o src/utils/json.o src/utils/logger.o \
src/utils/parray.o src/utils/pgut.o src/utils/thread.o src/utils/remote.o src/utils/file.o
OBJS += src/archive.o src/backup.o src/catalog.o src/checkdb.o src/configure.o src/data.o \
PGPOBJS += src/archive.o src/backup.o src/catalog.o src/checkdb.o src/configure.o src/data.o \
src/delete.o src/dir.o src/help.o src/init.o src/merge.o \
src/parsexlog.o src/ptrack.o src/pg_probackup.o src/restore.o src/show.o src/stream.o \
src/util.o src/validate.o src/datapagemap.o src/catchup.o \
src/compatibility/pg-11.o src/utils/simple_prompt.o
OBJS += src/compatibility/file_compat.o src/compatibility/receivelog.o \
PGPOBJS += src/compatibility/file_compat.o src/compatibility/receivelog.o \
src/compatibility/streamutil.o \
src/compatibility/walmethods.o src/compatibility/file_compat10.o
# artificial file for `main` function
OBJS += src/main.o
# sources borrowed from postgresql (paths are relative to pg top dir)
BORROWED_H_SRC :=
@@ -52,18 +50,21 @@ BORROWED_C_SRC := \
BORROW_DIR := src/borrowed
BORROWED_H := $(addprefix $(BORROW_DIR)/, $(notdir $(BORROWED_H_SRC)))
BORROWED_C := $(addprefix $(BORROW_DIR)/, $(notdir $(BORROWED_C_SRC)))
OBJS += $(patsubst %.c, %.o, $(BORROWED_C))
PGPOBJS += $(patsubst %.c, %.o, $(BORROWED_C))
EXTRA_CLEAN := $(BORROWED_H) $(BORROWED_C) $(BORROW_DIR) borrowed.mk
OBJS += src/fu_util/impl/ft_impl.o src/fu_util/impl/fo_impl.o
PGPOBJS += src/fu_util/impl/ft_impl.o src/fu_util/impl/fo_impl.o
# off-source build support
ifneq ($(abspath $(CURDIR))/, $(top_pbk_srcdir))
VPATH := $(top_pbk_srcdir)
endif
# artificial file for `main` function
OBJS += $(PGPOBJS) src/main.o
# standard PGXS stuff
# all OBJS must be defined above this
# all PGPOBJS must be defined above this
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
@@ -114,3 +115,4 @@ include $(top_pbk_srcdir)/packaging/Makefile.pkg
include $(top_pbk_srcdir)/packaging/Makefile.repo
include $(top_pbk_srcdir)/packaging/Makefile.test
include $(top_pbk_srcdir)/unit/Makefile

36
unit/CUnit-Run.dtd Normal file
View File

@@ -0,0 +1,36 @@
<!ELEMENT CUNIT_TEST_RUN_REPORT
(CUNIT_HEADER, CUNIT_RESULT_LISTING, CUNIT_RUN_SUMMARY, CUNIT_FOOTER)>
<!ELEMENT CUNIT_HEADER EMPTY>
<!ELEMENT CUNIT_RESULT_LISTING (CUNIT_RUN_SUITE*|CUNIT_RUN_GROUP*)>
<!ELEMENT CUNIT_RUN_SUITE (CUNIT_RUN_SUITE_SUCCESS|CUNIT_RUN_SUITE_FAILURE)>
<!ELEMENT CUNIT_RUN_SUITE_SUCCESS (SUITE_NAME,CUNIT_RUN_TEST_RECORD*)>
<!ELEMENT CUNIT_RUN_SUITE_FAILURE (SUITE_NAME,FAILURE_REASON)>
<!ELEMENT SUITE_NAME (#PCDATA)>
<!ELEMENT FAILURE_REASON (#PCDATA)>
<!ELEMENT CUNIT_RUN_GROUP (CUNIT_RUN_GROUP_SUCCESS|CUNIT_RUN_GROUP_FAILURE)>
<!ELEMENT CUNIT_RUN_GROUP_SUCCESS (GROUP_NAME,CUNIT_RUN_TEST_RECORD*)>
<!ELEMENT CUNIT_RUN_GROUP_FAILURE (GROUP_NAME,FAILURE_REASON)>
<!ELEMENT GROUP_NAME (#PCDATA)>
<!ELEMENT CUNIT_RUN_TEST_RECORD (CUNIT_RUN_TEST_SUCCESS|CUNIT_RUN_TEST_FAILURE)>
<!ELEMENT CUNIT_RUN_TEST_SUCCESS (TEST_NAME)>
<!ELEMENT CUNIT_RUN_TEST_FAILURE (TEST_NAME, FILE_NAME, LINE_NUMBER, CONDITION)>
<!ELEMENT TEST_NAME (#PCDATA)>
<!ELEMENT FILE_NAME (#PCDATA)>
<!ELEMENT LINE_NUMBER (#PCDATA)>
<!ELEMENT CONDITION (#PCDATA)>
<!ELEMENT CUNIT_RUN_SUMMARY (CUNIT_RUN_SUMMARY_RECORD*)>
<!ELEMENT CUNIT_RUN_SUMMARY_RECORD (TYPE, TOTAL, RUN, SUCCEEDED, FAILED, INACTIVE?)>
<!ELEMENT TYPE (#PCDATA)>
<!ELEMENT TOTAL (#PCDATA)>
<!ELEMENT RUN (#PCDATA)>
<!ELEMENT SUCCEEDED (#PCDATA)>
<!ELEMENT FAILED (#PCDATA)>
<!ELEMENT INACTIVE (#PCDATA)>
<!ELEMENT CUNIT_FOOTER (#PCDATA)>

173
unit/CUnit-Run.xsl Normal file
View File

@@ -0,0 +1,173 @@
<?xml version='1.0'?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="CUNIT_TEST_RUN_REPORT">
<html>
<head>
<title> CUnit - Automated Test Run Summary Report </title>
</head>
<body bgcolor="#e0e0f0">
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="CUNIT_HEADER">
<div align="center">
<h3>
<b> CUnit - A Unit testing framework for C. </b> <br/>
<a href="http://cunit.sourceforge.net/"> http://cunit.sourceforge.net/ </a>
</h3>
</div>
</xsl:template>
<xsl:template match="CUNIT_RESULT_LISTING">
<p/>
<div align="center">
<h2> Automated Test Run Results </h2>
</div>
<table cols="4" width="90%" align="center">
<tr>
<td width="25%"> </td>
<td width="25%"> </td>
<td width="25%"> </td>
<td width="25%"> </td>
</tr>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="CUNIT_RUN_SUITE">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="SUITE_NAME">
</xsl:template>
<xsl:template match="CUNIT_RUN_SUITE_SUCCESS">
<tr bgcolor="#f0e0f0">
<td colspan="4">
Running Suite <xsl:value-of select="SUITE_NAME"/>
</td>
</tr>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="CUNIT_RUN_GROUP">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="CUNIT_RUN_GROUP_SUCCESS">
<tr bgcolor="#f0e0f0">
<td colspan="4">
Running Group <xsl:apply-templates/>
</td>
</tr>
</xsl:template>
<xsl:template match="CUNIT_RUN_TEST_RECORD">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="CUNIT_RUN_TEST_SUCCESS">
<tr bgcolor="#e0f0d0">
<td> </td>
<td colspan="2">
Running test <xsl:apply-templates/>...
</td>
<td bgcolor="#50ff50"> Passed </td>
</tr>
</xsl:template>
<xsl:template match="CUNIT_RUN_TEST_FAILURE">
<tr bgcolor="#e0f0d0">
<td> </td>
<td colspan="2">
Running test <xsl:value-of select="TEST_NAME"/>...
</td>
<td bgcolor="#ff5050"> Failed </td>
</tr>
<tr>
<td colspan="4" bgcolor="#ff9090">
<table width="100%">
<tr>
<th width="15%"> File Name </th>
<td width="50%" bgcolor="#e0eee0">
<xsl:value-of select="FILE_NAME"/>
</td>
<th width="20%"> Line Number </th>
<td width="10%" bgcolor="#e0eee0">
<xsl:value-of select="LINE_NUMBER"/>
</td>
</tr>
<tr>
<th width="15%"> Condition </th>
<td colspan="3" width="85%" bgcolor="#e0eee0">
<xsl:value-of select="CONDITION"/>
</td>
</tr>
</table>
</td>
</tr>
</xsl:template>
<xsl:template match="CUNIT_RUN_SUITE_FAILURE">
<tr>
<td colspan="3" bgcolor="#f0b0f0">
Running Suite <xsl:value-of select="SUITE_NAME"/>...
</td>
<td bgcolor="#ff7070">
<xsl:value-of select="FAILURE_REASON"/>
</td>
</tr>
</xsl:template>
<xsl:template match="CUNIT_RUN_GROUP_FAILURE">
<tr>
<td colspan="3" bgcolor="#f0b0f0">
Running Group <xsl:value-of select="GROUP_NAME"/>...
</td>
<td bgcolor="#ff7070">
<xsl:value-of select="FAILURE_REASON"/>
</td>
</tr>
</xsl:template>
<xsl:template match="CUNIT_RUN_SUMMARY">
<p/>
<table width="90%" rows="5" align="center">
<tr align="center" bgcolor="skyblue">
<th colspan="6"> Cumulative Summary for Run </th>
</tr>
<tr>
<th width="15%" bgcolor="#ffffc0" align="center"> Type </th>
<th width="17%" bgcolor="#ffffc0" align="center"> Total </th>
<th width="17%" bgcolor="#ffffc0" align="center"> Run </th>
<th width="17%" bgcolor="#ffffc0" align="center"> Succeeded </th>
<th width="17%" bgcolor="#ffffc0" align="center"> Failed </th>
<th width="17%" bgcolor="#ffffc0" align="center"> Inactive </th>
</tr>
<xsl:for-each select="CUNIT_RUN_SUMMARY_RECORD">
<tr align="center" bgcolor="lightgreen">
<td> <xsl:value-of select="TYPE" /> </td>
<td> <xsl:value-of select="TOTAL" /> </td>
<td> <xsl:value-of select="RUN" /> </td>
<td> <xsl:value-of select="SUCCEEDED" /> </td>
<td> <xsl:value-of select="FAILED" /> </td>
<td> <xsl:value-of select="INACTIVE" /> </td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="CUNIT_FOOTER">
<p/>
<hr align="center" width="90%" color="maroon" />
<h5 align="center"> <xsl:apply-templates/> </h5>
</xsl:template>
</xsl:stylesheet>

26
unit/Makefile Normal file
View File

@@ -0,0 +1,26 @@
APPS=unit/test_unit_pio unit/test_unit_probackup
test_unit: $(APPS)
TEST_FILES=unit/test_probackup.o unit/test_pio.o
unit/test_unit_pio: LIBS += -lcunit
unit/test_unit_pio: $(PGPOBJS) unit/pgunit.o unit/test_pio.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LIBS) $(PG_LIBS_INTERNAL) -o $@
unit/test_unit_probackup: LIBS += -lcunit
unit/test_unit_probackup: $(PGPOBJS) unit/pgunit.o unit/test_probackup.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LIBS) $(PG_LIBS_INTERNAL) -o $@
test_unit_run: test_unit
(cd unit; ./test_unit_pio)
(cd unit; ./test_unit_probackup)
test_unit_pub: test_unit_run
(cd unit ; /bin/sh unit_pub.sh)
clean: test_clean
test_clean:
rm -rf $(APPS) unit/*.o *~ *.gcda *.gcno *.html *.xml pb.info gmon.out report/

BIN
unit/pg_control.TEST Normal file

Binary file not shown.

37
unit/pgpbkp.c Normal file
View File

@@ -0,0 +1,37 @@
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <CUnit/Basic.h>
#include <pg_probackup.h>
#include <utils/file.h>
#include <s3.h>
#include "pgunit.h"
/* Emulate pgprobackup */
bool show_color = true;
ShowFormat show_format = SHOW_PLAIN;
const char *PROGRAM_NAME = NULL;
const char *PROGRAM_NAME_FULL = NULL;
const char *PROGRAM_FULL_PATH = NULL;
pid_t my_pid = 0;
bool is_archive_cmd = false;
bool remote_agent = false;
time_t current_time = 0;
char *replication_slot = NULL;
pgBackup current;
bool perm_slot = false;
bool temp_slot = false;
bool progress = false;
int num_threads = 1;
bool delete_wal = false;
bool merge_expired = false;
bool smooth_checkpoint;
bool skip_block_validation = false;
bool dry_run = false;
bool delete_expired = false;
/***********************/

183
unit/pgunit.c Normal file
View File

@@ -0,0 +1,183 @@
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <CUnit/Basic.h>
#include <pg_probackup.h>
#include <utils/file.h>
#include "pgunit.h"
pioDrive_i drive;
pioDBDrive_i dbdrive;
pioDrive_i cloud_drive;
pioDBDrive_i local_drive;
int should_be_remote;
void
init_test_drives()
{
local_drive = pioDBDriveForLocation(FIO_LOCAL_HOST);
}
int
USE_LOCAL()
{
drive = $reduce(pioDrive, local_drive);
dbdrive = local_drive;
should_be_remote = 0;
printf("USE_LOCAL\n");
return 0;
}
static int
clean_basic_suite()
{
return 0;
}
#define FNAMES "abcdefghijklmnopqrstuvwxyz0123456789"
static int rand_init=0;
char *
random_path(void)
{
char name[MAXPGPATH];
if(!rand_init) {
srand(time(NULL));
rand_init = 1;
}
int len = 3 + rand() % 20;
int fnlen = strlen(FNAMES);
name[0]=0;
snprintf(name, MAXPGPATH, "/tmp/%d_", getpid());
int i;
int l=strlen(name);
for(i=l; i < len+l; ++i)
{
name[i] = FNAMES[rand()%fnlen];
}
name[i] = 0;
return strdup(name);
}
char *
random_name(void)
{
char name[MAXPGPATH];
if(!rand_init) {
srand(time(NULL));
rand_init = 1;
}
int len = 3 + rand() % 10;
int fnlen = strlen(FNAMES);
int i;
for(i=0;i<len; ++i)
{
name[i] = FNAMES[rand()%fnlen];
}
name[i] = 0;
return strdup(name);
}
void
copy_file(const char *from, const char *to)
{
int fdin = open(from, O_RDONLY|PG_BINARY);
CU_ASSERT_FATAL(fdin>=0);
int fdout = open(to, O_CREAT|O_RDWR|O_TRUNC, FILE_PERMISSION);
CU_ASSERT_FATAL(fdout>=0);
while(1)
{
char buf[BUFSZ];
int rc = read(fdin, buf, BUFSZ);
CU_ASSERT_FATAL(rc>=0);
if(rc==0) break;
int written = write(fdout, buf, rc);
CU_ASSERT_FATAL(written == rc);
}
close(fdin);
fsync(fdout);
close(fdout);
}
void
init_fake_server(const char *path)
{
char global[8192];
snprintf(global, 8192, "%s/global", path);
int rc = mkdir(path, DIR_PERMISSION);
CU_ASSERT_FATAL(rc == 0);
rc = mkdir(global, DIR_PERMISSION);
CU_ASSERT_FATAL(rc == 0);
char global2[MAXPGPATH];
snprintf(global2, MAXPGPATH, "%s/pg_control", global);
copy_file("pg_control.TEST", global2);
}
void
pbk_add_tests(int (*init)(void), const char *suite_name, PBK_test_description *tests)
{
CU_pSuite pSuite;
int i;
pSuite = CU_add_suite(suite_name, init, clean_basic_suite);
if(pSuite==NULL)
{
fprintf(stderr, "Can't add a suite %s\n", suite_name);
CU_cleanup_registry();
abort();
}
for(i = 0; tests[i].name; ++i)
{
if(CU_add_test(pSuite, tests[i].name, tests[i].foo) == NULL)
{
fprintf(stderr, "Can't add test %s.%s\n", suite_name, tests[i].name);
CU_cleanup_registry();
abort();
}
}
}
void
pio_write(pioDrive_i drive, path_t path, const char *data)
{
FOBJ_FUNC_ARP();
err_i err=$noerr();
err = $i(pioWriteFile, drive, .path = path, .content = ft_bytes((char *)data, strlen(data)), .binary = true);
CU_ASSERT(!$haserr(err));
}
bool
pio_exists(pioDrive_i drive, path_t path)
{
FOBJ_FUNC_ARP();
err_i err=$noerr();
bool exists = $i(pioExists, drive, .path = path, .expected_kind = PIO_KIND_REGULAR, &err);
if ($haserr(err))
fprintf(stderr, "pio_exists: %s\n", $errmsg(err));
CU_ASSERT(!$haserr(err));
return exists;
}
bool
pio_exists_d(pioDrive_i drive, path_t path)
{
FOBJ_FUNC_ARP();
err_i err=$noerr();
bool exists = $i(pioExists, drive, .path = path, .expected_kind = PIO_KIND_DIRECTORY, &err);
CU_ASSERT(!$haserr(err));
return exists;
}

27
unit/pgunit.h Normal file
View File

@@ -0,0 +1,27 @@
#ifdef __pgunit_h__
#error "Double #include of pgunit.h"
#endif
#define __pgunit_h__ 1
#define BUFSZ 8192
typedef struct {
const char *name;
void (*foo)(void);
} PBK_test_description;
extern pioDrive_i drive;
extern pioDBDrive_i dbdrive;
extern int should_be_remote;
void init_test_drives(void);
int USE_LOCAL(void);
char *random_path(void);
char *random_name(void);
void pbk_add_tests(int (*init)(void), const char *sub_name, PBK_test_description *tests);
void pio_write(pioDrive_i drive, path_t name, const char *data);
bool pio_exists(pioDrive_i drive, path_t path);
bool pio_exists_d(pioDrive_i drive, path_t path);
void copy_file(const char *from, const char *to);
void init_fake_server(const char *path);

408
unit/test_pio.c Normal file
View File

@@ -0,0 +1,408 @@
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <CUnit/Basic.h>
#include <CUnit/Automated.h>
#include <pg_probackup.h>
#include <utils/file.h>
#include "pgunit.h"
#define TEST_STR "test\n"
#define BUFSZ 8192
#define XXX_STR "XXX"
static void
test_pioStat()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path = random_path();
err = $i(pioWriteFile, drive, .path = path, .content = ft_bytes(TEST_STR, strlen(TEST_STR)), .binary = true);
CU_ASSERT(!$haserr(err));
time_t now = time(NULL);
pio_stat_t pst = $i(pioStat, drive, .path = path, .follow_symlink = false, .err = &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pst.pst_kind == PIO_KIND_REGULAR);
CU_ASSERT(pst.pst_mode == FILE_PERMISSION);
CU_ASSERT(abs(now-pst.pst_mtime) < 2);
CU_ASSERT(pst.pst_size == 5);
}
static void
test_pioRemove()
{
FOBJ_FUNC_ARP();
char *path = random_path();
pio_write(drive, path, TEST_STR);
CU_ASSERT(pio_exists(drive, path));
err_i err = $i(pioRemove, drive, .path = path, .missing_ok = false);
CU_ASSERT(!$haserr(err));
CU_ASSERT(!pio_exists(drive, path));
}
static void
test_pioRename()
{
FOBJ_FUNC_ARP();
char *name = random_path();
char *another_name = random_path();
pio_write(drive, name, TEST_STR);
CU_ASSERT(pio_exists(drive, name));
err_i err = $i(pioRename, dbdrive, .old_path = name, .new_path = another_name);
CU_ASSERT(!$haserr(err));
CU_ASSERT(!pio_exists(drive, name));
CU_ASSERT(pio_exists(drive, another_name));
}
static void
test_pioExists()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
bool exists = $i(pioExists, drive, .path = "/", .expected_kind = PIO_KIND_DIRECTORY, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(exists);
const char *path = random_path();
err = $noerr();
exists = $i(pioExists, drive, .path = path, .expected_kind = PIO_KIND_REGULAR, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(!exists);
char *name = random_path();
pio_write(drive, name, TEST_STR);
exists = $i(pioExists, drive, .path = name, .expected_kind = PIO_KIND_REGULAR, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(exists);
}
static void
test_pioIsRemote()
{
FOBJ_FUNC_ARP();
if(should_be_remote) {
CU_ASSERT( $i(pioIsRemote, drive) );
} else {
CU_ASSERT( !$i(pioIsRemote, drive) );
}
}
static void
test_pioWriteFile()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path = random_path();
CU_ASSERT(!pio_exists(drive, path));
err = $i(pioWriteFile, drive, .path = path, .content = ft_bytes(TEST_STR, strlen(TEST_STR)), .binary = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists(drive, path));
ft_bytes_t result = $i(pioReadFile, drive, .path = path, .binary = true, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(result.len==strlen(TEST_STR));
CU_ASSERT(!strncmp(result.ptr, TEST_STR, strlen(TEST_STR)));
ft_bytes_free(&result);
free(path);
}
static void
test_pioOpenRead()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path = random_path();
pio_write(drive, path, TEST_STR);
CU_ASSERT(pio_exists(drive, path));
pioReader_i reader = $i(pioOpenRead, drive, .path = path, &err);
CU_ASSERT(!$haserr(err));
char B0[8192];
ft_bytes_t buf = ft_bytes(B0, 8192);
size_t ret = $i(pioRead, reader, .buf = buf, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(ret==strlen(TEST_STR));
CU_ASSERT(!strncmp(buf.ptr, TEST_STR, strlen(TEST_STR)));
err = $i(pioSeek, reader, 0);
CU_ASSERT(!$haserr(err));
ft_bytes_t buf2 = ft_bytes(B0+100, 8192);
ret = $i(pioRead, reader, .buf = buf2, &err);
CU_ASSERT(ret==strlen(TEST_STR));
CU_ASSERT(!strncmp(buf2.ptr, TEST_STR, strlen(TEST_STR)));
$i(pioClose, reader);
//ft_bytes_free(&result);
free(path);
}
static void
test_pioOpenReadStream()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path = random_path();
pioReadStream_i stream;
/* Crash in pioCloudDrive */
stream = $i(pioOpenReadStream, drive, .path = path, &err);
CU_ASSERT($haserr(err));
pio_write(drive, path, TEST_STR);
stream = $i(pioOpenReadStream, drive, .path = path, &err);
CU_ASSERT(!$haserr(err));
char B0[8192];
ft_bytes_t buf = ft_bytes(B0, 8192);
size_t ret = $i(pioRead, stream, .buf= buf, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(ret==strlen(TEST_STR));
CU_ASSERT(!strncmp(buf.ptr, TEST_STR, strlen(TEST_STR)));
$i(pioClose, stream);
free(path);
}
static void
test_pioGetCRC32()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path = random_path();
pg_crc32 crc;
#if 0
//crashes. should return errno in err
crc = $i(pioGetCRC32, drive, .path = path, .compressed = false, .err = &err);
CU_ASSERT($haserr(err));
#endif
pio_write(drive, path, TEST_STR);
crc = $i(pioGetCRC32, drive, .path = path, .compressed = false, .err = &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(crc==0xFA94FDDF)
}
static void
test_pioMakeDir()
{
FOBJ_FUNC_ARP();
char *path = random_path();
CU_ASSERT(!pio_exists(drive, path));
err_i err = $i(pioMakeDir, drive, .path = path, .mode = DIR_PERMISSION, .strict = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists_d(drive, path));
}
static void
test_pioMakeDirWithParent()
{
FOBJ_FUNC_ARP();
char child[MAXPGPATH];
char *parent = random_path();
CU_ASSERT(!pio_exists(drive, parent));
snprintf(child, MAXPGPATH, "%s/TEST", parent);
err_i err = $i(pioMakeDir, drive, .path = child, .mode = DIR_PERMISSION, .strict = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists_d(drive, parent));
CU_ASSERT(pio_exists_d(drive, child));
free(parent);
}
static void
test_pioRemoveDir()
{
FOBJ_FUNC_ARP();
char *path = random_path();
err_i err = $noerr();
char path2[8192];
snprintf(path2, 8192, "%s/%s", path, "sample.txt");
CU_ASSERT(!pio_exists(drive, path));
err = $i(pioMakeDir, drive, .path = path, .mode = DIR_PERMISSION, .strict = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists_d(drive, path));
err = $i(pioWriteFile, drive, .path = path2, .content = ft_bytes(TEST_STR, strlen(TEST_STR)), .binary = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists(drive, path2));
$i(pioRemoveDir, drive, path, .root_as_well=false);
CU_ASSERT(!pio_exists(drive, path2));
CU_ASSERT(pio_exists_d(drive, path));
}
static void
test_pioFilesAreSame()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path1 = random_path();
char *path2 = random_path();
CU_ASSERT(!pio_exists(drive, path1));
CU_ASSERT(!pio_exists(drive, path2));
err = $i(pioWriteFile, drive, .path = path1, .content = ft_bytes(TEST_STR, strlen(TEST_STR)), .binary = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists(drive, path1));
err = $i(pioWriteFile, drive, .path = path2, .content = ft_bytes(TEST_STR, strlen(TEST_STR)), .binary = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists(drive, path2));
ft_bytes_t result1 = $i(pioReadFile, drive, .path = path1, .binary = true, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(result1.len==strlen(TEST_STR));
CU_ASSERT(!strncmp(result1.ptr, TEST_STR, strlen(TEST_STR)));
ft_bytes_t result2 = $i(pioReadFile, drive, .path = path2, .binary = true, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(result2.len==strlen(TEST_STR));
CU_ASSERT(!strncmp(result2.ptr, TEST_STR, strlen(TEST_STR)));
CU_ASSERT(result1.len == result2.len);
CU_ASSERT(!memcmp(result1.ptr, result2.ptr, result1.len));
ft_bytes_free(&result1);
ft_bytes_free(&result2);
free(path1);
free(path2);
}
static void
test_pioReadFile()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path = random_path();
CU_ASSERT(!pio_exists(drive, path));
err = $i(pioWriteFile, drive, .path = path, .content = ft_bytes(TEST_STR, strlen(TEST_STR)), .binary = true);
CU_ASSERT(!$haserr(err));
CU_ASSERT(pio_exists(drive, path));
ft_bytes_t result = $i(pioReadFile, drive, .path = path, .binary = true, &err);
CU_ASSERT(!$haserr(err));
CU_ASSERT(result.len==strlen(TEST_STR));
CU_ASSERT(!strncmp(result.ptr, TEST_STR, strlen(TEST_STR)));
ft_bytes_free(&result);
free(path);
}
static void
test_pioOpenRewrite()
{
FOBJ_FUNC_ARP();
err_i err = $noerr();
char *path = random_path();
pio_write(drive, path, TEST_STR);
CU_ASSERT(pio_exists(drive, path));
pioWriteCloser_i writer = $i(pioOpenRewrite, drive, .path = path,
.permissions = FILE_PERMISSION, .binary = true,
.use_temp=true, .sync = true, .err = &err);
CU_ASSERT(!$haserr(err));
char B0[8192];
snprintf(B0, 8192, XXX_STR);
ft_bytes_t buf = ft_bytes(B0, strlen(B0));
err = $i(pioWrite, writer, .buf = buf);
CU_ASSERT(!$haserr(err));
$i(pioClose, writer);
ft_bytes_t result = $i(pioReadFile, drive, .path = path, .binary = true, &err);
CU_ASSERT(strlen(XXX_STR) == result.len);
CU_ASSERT(!memcmp(XXX_STR, result.ptr, result.len));
ft_bytes_free(&result);
free(path);
}
PBK_test_description PIO_DRIVE_TESTS[] = {
{"Test pioOpenRead", test_pioOpenRead},
{"Test pioOpenReadStream", test_pioOpenReadStream},
{"Test pioStat", test_pioStat},
{"Test pioRemove", test_pioRemove},
{"Test pioRename", test_pioRename},
{"Test pioExists", test_pioExists},
{"Test pioGetCRC32", test_pioGetCRC32},
{"Test pioIsRemote", test_pioIsRemote},
{"Test pioMakeDir", test_pioMakeDir},
{"Test pioMakeDirWithParent", test_pioMakeDirWithParent},
{"Test pioRemoveDir", test_pioRemoveDir},
{"Test pioFilesAreSame", test_pioFilesAreSame},
{"Test pioReadFile", test_pioReadFile},
{"Test pioWriteFile", test_pioWriteFile},
{"Test pioOpenRewrite", test_pioOpenRewrite},
{NULL, NULL}
};
PBK_test_description PIO_DB_DRIVE_TESTS[] = {
{NULL, NULL}
};
int
main(int argc, char *argv[])
{
ft_init_log(elog_ft_log);
fobj_init();
FOBJ_FUNC_ARP();
init_pio_objects();
init_test_drives();
if(CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
pbk_add_tests(USE_LOCAL, "Local pioDrive", PIO_DRIVE_TESTS);
pbk_add_tests(USE_LOCAL, "LOcal pioDBDrive", PIO_DB_DRIVE_TESTS);
CU_list_tests_to_file();
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_set_output_filename("test_pio");
CU_basic_run_tests();
CU_automated_run_tests();
CU_cleanup_registry();
return CU_get_error();
}

86
unit/test_probackup.c Normal file
View File

@@ -0,0 +1,86 @@
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <CUnit/Basic.h>
#include <CUnit/Automated.h>
#include <pg_probackup.h>
#include <utils/file.h>
#include "pgunit.h"
static void
test_do_init()
{
FOBJ_FUNC_ARP();
char *backup_path = random_path();
CatalogState *catalogState = catalog_new(backup_path);
int rc = do_init(catalogState);
CU_ASSERT(rc == 0);
}
static void
test_do_add_instance()
{
//FOBJ_FUNC_ARP();
int rc;
char *backup_path = random_path();
char *instance_name = random_name();
char *server_path = random_path();
init_fake_server(server_path);
CatalogState *catalogState = catalog_new(backup_path);
catalogState->backup_location = drive;
rc = do_init(catalogState);
CU_ASSERT(rc == 0);
//CU_ASSERT_FATAL(pio_exists_d(drive, backup_path));
init_config(&instance_config, instance_name);
instance_config.pgdata = server_path;
InstanceState *instanceState = makeInstanceState(catalogState, instance_name);
instanceState->database_location = drive;
rc = do_add_instance(instanceState, &instance_config);
CU_ASSERT(rc == 0);
char buf[MAXPGPATH];
snprintf(buf, MAXPGPATH, "%s/%s/%s", catalogState->backup_subdir_path, instance_name, BACKUP_CATALOG_CONF_FILE);
CU_ASSERT(pio_exists(drive, buf));
}
PBK_test_description PIO_INIT_TESTS[] = {
{"Test do_init", test_do_init},
{"Test do_add_instance", test_do_add_instance},
{NULL,NULL},
};
int
main(int argc, char *argv[])
{
ft_init_log(elog_ft_log);
fobj_init();
FOBJ_FUNC_ARP();
init_pio_objects();
init_test_drives();
if(CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
pbk_add_tests(USE_LOCAL, "Local init", PIO_INIT_TESTS);
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_set_output_filename("test_probackup");
//CU_list_tests_to_file();
CU_automated_run_tests();
CU_cleanup_registry();
return CU_get_error();
}

9
unit/unit_pub.sh Normal file
View File

@@ -0,0 +1,9 @@
xsltproc test_pio-Results.xml > results-pio.html 2> /dev/null
xsltproc test_probackup-Results.xml > results-init.html 2> /dev/null
lcov -t "pb" --output pb.info --capture --directory . --directory ../s3 --directory ../src --rc lcov_branch_coverage=1 > /dev/null 2>&1
genhtml --output report --branch-coverage pb.info > /dev/null 2>&1
xdg-open report/index.html > /dev/null 2>&1
xdg-open results-pio.html > /dev/null 2>&1
if test -s results-init.html ; then
xdg-open results-init.html > /dev/null 2>&1
fi