diff --git a/src/test/obj_ulog_size/Makefile b/src/test/obj_ulog_size/Makefile
index 89c3de35945733e56ecdc0c52c5eb66203f85b34..3ec2ae5475b1a0df148aa0611a014a17110946b1 100644
--- a/src/test/obj_ulog_size/Makefile
+++ b/src/test/obj_ulog_size/Makefile
@@ -33,9 +33,13 @@
 #
 # src/test/obj_ulog_size/Makefile -- build obj_ulog_size unit test
 #
+
+TOP = ../../..
+
 TARGET = obj_ulog_size
 OBJS = obj_ulog_size.o
 
-LIBPMEMOBJ=internal-debug
+LIBPMEMOBJ=y
 
 include ../Makefile.inc
+CFLAGS += -I$(TOP)/src/libpmemobj/
diff --git a/src/test/obj_ulog_size/TEST0.PS1 b/src/test/obj_ulog_size/TEST0.PS1
deleted file mode 100644
index b3f1e44d2ef87df0c39a7e20483040ca9179c76c..0000000000000000000000000000000000000000
--- a/src/test/obj_ulog_size/TEST0.PS1
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Copyright 2019, Intel Corporation
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#
-#     * Redistributions in binary form must reproduce the above copyright
-#       notice, this list of conditions and the following disclaimer in
-#       the documentation and/or other materials provided with the
-#       distribution.
-#
-#     * Neither the name of the copyright holder nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-#
-# src/test/obj_ulog_size/TEST0 -- unit test for pmemobj_tx_publish abort
-#
-
-. ..\unittest\unittest.ps1
-
-require_test_type medium
-
-setup
-
-create_holey_file 16M $DIR\testfile
-
-expect_normal_exit $Env:EXE_DIR\obj_ulog_size$Env:EXESUFFIX $DIR\testfile
-
-check
-
-pass
diff --git a/src/test/obj_ulog_size/TEST1 b/src/test/obj_ulog_size/TEST1
deleted file mode 100755
index a31d6338be8c28072f2f338e32be26ae6e9d878c..0000000000000000000000000000000000000000
--- a/src/test/obj_ulog_size/TEST1
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright 2019, Intel Corporation
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#
-#     * Redistributions in binary form must reproduce the above copyright
-#       notice, this list of conditions and the following disclaimer in
-#       the documentation and/or other materials provided with the
-#       distribution.
-#
-#     * Neither the name of the copyright holder nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-#
-# src/test/obj_ulog_size/TEST1 -- unit test for pmemobj_tx_publish abort
-#
-
-. ../unittest/unittest.sh
-
-require_test_type medium
-configure_valgrind memcheck force-enable
-
-setup
-
-create_holey_file 16M $DIR/testfile
-
-expect_normal_exit ./obj_ulog_size$EXESUFFIX $DIR/testfile
-
-check
-
-pass
diff --git a/src/test/obj_ulog_size/TEST0 b/src/test/obj_ulog_size/TESTS.py
old mode 100755
new mode 100644
similarity index 76%
rename from src/test/obj_ulog_size/TEST0
rename to src/test/obj_ulog_size/TESTS.py
index fb1f931523c649b7e4c750cec7dfbadb30fb54a7..4980ac013f8d5da96d590e1fd740be9a88112b0a
--- a/src/test/obj_ulog_size/TEST0
+++ b/src/test/obj_ulog_size/TESTS.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!../env.py
 #
 # Copyright 2019, Intel Corporation
 #
@@ -31,20 +31,24 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
-#
-# src/test/obj_ulog_size/TEST0 -- unit test for pmemobj_tx_publish abort
-#
-
-. ../unittest/unittest.sh
 
-require_test_type medium
+import testframework as t
 
-setup
+class BASE(t.BaseTest):
+    test_type = t.Medium
+    build = [t.Debug, t.Release]
 
-create_holey_file 16M $DIR/testfile
+    def run(self, ctx):
+        filepath = ctx.create_holey_file(16 * t.MiB, 'testfile')
+        filepath1 = ctx.create_holey_file(16 * t.MiB, 'testfile1')
+        ctx.exec('obj_ulog_size', filepath, filepath1)
 
-expect_normal_exit ./obj_ulog_size$EXESUFFIX $DIR/testfile
+class TEST0(BASE):
+    memcheck = t.DISABLE
+    pmemcheck = t.DISABLE
 
