Postgres2015全国用户大会将于11月20至21日在北京丽亭华苑酒店召开。本次大会嘉宾阵容强大,国内顶级PostgreSQL数据库专家将悉数到场,并特邀欧洲、俄罗斯、日本、美国等国家和地区的数据库方面专家助阵:
- Postgres-XC项目的发起人铃木市一(SUZUKI Koichi)
- Postgres-XL的项目发起人Mason Sharp
- pgpool的作者石井达夫(Tatsuo Ishii)
- PG-Strom的作者海外浩平(Kaigai Kohei)
- Greenplum研发总监姚延栋
- 周正中(德哥), PostgreSQL中国用户会创始人之一
- 汪洋,平安科技数据库技术部经理
- ……
|
回归测试是PostgreSQL的测试方法之一。
回归测试,需要事先定义好测试脚本(通常是SQL脚本,放在sql目录中),同时定义好调用执行测试脚本的预期正确输出文件(通常放在expected目录中)。
测试使用make check或make installcheck进行,它会通过pg_regress程序调用sql目录中的SQL,并收集输出结果(通常放到results目录中),最后pg_regress会对expected目录和results目录中的文件使用diff进行一一比较。
如果比较发现文件内容不一致,会将不一致的结果输出到regression.diffs文件中,并返回这个TEST CASE failed。
但是这种测试方法实际上有一些需要注意的地方,例如我们使用不同的本地化设置,时区可能得到的结果和期望的结果就不一样。另外有些不可预知的结果,例如随机值,数据的顺序,执行计划和优化器相关参数有关。这些因素都可能导致测试结果和预期不一致,那么我们就需要人为去修复这种failed。
PostgreSQL的主代码测试文件在src/test/regress目录中。
这个目录的结构如下:
postgres@digoal-> ll -rttotal 1.2M-rw-r--r-- 1 postgres postgres 579 Jun 10 03:29 standby_schedule 测试standby的调度配置, 其实就是调度sql里的文件名-rw-r--r-- 1 postgres postgres 2.3K Jun 10 03:29 serial_schedule 串行测试的调度配置-rw-r--r-- 1 postgres postgres 937 Jun 10 03:29 resultmap 不同的测试平台的结果映射文件,因为不同平台某些测试结果可能不相同,所以一个expected文件不能支持所有的平台。例如浮点数测试。-rwxr-xr-x 1 postgres postgres 4.4K Jun 10 03:29 regressplans.sh-rw-r--r-- 1 postgres postgres 20K Jun 10 03:29 regress.c-rw-r--r-- 1 postgres postgres 159 Jun 10 03:29 README-rw-r--r-- 1 postgres postgres 2.7K Jun 10 03:29 pg_regress_main.c-rw-r--r-- 1 postgres postgres 1.6K Jun 10 03:29 pg_regress.h-rw-r--r-- 1 postgres postgres 69K Jun 10 03:29 pg_regress.c-rw-r--r-- 1 postgres postgres 3.6K Jun 10 03:29 parallel_schedule 并行测试的调度配置-rw-r--r-- 1 postgres postgres 624 Jun 10 03:29 Makefile-rw-r--r-- 1 postgres postgres 5.6K Jun 10 03:29 GNUmakefiledrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 outputdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 inputdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 data 一些测试数据drwxrwxrwx 2 postgres postgres 4.0K Sep 7 14:51 sql 测试用到的SQLdrwxrwxr-x 2 postgres postgres 4.0K Sep 7 14:52 results 通过pg_regress调用sql目录中的脚本,得到的结果drwxrwxrwx 2 postgres postgres 4.0K Sep 7 14:51 expected 执行sql目录中的文件对应的正确返回结果
上层目录结构如下,其中包含了一些其他的测试目标,例如隔离级别的测试,本地化测试,性能测试,线程安全测试。等。
postgres@digoal-> cd /opt/soft_bak/postgresql-9.4.4/src/testpostgres@digoal-> lltotal 36Kdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 examplesdrwxrwxrwx 4 postgres postgres 4.0K Jun 10 03:41 isolationdrwxrwxrwx 6 postgres postgres 4.0K Jun 10 03:38 locale-rw-r--r-- 1 postgres postgres 389 Jun 10 03:29 Makefiledrwxrwxrwx 4 postgres postgres 4.0K Jun 10 03:38 mbdrwxrwxrwx 4 postgres postgres 4.0K Jun 10 03:38 performancedrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 perldrwxrwxrwx 10 postgres postgres 4.0K Sep 7 19:17 regressdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 thread
接下来我们看看PostgreSQL的回归测试程序pg_regress的用法,它不会安装到PGHOME/bin中,只在src/test/regress中存在。
$ cd src/test/regress$ src/test/regress/pg_regress --helpPostgreSQL regression test driver
Usage:pg_regress [OPTION]... [EXTRA-TEST]...
Options:--config-auth=DATADIR update authentication settings for DATADIR--create-role=ROLE create the specified role before testing--dbname=DB use database DB (default "regression")--debug turn on debug mode in programs that are run--dlpath=DIR look for dynamic libraries in DIR--encoding=ENCODING use ENCODING as the encoding--inputdir=DIR take input files from DIR (default ".")--launcher=CMD use CMD as launcher of psql--load-extension=EXT load the named extension before running thetests; can appear multiple times--load-language=LANG load the named language before running thetests; can appear multiple times--max-connections=N maximum number of concurrent connections(default is 0, meaning unlimited)--outputdir=DIR place output files in DIR (default ".")--schedule=FILE use test ordering schedule from FILE(can be used multiple times to concatenate)--temp-install=DIR create a temporary installation in DIR--use-existing use an existing installation
Options for "temp-install" mode:--extra-install=DIR additional directory to install (e.g., contrib)--no-locale use C locale--port=PORT start postmaster on PORT--temp-config=FILE append contents of FILE to temporary config--top-builddir=DIR (relative) path to top level build directory
Options for using an existing installation:--host=HOST use postmaster running on HOST--port=PORT use postmaster running at PORT--user=USER connect as USER--psqldir=DIR use psql in DIR (default: configured bindir)
The exit status is 0 if all tests passed, 1 if some tests failed, and 2if the tests could not be run for some reason.
Report bugs to <pgsql-bugs@postgresql.org>.
回归测试用法:
在PostgreSQL源码根目录,或者源码的regress目录中执行如下:
make check // 测试时需要初始化数据库集群make installcheck // 使用以及启动的数据库集群测试,不需要初始化数据库集群
以下同时测试主代码以及contrib的代码:
make check-worldmake installcheck-world
如果要使用自定义的diff参数,可以设置一个环境变量,
例如:make check PG_REGRESS_DIFF_OPTS='-u'。
同时我们还可以使用不同的LOCALE进行测试。
例如:
make check LANG=de_DE.utf8make check NO_LOCALE=1make check LANG=C ENCODING=EUC_JP
当我们要测试调度中不包含的测试SQL时,可以使用EXTRA_TESTS参数,至于这些脚本为什么默认不包含在调度中,可能是因为这些SQL脚本可能对平台的依赖比较严重,所以没有放到默认的测试中。例如:
make check EXTRA_TESTS=collate.linux.utf8 LANG=en_US.utf8make check EXTRA_TESTS=numeric_big
接下来我们看看调度文件以及sql脚本目录:
postgres@digoal-> pwd/opt/soft_bak/postgresql-9.4.4/src/test/regresspostgres@digoal-> less serial_schedule# src/test/regress/serial_schedule# This should probably be in an order similar to parallel_schedule.test: tablespacetest: booleantest: chartest: nametest: varchartest: texttest: int2test: int4test: int8
......
并行调度
postgres@digoal-> less parallel_schedule
# ----------# src/test/regress/parallel_schedule## By convention, we put no more than twenty tests in any one parallel group;# this limits the number of connections needed to run the tests.# ----------# run tablespace by itself, and first, because it forces a checkpoint;# we'd prefer not to have checkpoints later in the tests because that# interferes with crash-recovery testing.test: tablespace
# ----------# The first group of parallel tests# ----------test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes pg_lsn regproc
......
调度文件的test:后面跟的就是sql目录下的文件名(不含.sql后缀)。
postgres@digoal-> less sql/total 1940drwxrwxrwx 2 postgres postgres 4096 Sep 7 14:51 ./drwxrwxrwx 10 postgres postgres 4096 Sep 7 22:34 ../-rw-r--r-- 1 postgres postgres 2237 Jun 10 03:29 abstime.sql-rw-r--r-- 1 postgres postgres 4097 Jun 10 03:29 advisory_lock.sql-rw-r--r-- 1 postgres postgres 20295 Jun 10 03:29 aggregates.sql-rw-r--r-- 1 postgres postgres 24882 Jun 10 03:29 alter_generic.sql-rw-r--r-- 1 postgres postgres 54461 Jun 10 03:29 alter_table.sql-rw-r--r-- 1 postgres postgres 17244 Jun 10 03:29 arrays.sql-rw-r--r-- 1 postgres postgres 594 Jun 10 03:29 async.sql-rw-r--r-- 1 postgres postgres 1365 Jun 10 03:29 bitmapops.sql-rw-r--r-- 1 postgres postgres 6406 Jun 10 03:29 bit.sql-rw-r--r-- 1 postgres postgres 4164 Jun 10 03:29 boolean.sql
......
所以前面提到的
EXTRA_TESTS实际上也是sql目录中的文件名(不带.sql后缀)。
make check EXTRA_TESTS=collate.linux.utf8 LANG=en_US.utf8make check EXTRA_TESTS=numeric_big
来实际的试一下吧:
postgres@digoal-> pwd/opt/soft_bak/postgresql-9.4.4/src/test/regresspostgres@digoal-> make installcheck-parallel //并行测试,使用已经开启的现有的数据库集群make -C ../../../src/port all......../../../src/test/regress/pg_regress --inputdir=. --psqldir='/opt/pgsql9.4.4/bin' --dlpath=. --schedule=./parallel_schedule(using postmaster on /data01/pg_root_1921, port 1921)============== dropping database "regression" ==============DROP DATABASE============== creating database "regression" ==============CREATE DATABASEALTER DATABASE============== running regression test queries ==============test tablespace ... ok......parallel group (19 tests): limit conversion sequence returning without_oid polymorphism copy2 xml prepare plancache rowtypes temp domain with truncate largeobject rangefuncs alter_table plpgsqlplancache ... oklimit ... okplpgsql ... okcopy2 ... oktemp ... okdomain ... okrangefuncs ... FAILEDprepare ... okwithout_oid ... okconversion ... oktruncate ... okalter_table ... oksequence ... okpolymorphism ... FAILEDrowtypes ... okreturning ... oklargeobject ... okwith ... FAILEDxml ... oktest stats ... ok......=========================22 of 145 tests failed.=========================
The differences that caused some tests to fail can be viewed in thefile "/opt/soft_bak/postgresql-9.4.4/src/test/regress/regression.diffs". A copy of the test summary that you seeabove is saved in the file "/opt/soft_bak/postgresql-9.4.4/src/test/regress/regression.out".
make: *** [installcheck-parallel] Error 1
有些测试失败了,diff文件已经输出到
/opt/soft_bak/postgresql-9.4.4/src/test/regress/regression.diffs,我们可以
查看一下看看为什么测试结果和预期结果不一致。
postgres@digoal-> less regression.diffs*** /opt/soft_bak/postgresql-9.4.4/src/test/regress/expected/pg_lsn.out 2015-06-10 03:29:38.000000000 +0800--- /opt/soft_bak/postgresql-9.4.4/src/test/regress/results/pg_lsn.out 2015-09-07 22:45:04.413922536 +0800****************** 72,92 ****generate_series(1, 5) kWHERE i <= 10 AND j > 0 AND j <= 10ORDER BY f;! QUERY PLAN! --------------------------------------------------------------------------! Sort! Sort Key: (((((i.i)::text || '/'::text) || (j.j)::text))::pg_lsn)! -> HashAggregate! Group Key: ((((i.i)::text || '/'::text) || (j.j)::text))::pg_lsn-> Nested Loop-> Function Scan on generate_series k! -> Materialize! -> Nested Loop! -> Function Scan on generate_series j! Filter: ((j > 0) AND (j <= 10))! -> Function Scan on generate_series i! Filter: (i <= 10)! (12 rows)SELECT DISTINCT (i || '/' || j)::pg_lsn fFROM generate_series(1, 10) i,--- 72,90 ----generate_series(1, 5) kWHERE i <= 10 AND j > 0 AND j <= 10ORDER BY f;......
对于主代码,如果我们需要自定义测试SQL,我们可以修改regress/sql目录下的文件,或者新增文件。同时修改regress/expected目录下的对应期望文件,或者现在期望文件。
如果是新增文件的情况,我们还需要修改调度文件regress/serial_schedule和regress/parallel_schedule,把测试加入调度。
最后,再以ltree插件为例,看看如何配置一个外加插件的回归测试。
ltree的源码目录:
postgres@digoal-> cd contrib/postgres@digoal-> cd ltree/postgres@digoal-> ll -rttotal 1.1M-rw-r--r-- 1 postgres postgres 517 Jun 10 03:29 Makefile-rw-r--r-- 1 postgres postgres 2.4K Jun 10 03:29 ltxtquery_op.c-rw-r--r-- 1 postgres postgres 11K Jun 10 03:29 ltxtquery_io.c-rw-r--r-- 1 postgres postgres 7.9K Jun 10 03:29 ltree--unpackaged--1.0.sql-rw-r--r-- 1 postgres postgres 994 Jun 10 03:29 ltreetest.sql-rw-r--r-- 1 postgres postgres 13K Jun 10 03:29 ltree_op.c-rw-r--r-- 1 postgres postgres 6.9K Jun 10 03:29 _ltree_op.c-rw-r--r-- 1 postgres postgres 14K Jun 10 03:29 ltree_io.c-rw-r--r-- 1 postgres postgres 7.3K Jun 10 03:29 ltree.h-rw-r--r-- 1 postgres postgres 16K Jun 10 03:29 ltree_gist.c-rw-r--r-- 1 postgres postgres 13K Jun 10 03:29 _ltree_gist.c-rw-r--r-- 1 postgres postgres 155 Jun 10 03:29 ltree.control-rw-r--r-- 1 postgres postgres 18K Jun 10 03:29 ltree--1.0.sql-rw-r--r-- 1 postgres postgres 7.1K Jun 10 03:29 lquery_op.c-rw-r--r-- 1 postgres postgres 263 Jun 10 03:29 crc32.h-rw-r--r-- 1 postgres postgres 4.1K Jun 10 03:29 crc32.cdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 sqldrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 expecteddrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 data
contrib/ltree的Makefile如下(在这里配置回归测试的调度,用到变量REGRESS,对应sql目录中的脚本文件名):
# contrib/ltree/Makefile
MODULE_big = ltreeOBJS = ltree_io.o ltree_op.o lquery_op.o _ltree_op.o crc32.o \ltxtquery_io.o ltxtquery_op.o ltree_gist.o _ltree_gist.oPG_CPPFLAGS = -DLOWER_NODE
EXTENSION = ltreeDATA = ltree--1.0.sql ltree--unpackaged--1.0.sql
REGRESS = ltree
ifdef USE_PGXSPG_CONFIG = pg_configPGXS := $(shell $(PG_CONFIG) --pgxs)include $(PGXS)elsesubdir = contrib/ltreetop_builddir = ../..include $(top_builddir)/src/Makefile.globalinclude $(top_srcdir)/contrib/contrib-global.mkendif
其中:
include $(PGXS)或 :include $(top_builddir)/src/Makefile.global
都指向了:
src/makefiles/pgxs.mk
这个makefile中会用到回归测试相关的两个变量:
# REGRESS -- list of regression test cases (without suffix)# REGRESS_OPTS -- additional switches to pass to pg_regress
引用
src/makefiles/pgxs.mk的部分内容如下:
ifdef REGRESS
# Select database to use for running the testsifneq ($(USE_MODULE_DB),)REGRESS_OPTS += --dbname=$(CONTRIB_TESTDB_MODULE)elseREGRESS_OPTS += --dbname=$(CONTRIB_TESTDB)endif
# where to find psql for running the testsPSQLDIR = $(bindir)
# When doing a VPATH build, must copy over the data files so that the# driver script can find them. We have to use an absolute path for# the targets, because otherwise make will try to locate the missing# files using VPATH, and will find them in $(srcdir), but the point# here is that we want to copy them from $(srcdir) to the build# directory.
ifdef VPATHabs_builddir := $(shell pwd)test_files_src := $(wildcard $(srcdir)/data/*.data)test_files_build := $(patsubst $(srcdir)/%, $(abs_builddir)/%, $(test_files_src))
all: $(test_files_build)$(test_files_build): $(abs_builddir)/%: $(srcdir)/%$(MKDIR_P) $(dir $@)ln -s $< $@endif # VPATH
.PHONY: submakesubmake:ifndef PGXS$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)endif
# against installed postmasterinstallcheck: submake $(REGRESS_PREP)$(pg_regress_installcheck) $(REGRESS_OPTS) $(REGRESS)
ifdef PGXScheck:@echo '"$(MAKE) check" is not supported.'@echo 'Do "$(MAKE) install", then "$(MAKE) installcheck" instead.'elsecheck: all submake $(REGRESS_PREP)$(pg_regress_check) --extra-install=$(subdir) $(REGRESS_OPTS) $(REGRESS)endifendif # REGRESS
这里用到了ltree中Makefile中定义的
subdir
和 REGRESS变量,如下:
top_builddir = ../..subdir = contrib/ltreeREGRESS = ltree
所以我们在contrib/ltree中执行make check会执行:(指
PGXS未定义时
)
$(pg_regress_check) --extra-install=$(subdir) $(REGRESS_OPTS) $(REGRESS)pg_regress_check这个变量在src/Makefile.global中定义了,其实就是pg_regress命令的调用:
src/Makefile.globalsrc/Makefile.global:srcdir = .pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE)pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
在contrib/ltree中执行make check最终执行的是(没有定义的变量直接忽略):
../../src/test/regress/pg_regress --inputdir=. --temp-install=./tmp_check --top-builddir=../.. --extra-install=contrib/ltree ltree
我们可以直接到ltree的源码目录测试这条命令:
[root@digoal ~]# chown -R postgres:postgres /opt/soft_bak/postgresql-9.4.4[root@digoal ~]# su - postgrespostgres@digoal-> cd /opt/soft_bak/postgresql-9.4.4/contrib/ltree/postgres@digoal-> ../../src/test/regress/pg_regress --inputdir=. --temp-install=./tmp_check --top-builddir=../.. --extra-install=contrib/ltree ltree============== removing existing temp installation ============================ creating temporary installation ============================ initializing database system ============================ starting postmaster ==============running on port 57636 with PID 27852============== creating database "regression" ==============CREATE DATABASEALTER DATABASE============== running regression test queries ==============test ltree ... ok============== shutting down postmaster ============================ removing temporary installation ==============
=====================All 1 tests passed.=====================
另外一种测试时installcheck,和check不同的是,installcheck不需要初始化数据库,是在我们开启了数据库集群的情况下的测试。
同样的方法,我们可以发现它调用的是:
$(pg_regress_installcheck) $(REGRESS_OPTS) $(REGRESS)
通过src/Makefile.global的定义:
pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir='$(PSQLDIR)' $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)bindir := $(shell $(PG_CONFIG) --bindir)
以及
src/makefiles/pgxs.mkPSQLDIR = $(bindir)
最终转换为:
../../src/test/regress/pg_regress --inputdir=. --psqldir='/opt/pgsql/bin' ltree
启动数据库后,就可以进行测试了。同样需要注意(PGPORT PGHOST PGDATABASE PGUSER等)环境变量。
postgres@digoal-> pg_ctl startpostgres@digoal-> pwd/opt/soft_bak/postgresql-9.4.4/contrib/ltreepostgres@digoal-> ../../src/test/regress/pg_regress --inputdir=. --psqldir='/opt/pgsql/bin' ltree(using postmaster on /data01/pg_root_1921, port 1921)============== dropping database "regression" ==============DROP DATABASE============== creating database "regression" ==============CREATE DATABASEALTER DATABASE============== running regression test queries ==============test ltree ... ok
=====================All 1 tests passed.=====================
所以插件的回归测试配置也很简单,同样需要sql, expected目录,以及通过配置Makefile来指定需要回归测试的sql脚本。
[参考]
各种Makefile
src/Makefile.global
src/Makefile
src/makefiles/pgxs.mk
contrib/contrib-global.mk
contrib/xx/Makefile
......
代码覆盖率测试见我另一篇BLOG
回归测试是PostgreSQL的测试方法之一。
回归测试,需要事先定义好测试脚本(通常是SQL脚本,放在sql目录中),同时定义好调用执行测试脚本的预期正确输出文件(通常放在expected目录中)。
测试使用make check或make installcheck进行,它会通过pg_regress程序调用sql目录中的SQL,并收集输出结果(通常放到results目录中),最后pg_regress会对expected目录和results目录中的文件使用diff进行一一比较。
如果比较发现文件内容不一致,会将不一致的结果输出到regression.diffs文件中,并返回这个TEST CASE failed。
但是这种测试方法实际上有一些需要注意的地方,例如我们使用不同的本地化设置,时区可能得到的结果和期望的结果就不一样。另外有些不可预知的结果,例如随机值,数据的顺序,执行计划和优化器相关参数有关。这些因素都可能导致测试结果和预期不一致,那么我们就需要人为去修复这种failed。
PostgreSQL的主代码测试文件在src/test/regress目录中。
这个目录的结构如下:
postgres@digoal-> ll -rttotal 1.2M-rw-r--r-- 1 postgres postgres 579 Jun 10 03:29 standby_schedule 测试standby的调度配置, 其实就是调度sql里的文件名-rw-r--r-- 1 postgres postgres 2.3K Jun 10 03:29 serial_schedule 串行测试的调度配置-rw-r--r-- 1 postgres postgres 937 Jun 10 03:29 resultmap 不同的测试平台的结果映射文件,因为不同平台某些测试结果可能不相同,所以一个expected文件不能支持所有的平台。例如浮点数测试。-rwxr-xr-x 1 postgres postgres 4.4K Jun 10 03:29 regressplans.sh-rw-r--r-- 1 postgres postgres 20K Jun 10 03:29 regress.c-rw-r--r-- 1 postgres postgres 159 Jun 10 03:29 README-rw-r--r-- 1 postgres postgres 2.7K Jun 10 03:29 pg_regress_main.c-rw-r--r-- 1 postgres postgres 1.6K Jun 10 03:29 pg_regress.h-rw-r--r-- 1 postgres postgres 69K Jun 10 03:29 pg_regress.c-rw-r--r-- 1 postgres postgres 3.6K Jun 10 03:29 parallel_schedule 并行测试的调度配置-rw-r--r-- 1 postgres postgres 624 Jun 10 03:29 Makefile-rw-r--r-- 1 postgres postgres 5.6K Jun 10 03:29 GNUmakefiledrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 outputdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 inputdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 data 一些测试数据drwxrwxrwx 2 postgres postgres 4.0K Sep 7 14:51 sql 测试用到的SQLdrwxrwxr-x 2 postgres postgres 4.0K Sep 7 14:52 results 通过pg_regress调用sql目录中的脚本,得到的结果drwxrwxrwx 2 postgres postgres 4.0K Sep 7 14:51 expected 执行sql目录中的文件对应的正确返回结果
上层目录结构如下,其中包含了一些其他的测试目标,例如隔离级别的测试,本地化测试,性能测试,线程安全测试。等。
postgres@digoal-> cd /opt/soft_bak/postgresql-9.4.4/src/testpostgres@digoal-> lltotal 36Kdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 examplesdrwxrwxrwx 4 postgres postgres 4.0K Jun 10 03:41 isolationdrwxrwxrwx 6 postgres postgres 4.0K Jun 10 03:38 locale-rw-r--r-- 1 postgres postgres 389 Jun 10 03:29 Makefiledrwxrwxrwx 4 postgres postgres 4.0K Jun 10 03:38 mbdrwxrwxrwx 4 postgres postgres 4.0K Jun 10 03:38 performancedrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 perldrwxrwxrwx 10 postgres postgres 4.0K Sep 7 19:17 regressdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 thread
接下来我们看看PostgreSQL的回归测试程序pg_regress的用法,它不会安装到PGHOME/bin中,只在src/test/regress中存在。
$ cd src/test/regress$ src/test/regress/pg_regress --helpPostgreSQL regression test driver
Usage:pg_regress [OPTION]... [EXTRA-TEST]...
Options:--config-auth=DATADIR update authentication settings for DATADIR--create-role=ROLE create the specified role before testing--dbname=DB use database DB (default "regression")--debug turn on debug mode in programs that are run--dlpath=DIR look for dynamic libraries in DIR--encoding=ENCODING use ENCODING as the encoding--inputdir=DIR take input files from DIR (default ".")--launcher=CMD use CMD as launcher of psql--load-extension=EXT load the named extension before running thetests; can appear multiple times--load-language=LANG load the named language before running thetests; can appear multiple times--max-connections=N maximum number of concurrent connections(default is 0, meaning unlimited)--outputdir=DIR place output files in DIR (default ".")--schedule=FILE use test ordering schedule from FILE(can be used multiple times to concatenate)--temp-install=DIR create a temporary installation in DIR--use-existing use an existing installation
Options for "temp-install" mode:--extra-install=DIR additional directory to install (e.g., contrib)--no-locale use C locale--port=PORT start postmaster on PORT--temp-config=FILE append contents of FILE to temporary config--top-builddir=DIR (relative) path to top level build directory
Options for using an existing installation:--host=HOST use postmaster running on HOST--port=PORT use postmaster running at PORT--user=USER connect as USER--psqldir=DIR use psql in DIR (default: configured bindir)
The exit status is 0 if all tests passed, 1 if some tests failed, and 2if the tests could not be run for some reason.
Report bugs to <pgsql-bugs@postgresql.org>.
回归测试用法:
在PostgreSQL源码根目录,或者源码的regress目录中执行如下:
make check // 测试时需要初始化数据库集群make installcheck // 使用以及启动的数据库集群测试,不需要初始化数据库集群
以下同时测试主代码以及contrib的代码:
make check-worldmake installcheck-world
如果要使用自定义的diff参数,可以设置一个环境变量,
例如:make check PG_REGRESS_DIFF_OPTS='-u'。
同时我们还可以使用不同的LOCALE进行测试。
例如:
make check LANG=de_DE.utf8make check NO_LOCALE=1make check LANG=C ENCODING=EUC_JP
当我们要测试调度中不包含的测试SQL时,可以使用EXTRA_TESTS参数,至于这些脚本为什么默认不包含在调度中,可能是因为这些SQL脚本可能对平台的依赖比较严重,所以没有放到默认的测试中。例如:
make check EXTRA_TESTS=collate.linux.utf8 LANG=en_US.utf8make check EXTRA_TESTS=numeric_big
接下来我们看看调度文件以及sql脚本目录:
postgres@digoal-> pwd/opt/soft_bak/postgresql-9.4.4/src/test/regresspostgres@digoal-> less serial_schedule# src/test/regress/serial_schedule# This should probably be in an order similar to parallel_schedule.test: tablespacetest: booleantest: chartest: nametest: varchartest: texttest: int2test: int4test: int8
......
并行调度
postgres@digoal-> less parallel_schedule
# ----------# src/test/regress/parallel_schedule## By convention, we put no more than twenty tests in any one parallel group;# this limits the number of connections needed to run the tests.# ----------# run tablespace by itself, and first, because it forces a checkpoint;# we'd prefer not to have checkpoints later in the tests because that# interferes with crash-recovery testing.test: tablespace
# ----------# The first group of parallel tests# ----------test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes pg_lsn regproc
......
调度文件的test:后面跟的就是sql目录下的文件名(不含.sql后缀)。
postgres@digoal-> less sql/total 1940drwxrwxrwx 2 postgres postgres 4096 Sep 7 14:51 ./drwxrwxrwx 10 postgres postgres 4096 Sep 7 22:34 ../-rw-r--r-- 1 postgres postgres 2237 Jun 10 03:29 abstime.sql-rw-r--r-- 1 postgres postgres 4097 Jun 10 03:29 advisory_lock.sql-rw-r--r-- 1 postgres postgres 20295 Jun 10 03:29 aggregates.sql-rw-r--r-- 1 postgres postgres 24882 Jun 10 03:29 alter_generic.sql-rw-r--r-- 1 postgres postgres 54461 Jun 10 03:29 alter_table.sql-rw-r--r-- 1 postgres postgres 17244 Jun 10 03:29 arrays.sql-rw-r--r-- 1 postgres postgres 594 Jun 10 03:29 async.sql-rw-r--r-- 1 postgres postgres 1365 Jun 10 03:29 bitmapops.sql-rw-r--r-- 1 postgres postgres 6406 Jun 10 03:29 bit.sql-rw-r--r-- 1 postgres postgres 4164 Jun 10 03:29 boolean.sql
......
所以前面提到的
EXTRA_TESTS实际上也是sql目录中的文件名(不带.sql后缀)。
make check EXTRA_TESTS=collate.linux.utf8 LANG=en_US.utf8make check EXTRA_TESTS=numeric_big
来实际的试一下吧:
postgres@digoal-> pwd/opt/soft_bak/postgresql-9.4.4/src/test/regresspostgres@digoal-> make installcheck-parallel //并行测试,使用已经开启的现有的数据库集群make -C ../../../src/port all......../../../src/test/regress/pg_regress --inputdir=. --psqldir='/opt/pgsql9.4.4/bin' --dlpath=. --schedule=./parallel_schedule(using postmaster on /data01/pg_root_1921, port 1921)============== dropping database "regression" ==============DROP DATABASE============== creating database "regression" ==============CREATE DATABASEALTER DATABASE============== running regression test queries ==============test tablespace ... ok......parallel group (19 tests): limit conversion sequence returning without_oid polymorphism copy2 xml prepare plancache rowtypes temp domain with truncate largeobject rangefuncs alter_table plpgsqlplancache ... oklimit ... okplpgsql ... okcopy2 ... oktemp ... okdomain ... okrangefuncs ... FAILEDprepare ... okwithout_oid ... okconversion ... oktruncate ... okalter_table ... oksequence ... okpolymorphism ... FAILEDrowtypes ... okreturning ... oklargeobject ... okwith ... FAILEDxml ... oktest stats ... ok......=========================22 of 145 tests failed.=========================
The differences that caused some tests to fail can be viewed in thefile "/opt/soft_bak/postgresql-9.4.4/src/test/regress/regression.diffs". A copy of the test summary that you seeabove is saved in the file "/opt/soft_bak/postgresql-9.4.4/src/test/regress/regression.out".
make: *** [installcheck-parallel] Error 1
有些测试失败了,diff文件已经输出到
/opt/soft_bak/postgresql-9.4.4/src/test/regress/regression.diffs,我们可以
查看一下看看为什么测试结果和预期结果不一致。
postgres@digoal-> less regression.diffs*** /opt/soft_bak/postgresql-9.4.4/src/test/regress/expected/pg_lsn.out 2015-06-10 03:29:38.000000000 +0800--- /opt/soft_bak/postgresql-9.4.4/src/test/regress/results/pg_lsn.out 2015-09-07 22:45:04.413922536 +0800****************** 72,92 ****generate_series(1, 5) kWHERE i <= 10 AND j > 0 AND j <= 10ORDER BY f;! QUERY PLAN! --------------------------------------------------------------------------! Sort! Sort Key: (((((i.i)::text || '/'::text) || (j.j)::text))::pg_lsn)! -> HashAggregate! Group Key: ((((i.i)::text || '/'::text) || (j.j)::text))::pg_lsn-> Nested Loop-> Function Scan on generate_series k! -> Materialize! -> Nested Loop! -> Function Scan on generate_series j! Filter: ((j > 0) AND (j <= 10))! -> Function Scan on generate_series i! Filter: (i <= 10)! (12 rows)SELECT DISTINCT (i || '/' || j)::pg_lsn fFROM generate_series(1, 10) i,--- 72,90 ----generate_series(1, 5) kWHERE i <= 10 AND j > 0 AND j <= 10ORDER BY f;......
对于主代码,如果我们需要自定义测试SQL,我们可以修改regress/sql目录下的文件,或者新增文件。同时修改regress/expected目录下的对应期望文件,或者现在期望文件。
如果是新增文件的情况,我们还需要修改调度文件regress/serial_schedule和regress/parallel_schedule,把测试加入调度。
最后,再以ltree插件为例,看看如何配置一个外加插件的回归测试。
ltree的源码目录:
postgres@digoal-> cd contrib/postgres@digoal-> cd ltree/postgres@digoal-> ll -rttotal 1.1M-rw-r--r-- 1 postgres postgres 517 Jun 10 03:29 Makefile-rw-r--r-- 1 postgres postgres 2.4K Jun 10 03:29 ltxtquery_op.c-rw-r--r-- 1 postgres postgres 11K Jun 10 03:29 ltxtquery_io.c-rw-r--r-- 1 postgres postgres 7.9K Jun 10 03:29 ltree--unpackaged--1.0.sql-rw-r--r-- 1 postgres postgres 994 Jun 10 03:29 ltreetest.sql-rw-r--r-- 1 postgres postgres 13K Jun 10 03:29 ltree_op.c-rw-r--r-- 1 postgres postgres 6.9K Jun 10 03:29 _ltree_op.c-rw-r--r-- 1 postgres postgres 14K Jun 10 03:29 ltree_io.c-rw-r--r-- 1 postgres postgres 7.3K Jun 10 03:29 ltree.h-rw-r--r-- 1 postgres postgres 16K Jun 10 03:29 ltree_gist.c-rw-r--r-- 1 postgres postgres 13K Jun 10 03:29 _ltree_gist.c-rw-r--r-- 1 postgres postgres 155 Jun 10 03:29 ltree.control-rw-r--r-- 1 postgres postgres 18K Jun 10 03:29 ltree--1.0.sql-rw-r--r-- 1 postgres postgres 7.1K Jun 10 03:29 lquery_op.c-rw-r--r-- 1 postgres postgres 263 Jun 10 03:29 crc32.h-rw-r--r-- 1 postgres postgres 4.1K Jun 10 03:29 crc32.cdrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 sqldrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 expecteddrwxrwxrwx 2 postgres postgres 4.0K Jun 10 03:38 data
contrib/ltree的Makefile如下(在这里配置回归测试的调度,用到变量REGRESS,对应sql目录中的脚本文件名):
# contrib/ltree/Makefile
MODULE_big = ltreeOBJS = ltree_io.o ltree_op.o lquery_op.o _ltree_op.o crc32.o \ltxtquery_io.o ltxtquery_op.o ltree_gist.o _ltree_gist.oPG_CPPFLAGS = -DLOWER_NODE
EXTENSION = ltreeDATA = ltree--1.0.sql ltree--unpackaged--1.0.sql
REGRESS = ltree
ifdef USE_PGXSPG_CONFIG = pg_configPGXS := $(shell $(PG_CONFIG) --pgxs)include $(PGXS)elsesubdir = contrib/ltreetop_builddir = ../..include $(top_builddir)/src/Makefile.globalinclude $(top_srcdir)/contrib/contrib-global.mkendif
其中:
include $(PGXS)或 :include $(top_builddir)/src/Makefile.global
都指向了:
src/makefiles/pgxs.mk
这个makefile中会用到回归测试相关的两个变量:
# REGRESS -- list of regression test cases (without suffix)# REGRESS_OPTS -- additional switches to pass to pg_regress
引用
src/makefiles/pgxs.mk的部分内容如下:
ifdef REGRESS
# Select database to use for running the testsifneq ($(USE_MODULE_DB),)REGRESS_OPTS += --dbname=$(CONTRIB_TESTDB_MODULE)elseREGRESS_OPTS += --dbname=$(CONTRIB_TESTDB)endif
# where to find psql for running the testsPSQLDIR = $(bindir)
# When doing a VPATH build, must copy over the data files so that the# driver script can find them. We have to use an absolute path for# the targets, because otherwise make will try to locate the missing# files using VPATH, and will find them in $(srcdir), but the point# here is that we want to copy them from $(srcdir) to the build# directory.
ifdef VPATHabs_builddir := $(shell pwd)test_files_src := $(wildcard $(srcdir)/data/*.data)test_files_build := $(patsubst $(srcdir)/%, $(abs_builddir)/%, $(test_files_src))
all: $(test_files_build)$(test_files_build): $(abs_builddir)/%: $(srcdir)/%$(MKDIR_P) $(dir $@)ln -s $< $@endif # VPATH
.PHONY: submakesubmake:ifndef PGXS$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)endif
# against installed postmasterinstallcheck: submake $(REGRESS_PREP)$(pg_regress_installcheck) $(REGRESS_OPTS) $(REGRESS)
ifdef PGXScheck:@echo '"$(MAKE) check" is not supported.'@echo 'Do "$(MAKE) install", then "$(MAKE) installcheck" instead.'elsecheck: all submake $(REGRESS_PREP)$(pg_regress_check) --extra-install=$(subdir) $(REGRESS_OPTS) $(REGRESS)endifendif # REGRESS
这里用到了ltree中Makefile中定义的
subdir
和 REGRESS变量,如下:
top_builddir = ../..subdir = contrib/ltreeREGRESS = ltree
所以我们在contrib/ltree中执行make check会执行:(指
PGXS未定义时
)
$(pg_regress_check) --extra-install=$(subdir) $(REGRESS_OPTS) $(REGRESS)pg_regress_check这个变量在src/Makefile.global中定义了,其实就是pg_regress命令的调用:
src/Makefile.globalsrc/Makefile.global:srcdir = .pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE)pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
在contrib/ltree中执行make check最终执行的是(没有定义的变量直接忽略):
../../src/test/regress/pg_regress --inputdir=. --temp-install=./tmp_check --top-builddir=../.. --extra-install=contrib/ltree ltree
我们可以直接到ltree的源码目录测试这条命令:
[root@digoal ~]# chown -R postgres:postgres /opt/soft_bak/postgresql-9.4.4[root@digoal ~]# su - postgrespostgres@digoal-> cd /opt/soft_bak/postgresql-9.4.4/contrib/ltree/postgres@digoal-> ../../src/test/regress/pg_regress --inputdir=. --temp-install=./tmp_check --top-builddir=../.. --extra-install=contrib/ltree ltree============== removing existing temp installation ============================ creating temporary installation ============================ initializing database system ============================ starting postmaster ==============running on port 57636 with PID 27852============== creating database "regression" ==============CREATE DATABASEALTER DATABASE============== running regression test queries ==============test ltree ... ok============== shutting down postmaster ============================ removing temporary installation ==============
=====================All 1 tests passed.=====================
另外一种测试时installcheck,和check不同的是,installcheck不需要初始化数据库,是在我们开启了数据库集群的情况下的测试。
同样的方法,我们可以发现它调用的是:
$(pg_regress_installcheck) $(REGRESS_OPTS) $(REGRESS)
通过src/Makefile.global的定义:
pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir='$(PSQLDIR)' $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)bindir := $(shell $(PG_CONFIG) --bindir)
以及
src/makefiles/pgxs.mkPSQLDIR = $(bindir)
最终转换为:
../../src/test/regress/pg_regress --inputdir=. --psqldir='/opt/pgsql/bin' ltree
启动数据库后,就可以进行测试了。同样需要注意(PGPORT PGHOST PGDATABASE PGUSER等)环境变量。
postgres@digoal-> pg_ctl startpostgres@digoal-> pwd/opt/soft_bak/postgresql-9.4.4/contrib/ltreepostgres@digoal-> ../../src/test/regress/pg_regress --inputdir=. --psqldir='/opt/pgsql/bin' ltree(using postmaster on /data01/pg_root_1921, port 1921)============== dropping database "regression" ==============DROP DATABASE============== creating database "regression" ==============CREATE DATABASEALTER DATABASE============== running regression test queries ==============test ltree ... ok
=====================All 1 tests passed.=====================
所以插件的回归测试配置也很简单,同样需要sql, expected目录,以及通过配置Makefile来指定需要回归测试的sql脚本。
[参考]
各种Makefile
src/Makefile.global
src/Makefile
src/makefiles/pgxs.mk
contrib/contrib-global.mk
contrib/xx/Makefile
......
代码覆盖率测试见我另一篇BLOG