You've already forked pg_probackup
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:
committed by
Yura Sokolov
parent
c77b50b7b1
commit
7365f24bc5
18
Makefile
18
Makefile
@@ -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
36
unit/CUnit-Run.dtd
Normal 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
173
unit/CUnit-Run.xsl
Normal 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
26
unit/Makefile
Normal 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
BIN
unit/pg_control.TEST
Normal file
Binary file not shown.
37
unit/pgpbkp.c
Normal file
37
unit/pgpbkp.c
Normal 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
183
unit/pgunit.c
Normal 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
27
unit/pgunit.h
Normal 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
408
unit/test_pio.c
Normal 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
86
unit/test_probackup.c
Normal 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
9
unit/unit_pub.sh
Normal 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
|
Reference in New Issue
Block a user