-check
+class TEST1(BASE):
+    memcheck = t.ENABLE
 
-pass
+class TEST2(BASE):
+    pmemcheck = t.ENABLE
diff --git a/src/test/obj_ulog_size/obj_ulog_size.c b/src/test/obj_ulog_size/obj_ulog_size.c
index faa77d6396e32633f91dcd09265ebc8a13313559..2662a39e6822cecaa7fae0c25cd6dc5112c8edab 100644
--- a/src/test/obj_ulog_size/obj_ulog_size.c
+++ b/src/test/obj_ulog_size/obj_ulog_size.c
@@ -32,7 +32,7 @@
 
 /*
  * obj_ulog_size.c -- unit tests for pmemobj_action API and
- *		redo, undo logs
+ * redo, undo logs
  */
 #include <sys/param.h>
 #include <string.h>
@@ -41,23 +41,33 @@
 #include "unittest.h"
 
 /*
- * lane.h -- needed for LANE_REDO_EXTERNAL_SIZE
+ * tx.h -- needed for TX_SNAPSHOT_LOG_ENTRY_ALIGNMENT,
+ * TX_SNAPSHOT_LOG_BUFFER_OVERHEAD, TX_SNAPSHOT_LOG_ENTRY_OVERHEAD,
+ * TX_INTENT_LOG_BUFFER_ALIGNMENT, TX_INTENT_LOG_BUFFER_OVERHEAD,
+ * TX_INTENT_LOG_ENTRY_OVERHEAD
  */
-#include "lane.h"
+#include "tx.h"
 
-/*
- * TX_INTENT_LOG_ENTRY_OVERHEAD -- sizeof(struct ulog_entry_val)
- */
-#define TX_INTENT_LOG_ENTRY_OVERHEAD (0b01ULL << 4) /* 16 bytes */
+/* needed for LANE_REDO_EXTERNAL_SIZE and LANE_UNDO_SIZE */
+#include "lane.h"
 
 #define LAYOUT_NAME "obj_ulog_size"
 
 #define MIN_ALLOC 64
 #define MAX_ALLOC (1024 * 1024)
+#define HALF_OF_DEFAULT_UNDO_SIZE (LANE_UNDO_SIZE / 2)
+#define ARRAY_SIZE_COMMON 3
+
+/* the ranges of indices are describing the use of some allocations */
+#define LOG_BUFFER 0
+#define LOG_BUFFER_NUM 6
+#define RANGE (LOG_BUFFER + LOG_BUFFER_NUM)
+#define RANGE_NUM 6
+#define MIN_NOIDS (RANGE + RANGE_NUM)
 
 /*
  * REDO_OVERFLOW -- size for trigger out of memory
- *     during redo log extension
+ * during redo log extension
  */
 #define REDO_OVERFLOW ((size_t)((LANE_REDO_EXTERNAL_SIZE\
 		/ TX_INTENT_LOG_ENTRY_OVERHEAD) + 1))
@@ -102,8 +112,8 @@ fill_pool(PMEMobjpool *pop, size_t *noids)
 				(*noids)++;
 			if (*noids == oids_size) {
 				oids_size *= 2;
-				oids = (PMEMoid *)REALLOC(oids, oids_size
-					* sizeof(PMEMoid));
+				oids = (PMEMoid *)REALLOC(oids, oids_size *
+					sizeof(PMEMoid));
 			}
 		}
 	}
@@ -112,7 +122,7 @@ fill_pool(PMEMobjpool *pop, size_t *noids)
 
 /*
  * do_tx_max_alloc_tx_publish_abort -- fills the pool and then tries
- *		to overfill redo log - transaction abort expected
+ * to overfill redo log - transaction abort expected
  */
 static void
 do_tx_max_alloc_tx_publish_abort(PMEMobjpool *pop)
@@ -129,27 +139,367 @@ do_tx_max_alloc_tx_publish_abort(PMEMobjpool *pop)
 	}
 
 	allocated = fill_pool(pop, &nallocated);
+	UT_ASSERT(nallocated >= MIN_NOIDS);
 
 	/* it should abort - cannot extend redo log */
 	TX_BEGIN(pop) {
 		pmemobj_tx_publish(act, REDO_OVERFLOW);
 	} TX_ONABORT {
-		UT_OUT("!Cannot publish");
+		UT_OUT("!Cannot extend redo log - the pool is full");
 	} TX_ONCOMMIT {
-		UT_FATAL("Can publish");
+		UT_FATAL("Can extend redo log despite the pool is full");
 	} TX_END
 
 	free_pool(allocated, nallocated);
 	pmemobj_cancel(pop, act, REDO_OVERFLOW);
 }
 
+/*
+ * do_tx_max_alloc_no_user_alloc_snap -- fills the pool and tries to do
+ * snapshot which is bigger than ulog size
+ */
+static void
+do_tx_max_alloc_no_user_alloc_snap(PMEMobjpool *pop)
+{
+	UT_OUT("do_tx_max_alloc_no_user_alloc_snap");
+	size_t nallocated = 0;
+	PMEMoid *allocated = fill_pool(pop, &nallocated);
+	UT_ASSERT(nallocated >= MIN_NOIDS);
+
+	size_t range_size = pmemobj_alloc_usable_size(allocated[LOG_BUFFER]);
+	UT_ASSERT(range_size > LANE_UNDO_SIZE);
+
+	void *range_addr = pmemobj_direct(allocated[LOG_BUFFER]);
+	pmemobj_memset(pop, range_addr, 0, range_size, 0);
+
+	TX_BEGIN(pop) {
+		/* it should abort - cannot extend undo log */
+		pmemobj_tx_add_range(allocated[LOG_BUFFER], 0, range_size);
+	} TX_ONABORT {
+		UT_OUT("!Cannot extend undo log - the pool is full");
+	} TX_ONCOMMIT {
+		UT_FATAL("Can extend undo log despite the pool is full");
+	} TX_END
+
+	free_pool(allocated, nallocated);
+}
+
+/*
+ * do_tx_max_alloc_user_alloc_snap -- fills the pool, appends allocated
+ * buffer and tries to do snapshot which is bigger than ulog size
+ */
+static void
+do_tx_max_alloc_user_alloc_snap(PMEMobjpool *pop)
+{
+	UT_OUT("do_tx_max_alloc_user_alloc_snap");
+	size_t nallocated = 0;
+	PMEMoid *allocated = fill_pool(pop, &nallocated);
+	UT_ASSERT(nallocated >= MIN_NOIDS);
+
+	size_t buff_size = pmemobj_alloc_usable_size(allocated[LOG_BUFFER]);
+	void *buff_addr = pmemobj_direct(allocated[LOG_BUFFER]);
+	size_t range_size = pmemobj_alloc_usable_size(allocated[RANGE]);
+	UT_ASSERT(range_size > LANE_UNDO_SIZE);
+
+	void *range_addr = pmemobj_direct(allocated[RANGE]);
+	pmemobj_memset(pop, range_addr, 0, range_size, 0);
+
+	TX_BEGIN(pop) {
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addr, buff_size);
+		pmemobj_tx_add_range(allocated[RANGE], 0, range_size);
+	} TX_ONABORT {
+		UT_FATAL("!Cannot use the user appended undo log buffer");
+	} TX_ONCOMMIT {
+		UT_OUT("Can use the user appended undo log buffer");
+	} TX_END
+
+	free_pool(allocated, nallocated);
+}
+
+/*
+ * do_tx_max_alloc_user_alloc_nested -- example of buffer appending
+ * allocated by the user in a nested transaction
+ */
+static void
+do_tx_max_alloc_user_alloc_nested(PMEMobjpool *pop)
+{
+	UT_OUT("do_tx_max_alloc_user_alloc_nested");
+	size_t nallocated = 0;
+	PMEMoid *allocated = fill_pool(pop, &nallocated);
+	UT_ASSERT(nallocated >= MIN_NOIDS);
+
+	size_t buff_size = pmemobj_alloc_usable_size(allocated[LOG_BUFFER]);
+	void *buff_addr = pmemobj_direct(allocated[LOG_BUFFER]);
+	size_t range_size = pmemobj_alloc_usable_size(allocated[RANGE]);
+
+	void *range_addr = pmemobj_direct(allocated[RANGE]);
+	pmemobj_memset(pop, range_addr, 0, range_size, 0);
+
+	TX_BEGIN(pop) {
+		TX_BEGIN(pop) {
+			pmemobj_tx_log_append_buffer(
+				TX_LOG_TYPE_SNAPSHOT, buff_addr, buff_size);
+			pmemobj_tx_add_range(allocated[RANGE], 0, range_size);
+		} TX_ONABORT {
+			UT_FATAL("Cannot use the undo log appended by the user "
+				"in a nested transaction");
+		} TX_ONCOMMIT {
+			UT_OUT("Can use the undo log appended by the user in "
+				"a nested transaction");
+		} TX_END
+	} TX_END
+
+	free_pool(allocated, nallocated);
+}
+
+/*
+ * do_tx_max_alloc_user_alloc_snap_multi -- appending of many buffers
+ * in one transaction
+ */
+static void
+do_tx_max_alloc_user_alloc_snap_multi(PMEMobjpool *pop)
+{
+	UT_OUT("do_tx_max_alloc_user_alloc_snap_multi");
+	size_t nallocated = 0;
+	PMEMoid *allocated = fill_pool(pop, &nallocated);
+	UT_ASSERT(nallocated >= MIN_NOIDS);
+
+	size_t buff_sizes[ARRAY_SIZE_COMMON];
+	void *buff_addrs[ARRAY_SIZE_COMMON];
+	size_t range_sizes[ARRAY_SIZE_COMMON];
+	void *range_addrs[ARRAY_SIZE_COMMON];
+
+	UT_COMPILE_ERROR_ON((ARRAY_SIZE_COMMON - 1) * 2 >= LOG_BUFFER_NUM);
+	UT_COMPILE_ERROR_ON((ARRAY_SIZE_COMMON - 1) * 2 >= RANGE_NUM);
+
+	for (unsigned long i = 0; i < ARRAY_SIZE_COMMON; i++) {
+		/* we multiply the value to not use continuous memory blocks */
+		buff_sizes[i] = pmemobj_alloc_usable_size(
+			allocated[LOG_BUFFER + (i *2)]);
+		buff_addrs[i] = pmemobj_direct(
+			allocated[LOG_BUFFER + (i * 2)]);
+		range_sizes[i] = pmemobj_alloc_usable_size(
+			allocated[RANGE + (i * 2)]);
+		range_addrs[i] = pmemobj_direct(allocated[RANGE + (i * 2)]);
+
+		pmemobj_memset(pop, range_addrs[i], 0, range_sizes[i], 0);
+	}
+
+	errno = 0;
+	TX_BEGIN(pop) {
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addrs[0], buff_sizes[0]);
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addrs[1], buff_sizes[1]);
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addrs[2], buff_sizes[1]);
+
+		for (unsigned long i = 0; i < ARRAY_SIZE_COMMON; i++) {
+			pmemobj_tx_add_range(allocated[RANGE + (i * 2)], 0,
+			range_sizes[i]);
+		}
+	} TX_ONABORT {
+		UT_FATAL("!Cannot use multiple user appended undo log buffers");
+	} TX_ONCOMMIT {
+		UT_OUT("Can use multiple user appended undo log buffers");
+	} TX_END
+
+	/* check if all user allocated buffers are used */
+	errno = 0;
+	TX_BEGIN(pop) {
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addrs[0], buff_sizes[0]);
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addrs[1], buff_sizes[1]);
+		/*
+		 * do not append last buffer to make sure it is needed for this
+		 * transaction to succeed
+		 */
+		pmemobj_tx_add_range(allocated[RANGE + 0], 0, range_sizes[0]);
+		pmemobj_tx_add_range(allocated[RANGE + 2], 0, range_sizes[1]);
+		pmemobj_tx_add_range(allocated[RANGE + 4], 0, range_sizes[2]);
+	} TX_ONABORT {
+		UT_OUT("!All user appended undo log buffers are used");
+	} TX_ONCOMMIT {
+		UT_FATAL("Not all user appended undo log buffers are required "
+			"- too small ranges");
+	} TX_END
+
+	free_pool(allocated, nallocated);
+}
+
+/*
+ * do_tx_auto_alloc_disabled -- blocking of automatic expansion
+ * of ulog. When auto expansion of ulog is off, snapshot with size
+ * of default undo log is going to fail, because of buffer overhead
+ * (size of internal undo log and header size).
+ */
+static void
+do_tx_auto_alloc_disabled(PMEMobjpool *pop)
+{
+	UT_OUT("do_tx_auto_alloc_disabled");
+	PMEMoid oid0, oid1;
+
+	int ret = pmemobj_zalloc(pop, &oid0, HALF_OF_DEFAULT_UNDO_SIZE, 0);
+	UT_ASSERTeq(ret, 0);
+	ret = pmemobj_zalloc(pop, &oid1, HALF_OF_DEFAULT_UNDO_SIZE, 0);
+	UT_ASSERTeq(ret, 0);
+
+	TX_BEGIN(pop) {
+		pmemobj_tx_log_auto_alloc(TX_LOG_TYPE_SNAPSHOT, 0);
+		pmemobj_tx_add_range(oid0, 0, HALF_OF_DEFAULT_UNDO_SIZE);
+		/* it should abort - cannot extend ulog (first entry is full) */
+		pmemobj_tx_add_range(oid1, 0, HALF_OF_DEFAULT_UNDO_SIZE);
+	} TX_ONABORT {
+		UT_OUT("!Cannot add to undo log the range bigger than the undo "
+			"log default size - the auto alloc is disabled");
+	} TX_ONCOMMIT {
+		UT_FATAL("!Can add to undo log the range bigger than the undo "
+			"log default size despite the auto alloc is disabled");
+	} TX_END
+
+	pmemobj_free(&oid0);
+	pmemobj_free(&oid1);
+}
+
+/*
+ * do_tx_max_alloc_wrong_pop_addr -- allocates two pools and tries to
+ * do transaction with the first pool and address from the second
+ * pool. Abort expected - cannot allocate from different pool.
+ */
+static void
+do_tx_max_alloc_wrong_pop_addr(PMEMobjpool *pop, PMEMobjpool *pop2)
+{
+	UT_OUT("do_tx_max_alloc_wrong_pop_addr");
+	size_t nallocated = 0;
+	PMEMoid *allocated = fill_pool(pop, &nallocated);
+	UT_ASSERT(nallocated >= MIN_NOIDS);
+	PMEMoid oid2;
+
+	int ret = pmemobj_alloc(pop2, &oid2, MAX_ALLOC, 0, NULL, NULL);
+	UT_ASSERTeq(ret, 0);
+
+	/* pools are allocated now, let's try to get address from wrong pool */
+	size_t buff2_size = pmemobj_alloc_usable_size(oid2);
+	void *buff2_addr = pmemobj_direct(oid2);
+
+	/* abort expected - cannot allocate from different pool */
+	TX_BEGIN(pop) {
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff2_addr, buff2_size);
+	} TX_ONABORT {
+		UT_OUT("!Cannot append an undo log buffer from a different "
+			"memory pool");
+	} TX_ONCOMMIT {
+		UT_FATAL("Can append an undo log buffer from a different "
+			"memory pool");
+	} TX_END
+
+	free_pool(allocated, nallocated);
+	pmemobj_free(&oid2);
+}
+
+/*
+ * do_tx_buffer_currently_used -- the same buffer cannot be used
+ * twice in the same time.
+ */
+static void
+do_tx_buffer_currently_used(PMEMobjpool *pop)
+{
+	UT_OUT("do_tx_buffer_currently_used");
+
+	PMEMoid oid_buff;
+	int verify_user_buffers = 1;
+
+	/* by default verify_user_buffers should be 0 */
+	int ret = pmemobj_ctl_get(pop, "tx.debug.verify_user_buffers",
+					&verify_user_buffers);
+	UT_ASSERTeq(ret, 0);
+	UT_ASSERTeq(verify_user_buffers, 0);
+
+	int err = pmemobj_alloc(pop, &oid_buff, MAX_ALLOC, 0, NULL, NULL);
+	UT_ASSERTeq(err, 0);
+	/* this buffer we will try to use twice */
+	size_t buff_size = pmemobj_alloc_usable_size(oid_buff);
+	void *buff_addr = pmemobj_direct(oid_buff);
+
+	/* changes verify_user_buffers value */
+	verify_user_buffers = 1;
+	ret = pmemobj_ctl_set(pop, "tx.debug.verify_user_buffers",
+			&verify_user_buffers);
+	UT_ASSERTeq(ret, 0);
+
+	verify_user_buffers = 99;
+	/* check if verify_user_buffers has changed */
+	ret = pmemobj_ctl_get(pop, "tx.debug.verify_user_buffers",
+					&verify_user_buffers);
+	UT_ASSERTeq(ret, 0);
+	UT_ASSERTeq(verify_user_buffers, 1);
+
+	/* if verify_user_buffers is set we should abort tx */
+	TX_BEGIN(pop) {
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addr, buff_size);
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_SNAPSHOT, buff_addr, buff_size);
+	} TX_ONABORT {
+		UT_OUT("!User cannot append the same undo log buffer twice");
+	} TX_ONCOMMIT {
+		UT_FATAL("User can append the same undo log buffer twice");
+	} TX_END
+
+	pmemobj_free(&oid_buff);
+}
+
+/*
+ * do_tx_max_alloc_tx_publish -- fills the pool and then tries
+ * to overfill redo log with appended buffer
+ */
+static void
+do_tx_max_alloc_tx_publish(PMEMobjpool *pop)
+{
+	UT_OUT("do_tx_max_alloc_tx_publish");
+	PMEMoid *allocated = NULL;
+	PMEMoid reservations[REDO_OVERFLOW];
+	size_t nallocated = 0;
+	struct pobj_action act[REDO_OVERFLOW];
+
+	for (int i = 0; i < REDO_OVERFLOW; i++) {
+		reservations[i] = pmemobj_reserve(pop, &act[i], MIN_ALLOC, 0);
+		UT_ASSERT(!OID_IS_NULL(reservations[i]));
+	}
+
+	allocated = fill_pool(pop, &nallocated);
+	UT_ASSERT(nallocated >= MIN_NOIDS);
+
+	size_t buff_size = pmemobj_alloc_usable_size(allocated[LOG_BUFFER]);
+	void *buff_addr = pmemobj_direct(allocated[LOG_BUFFER]);
+
+	TX_BEGIN(pop) {
+		pmemobj_tx_log_append_buffer(
+			TX_LOG_TYPE_INTENT, buff_addr, buff_size);
+		pmemobj_tx_publish(act, REDO_OVERFLOW);
+	} TX_ONABORT {
+		UT_FATAL("!Cannot extend redo log despite appended buffer");
+	} TX_ONCOMMIT {
+		UT_OUT("Can extend redo log with appended buffer");
+	} TX_END
+
+	free_pool(allocated, nallocated);
+
+	for (int i = 0; i < REDO_OVERFLOW; ++i) {
+		pmemobj_free(&reservations[i]);
+	}
+}
+
 int
 main(int argc, char *argv[])
 {
 	START(argc, argv, "obj_ulog_size");
 
-	if (argc != 2)
-		UT_FATAL("usage: %s [file]", argv[0]);
+	if (argc != 3)
+		UT_FATAL("usage: %s [file] [file1]", argv[0]);
 
 	PMEMobjpool *pop = pmemobj_create(argv[1], LAYOUT_NAME, 0,
 		S_IWUSR | S_IRUSR);
@@ -157,20 +507,24 @@ main(int argc, char *argv[])
 	if (pop == NULL)
 		UT_FATAL("!pmemobj_create");
 
+	PMEMobjpool *pop2 = pmemobj_create(argv[2], LAYOUT_NAME, 0,
+		S_IWUSR | S_IRUSR);
+
+	if (pop2 == NULL)
+		UT_FATAL("!pmemobj_create");
+
+	do_tx_max_alloc_no_user_alloc_snap(pop);
+	do_tx_max_alloc_user_alloc_snap(pop);
+	do_tx_max_alloc_user_alloc_nested(pop);
+	do_tx_max_alloc_user_alloc_snap_multi(pop);
+	do_tx_auto_alloc_disabled(pop);
+	do_tx_max_alloc_wrong_pop_addr(pop, pop2);
 	do_tx_max_alloc_tx_publish_abort(pop);
+	do_tx_buffer_currently_used(pop);
+	do_tx_max_alloc_tx_publish(pop);
 
 	pmemobj_close(pop);
+	pmemobj_close(pop2);
 
 	DONE(NULL);
 }
-
-#ifdef _MSC_VER
-extern "C" {
-	/*
-	 * Since libpmemobj is linked statically,
-	 * we need to invoke its ctor/dtor.
-	 */
-	MSVC_CONSTR(libpmemobj_init)
-	MSVC_DESTR(libpmemobj_fini)
-}
-#endif
diff --git a/src/test/obj_ulog_size/obj_ulog_size.vcxproj b/src/test/obj_ulog_size/obj_ulog_size.vcxproj
index c18cae00b29965b49a145edecab4a5121bc7b488..94744f94594c91c2b83b3c3b2c28ee6f49a0a9a8 100644
--- a/src/test/obj_ulog_size/obj_ulog_size.vcxproj
+++ b/src/test/obj_ulog_size/obj_ulog_size.vcxproj
@@ -65,102 +65,6 @@
     <Link />
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClCompile Include="..\..\common\ctl.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\common\ctl_prefault.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\common\ctl_sds.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\bucket.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\ravl.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\ctl_debug.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\critnib.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\heap.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\lane.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\libpmemobj.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\list.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\memblock.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\memops.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\obj.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\palloc.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\pmalloc.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\ulog.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\sync.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\tx.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\recycler.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\container_ravl.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\container_seglists.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\alloc_class.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\stats.c">
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsC</CompileAs>
-      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsC</CompileAs>
-    </ClCompile>
     <ClCompile Include="obj_ulog_size.c" />
   </ItemGroup>
   <ItemGroup>
@@ -173,7 +77,7 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="out0.log.match" />
-    <None Include="TEST0.PS1" />
+    <None Include="TESTS.py" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
diff --git a/src/test/obj_ulog_size/obj_ulog_size.vcxproj.filters b/src/test/obj_ulog_size/obj_ulog_size.vcxproj.filters
index 6ff58fe572e6dcc16856dfa5dab13c3af3351280..889b1ee842db18436182b79fff29a0c08c092654 100644
--- a/src/test/obj_ulog_size/obj_ulog_size.vcxproj.filters
+++ b/src/test/obj_ulog_size/obj_ulog_size.vcxproj.filters
@@ -7,7 +7,7 @@
     </Filter>
     <Filter Include="Test Scripts">
       <UniqueIdentifier>{9cef02dc-bf93-4bcc-88fd-82b274dbbf71}</UniqueIdentifier>
-      <Extensions>ps1</Extensions>
+      <Extensions>py</Extensions>
     </Filter>
     <Filter Include="Match Files">
       <UniqueIdentifier>{5ed3a714-4184-4abe-92cb-ce881168ad0c}</UniqueIdentifier>
@@ -15,84 +15,12 @@
     </Filter>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\..\common\ctl.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\alloc_class.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\bucket.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\container_ravl.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\container_seglists.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\ctl_debug.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\critnib.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\heap.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\lane.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\libpmemobj.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\list.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\memblock.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\memops.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\obj.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\palloc.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\pmalloc.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\ravl.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\recycler.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\ulog.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\stats.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\sync.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\libpmemobj\tx.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\common\ctl_prefault.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\common\ctl_sds.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="obj_ulog_size.c">
       <Filter>Source Files</Filter>
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <None Include="TEST0.PS1">
+    <None Include="TESTS.py">
       <Filter>Test Scripts</Filter>
     </None>
     <None Include="out0.log.match">
diff --git a/src/test/obj_ulog_size/out0.log.match b/src/test/obj_ulog_size/out0.log.match
index 4a74041c42d31d3e5567b599b7e93b2da94cc834..af41d5dee0a7ac5027b95df4193e63adcf2eea03 100644
--- a/src/test/obj_ulog_size/out0.log.match
+++ b/src/test/obj_ulog_size/out0.log.match
@@ -1,5 +1,22 @@
 obj_ulog_size$(nW)TEST0: START: obj_ulog_size
- $(nW)obj_ulog_size$(nW) $(nW)testfile
+ $(nW)obj_ulog_size$(nW) $(nW)testfile $(nW)testfile1
+do_tx_max_alloc_no_user_alloc_snap
+Cannot extend undo log - the pool is full: ${Cannot allocate memory|Not enough space}
+do_tx_max_alloc_user_alloc_snap
+Can use the user appended undo log buffer
+do_tx_max_alloc_user_alloc_nested
+Can use the undo log appended by the user in a nested transaction
+do_tx_max_alloc_user_alloc_snap_multi
+Can use multiple user appended undo log buffers
+All user appended undo log buffers are used: ${Cannot allocate memory|Not enough space}
+do_tx_auto_alloc_disabled
+Cannot add to undo log the range bigger than the undo log default size - the auto alloc is disabled: ${Cannot allocate memory|Not enough space}
+do_tx_max_alloc_wrong_pop_addr
+Cannot append an undo log buffer from a different memory pool: Invalid argument
 do_tx_max_alloc_tx_publish_abort
-Cannot publish: ${Cannot allocate memory|Not enough space}
+Cannot extend redo log - the pool is full: ${Cannot allocate memory|Not enough space}
+do_tx_buffer_currently_used
+User cannot append the same undo log buffer twice: Invalid argument
+do_tx_max_alloc_tx_publish
+Can extend redo log with appended buffer
 obj_ulog_size$(nW)TEST0: DONE
diff --git a/src/test/obj_ulog_size/out1.log.match b/src/test/obj_ulog_size/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..19b4d70be71bd79426b9acd638e7df0590477e20
--- /dev/null
+++ b/src/test/obj_ulog_size/out1.log.match
@@ -0,0 +1,22 @@
+obj_ulog_size$(nW)TEST1: START: obj_ulog_size
+ $(nW)obj_ulog_size$(nW) $(nW)testfile $(nW)testfile1
+do_tx_max_alloc_no_user_alloc_snap
+Cannot extend undo log - the pool is full: ${Cannot allocate memory|Not enough space}
+do_tx_max_alloc_user_alloc_snap
+Can use the user appended undo log buffer
+do_tx_max_alloc_user_alloc_nested
+Can use the undo log appended by the user in a nested transaction
+do_tx_max_alloc_user_alloc_snap_multi
+Can use multiple user appended undo log buffers
+All user appended undo log buffers are used: ${Cannot allocate memory|Not enough space}
+do_tx_auto_alloc_disabled
+Cannot add to undo log the range bigger than the undo log default size - the auto alloc is disabled: ${Cannot allocate memory|Not enough space}
+do_tx_max_alloc_wrong_pop_addr
+Cannot append an undo log buffer from a different memory pool: Invalid argument
+do_tx_max_alloc_tx_publish_abort
+Cannot extend redo log - the pool is full: ${Cannot allocate memory|Not enough space}
+do_tx_buffer_currently_used
+User cannot append the same undo log buffer twice: Invalid argument
+do_tx_max_alloc_tx_publish
+Can extend redo log with appended buffer
+obj_ulog_size$(nW)TEST1: DONE
diff --git a/src/test/obj_ulog_size/out2.log.match b/src/test/obj_ulog_size/out2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..7f7e5a4dd61f045e3dcb5345912b64d8446bc835
--- /dev/null
+++ b/src/test/obj_ulog_size/out2.log.match
@@ -0,0 +1,22 @@
+obj_ulog_size$(nW)TEST2: START: obj_ulog_size
+ $(nW)obj_ulog_size$(nW) $(nW)testfile $(nW)testfile1
+do_tx_max_alloc_no_user_alloc_snap
+Cannot extend undo log - the pool is full: ${Cannot allocate memory|Not enough space}
+do_tx_max_alloc_user_alloc_snap
+Can use the user appended undo log buffer
+do_tx_max_alloc_user_alloc_nested
+Can use the undo log appended by the user in a nested transaction
+do_tx_max_alloc_user_alloc_snap_multi
+Can use multiple user appended undo log buffers
+All user appended undo log buffers are used: ${Cannot allocate memory|Not enough space}
+do_tx_auto_alloc_disabled
+Cannot add to undo log the range bigger than the undo log default size - the auto alloc is disabled: ${Cannot allocate memory|Not enough space}
+do_tx_max_alloc_wrong_pop_addr
+Cannot append an undo log buffer from a different memory pool: Invalid argument
+do_tx_max_alloc_tx_publish_abort
+Cannot extend redo log - the pool is full: ${Cannot allocate memory|Not enough space}
+do_tx_buffer_currently_used
+User cannot append the same undo log buffer twice: Invalid argument
+do_tx_max_alloc_tx_publish
+Can extend redo log with appended buffer
+obj_ulog_size$(nW)TEST2: DONE