diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index d71a6995b7e6d42e1d4b75bbc44d9895385a2431..e6dde59ba01d3ceb7bbb03678643e7a33a194df6 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -12,11 +12,16 @@
 #include "sieve-generator.h"
 
 /* Jump list */
-void sieve_jumplist_init
-	(struct sieve_jumplist *jlist, pool_t pool, struct sieve_binary *sbin)
+struct sieve_jumplist *sieve_jumplist_create
+	(pool_t pool, struct sieve_binary *sbin)
 {
+	struct sieve_jumplist *jlist;
+	
+	jlist = p_new(pool, struct sieve_jumplist, 1);
 	jlist->binary = sbin;
 	p_array_init(&jlist->jumps, pool, 4);
+	
+	return jlist;
 }
 
 void sieve_jumplist_init_temp
@@ -26,6 +31,12 @@ void sieve_jumplist_init_temp
 	t_array_init(&jlist->jumps, 4);
 }
 
+void sieve_jumplist_reset
+	(struct sieve_jumplist *jlist)
+{
+	array_clear(&jlist->jumps);
+}
+
 void sieve_jumplist_add(struct sieve_jumplist *jlist, sieve_size_t jump) 
 {
 	array_append(&jlist->jumps, &jump, 1);
diff --git a/src/lib-sieve/sieve-generator.h b/src/lib-sieve/sieve-generator.h
index aa1b46003c6963b4bdd6e4c2d9fe1103b6c47e20..367672d6edfe3368c0769c6e168df01cf7b0b15a 100644
--- a/src/lib-sieve/sieve-generator.h
+++ b/src/lib-sieve/sieve-generator.h
@@ -41,10 +41,12 @@ struct sieve_jumplist {
 	ARRAY_DEFINE(jumps, sieve_size_t);
 };
 
+struct sieve_jumplist *sieve_jumplist_create
+	(pool_t pool, struct sieve_binary *sbin);
 void sieve_jumplist_init_temp
 	(struct sieve_jumplist *jlist, struct sieve_binary *sbin);
-void sieve_jumplist_init
-	(struct sieve_jumplist *jlist, pool_t pool, struct sieve_binary *sbin);
+void sieve_jumplist_reset
+	(struct sieve_jumplist *jlist);
 void sieve_jumplist_add
 	(struct sieve_jumplist *jlist, sieve_size_t jump);
 void sieve_jumplist_resolve(struct sieve_jumplist *jlist);
diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am
index 7d4382dd6e154e033e2e6eadcbe0c111c7ab9fc9..1afea99323086a6b39426f129ffb318c64bd57e3 100644
--- a/src/testsuite/Makefile.am
+++ b/src/testsuite/Makefile.am
@@ -39,6 +39,7 @@ testsuite_DEPENDENCIES = $(libs)
 
 cmds = \
 	cmd-test.c \
+	cmd-test-fail.c \
 	cmd-test-set.c
 
 testsuite_SOURCES = \
diff --git a/src/testsuite/cmd-test-fail.c b/src/testsuite/cmd-test-fail.c
new file mode 100644
index 0000000000000000000000000000000000000000..13a775356be95ef373fb6cc08db5c84840cc9a7b
--- /dev/null
+++ b/src/testsuite/cmd-test-fail.c
@@ -0,0 +1,147 @@
+#include "sieve-commands.h"
+#include "sieve-commands-private.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+
+/* Predeclarations */
+
+static bool cmd_test_fail_operation_dump
+	(const struct sieve_operation *op,
+		const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static bool cmd_test_fail_operation_execute
+	(const struct sieve_operation *op, 
+		const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+static bool cmd_test_fail_validate
+	(struct sieve_validator *validator, struct sieve_command_context *cmd);
+static bool cmd_test_fail_generate
+	(struct sieve_generator *generator, struct sieve_command_context *ctx);
+
+/* Test_fail command
+ *
+ * Syntax:   
+ *   test <reason: string>
+ */
+const struct sieve_command cmd_test_fail = { 
+	"test_fail", 
+	SCT_COMMAND, 
+	1, 0, FALSE, FALSE,
+	NULL, NULL,
+	cmd_test_fail_validate, 
+	cmd_test_fail_generate, 
+	NULL 
+};
+
+/* Test operation */
+
+const struct sieve_operation test_fail_operation = { 
+	"TEST_FAIL",
+	&testsuite_extension, 
+	TESTSUITE_OPERATION_TEST_FAIL,
+	cmd_test_fail_operation_dump, 
+	cmd_test_fail_operation_execute 
+};
+
+/* Validation */
+
+static bool cmd_test_fail_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command_context *cmd) 
+{
+	struct sieve_ast_argument *arg = cmd->first_positional;
+	
+	if ( !sieve_validate_positional_argument
+		(valdtr, cmd, arg, "reason", 1, SAAT_STRING) ) {
+		return FALSE;
+	}
+	
+	return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/* Code generation */
+
+static inline struct testsuite_generator_context *
+	_get_generator_context(struct sieve_generator *gentr)
+{
+	return (struct testsuite_generator_context *) 
+		sieve_generator_extension_get_context(gentr, ext_testsuite_my_id);
+}
+
+static bool cmd_test_fail_generate
+	(struct sieve_generator *gentr, struct sieve_command_context *ctx)
+{
+	struct sieve_binary *sbin = sieve_generator_get_binary(gentr);
+	struct testsuite_generator_context *genctx = 
+		_get_generator_context(gentr);
+	
+	sieve_generator_emit_operation_ext(gentr, &test_fail_operation, 
+		ext_testsuite_my_id);
+
+	/* Generate arguments */
+	if ( !sieve_generate_arguments(gentr, ctx, NULL) )
+		return FALSE;
+		
+	sieve_jumplist_add(genctx->exit_jumps, sieve_binary_emit_offset(sbin, 0));			
+	
+	return TRUE;
+}
+
+/* 
+ * Code dump
+ */
+ 
+static bool cmd_test_fail_operation_dump
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+	unsigned int pc;
+  int offset;
+    
+	sieve_code_dumpf(denv, "TEST_FAIL:");
+	sieve_code_descend(denv);
+
+	if ( !sieve_opr_string_dump(denv, address) ) 
+		return FALSE;
+
+	sieve_code_mark(denv);
+	pc = *address;
+	if ( sieve_binary_read_offset(denv->sbin, address, &offset) )
+		sieve_code_dumpf(denv, "OFFSET: %d [%08x]", offset, pc + offset);
+	else
+		return FALSE;
+
+	return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static bool cmd_test_fail_operation_execute
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+	string_t *reason;
+
+	t_push();
+
+	if ( !sieve_opr_string_read(renv, address, &reason) ) {
+		t_pop();
+		return FALSE;
+	}
+
+	printf("TEST FAILED: %s\n", str_c(reason));
+	
+	t_pop();
+	
+	return sieve_interpreter_program_jump(renv->interp, TRUE);
+}
+
+
+
+
diff --git a/src/testsuite/cmd-test.c b/src/testsuite/cmd-test.c
index c1f796d53834f19be73ea2a81a546182fce338dc..5772abb83f032c3c145965977e01586711ea536e 100644
--- a/src/testsuite/cmd-test.c
+++ b/src/testsuite/cmd-test.c
@@ -72,27 +72,35 @@ static bool cmd_test_validate
 
 /* Code generation */
 
+static inline struct testsuite_generator_context *
+	_get_generator_context(struct sieve_generator *gentr)
+{
+	return (struct testsuite_generator_context *) 
+		sieve_generator_extension_get_context(gentr, ext_testsuite_my_id);
+}
+
 static bool cmd_test_generate
-	(struct sieve_generator *generator, struct sieve_command_context *ctx)
+	(struct sieve_generator *gentr, struct sieve_command_context *ctx)
 {
-	struct sieve_binary *sbin = sieve_generator_get_binary(generator);
-	struct sieve_jumplist jmplist;
+	struct sieve_binary *sbin = sieve_generator_get_binary(gentr);
+	struct testsuite_generator_context *genctx = 
+		_get_generator_context(gentr);
 	
-	sieve_generator_emit_operation_ext(generator, &test_operation, 
+	sieve_generator_emit_operation_ext(gentr, &test_operation, 
 		ext_testsuite_my_id);
 
 	/* Generate arguments */
-	if ( !sieve_generate_arguments(generator, ctx, NULL) )
+	if ( !sieve_generate_arguments(gentr, ctx, NULL) )
 		return FALSE;
 		
 	/* Prepare jumplist */
-	sieve_jumplist_init_temp(&jmplist, sbin);
+	sieve_jumplist_reset(genctx->exit_jumps);
 		
 	/* Test body */
-	sieve_generate_block(generator, ctx->ast_node);
+	sieve_generate_block(gentr, ctx->ast_node);
 	
 	/* Resolve exit jumps to this point */
-	sieve_jumplist_resolve(&jmplist); 
+	sieve_jumplist_resolve(genctx->exit_jumps); 
 			
 	return TRUE;
 }
diff --git a/src/testsuite/ext-testsuite.c b/src/testsuite/ext-testsuite.c
index c787d280eba1b6aeb0d7def0ec24032fa4ca6675..514755cf8f7a9f116d4b8e24f6f1a1fae143e336 100644
--- a/src/testsuite/ext-testsuite.c
+++ b/src/testsuite/ext-testsuite.c
@@ -29,26 +29,25 @@
 /* Forward declarations */
 
 static bool ext_testsuite_load(int ext_id);
-static bool ext_testsuite_validator_load(struct sieve_validator *validator);
+static bool ext_testsuite_validator_load(struct sieve_validator *valdtr);
+static bool ext_testsuite_generator_load(struct sieve_generator *gentr);
 static bool ext_testsuite_binary_load(struct sieve_binary *sbin);
 
 /* Commands */
 
 extern const struct sieve_command cmd_test;
+extern const struct sieve_command cmd_test_fail;
 extern const struct sieve_command cmd_test_set;
 
+/* Operations */
+
+const struct sieve_operation *testsuite_operations[] =
+    { &test_operation, &test_fail_operation, &test_set_operation };
+
 /* Operands */
 
 const struct sieve_operand *testsuite_operands[] =
     { &testsuite_object_operand };
-
-/* Operations */
-
-extern const struct sieve_operation test_operation;
-extern const struct sieve_operation test_set_operation;
-
-const struct sieve_operation *testsuite_operations[] =
-    { &test_operation, &test_set_operation };
     
 /* Extension definitions */
 
@@ -57,8 +56,9 @@ int ext_testsuite_my_id;
 const struct sieve_extension testsuite_extension = { 
 	"vnd.dovecot.testsuite", 
 	ext_testsuite_load,
-	ext_testsuite_validator_load, 
-	NULL, NULL,
+	ext_testsuite_validator_load,
+	ext_testsuite_generator_load,
+	NULL,
 	ext_testsuite_binary_load, 
 	NULL, 
 	SIEVE_EXT_DEFINE_OPERATIONS(testsuite_operations),
@@ -74,12 +74,20 @@ static bool ext_testsuite_load(int ext_id)
 
 /* Load extension into validator */
 
-static bool ext_testsuite_validator_load(struct sieve_validator *validator)
+static bool ext_testsuite_validator_load(struct sieve_validator *valdtr)
 {
-	sieve_validator_register_command(validator, &cmd_test);
-	sieve_validator_register_command(validator, &cmd_test_set);
+	sieve_validator_register_command(valdtr, &cmd_test);
+	sieve_validator_register_command(valdtr, &cmd_test_fail);
+	sieve_validator_register_command(valdtr, &cmd_test_set);
 	
-	return testsuite_validator_context_initialize(validator);
+	return testsuite_validator_context_initialize(valdtr);
+}
+
+/* Load extension into generator */
+
+static bool ext_testsuite_generator_load(struct sieve_generator *gentr)
+{
+	return testsuite_generator_context_initialize(gentr);
 }
 
 /* Load extension into binary */
diff --git a/src/testsuite/tests/testsuite.sieve b/src/testsuite/tests/testsuite.sieve
index 4c076ba264673db436329a7302265ec9c3a83388..05a4e13ad4d0b31aca3e25835a3ed254770e1d48 100644
--- a/src/testsuite/tests/testsuite.sieve
+++ b/src/testsuite/tests/testsuite.sieve
@@ -12,8 +12,7 @@ Frop!
 	test_set "envelope.from" "stephan@rename-it.nl";
 
 	if not header :contains "from" "rename-it.nl" {
-		discard;
-		stop;
+		test_fail "Message data not set properly.";
 	}
 
 	test_set "message" text:
@@ -27,8 +26,7 @@ Friep!
 	test_set "envelope.from" "stephan@rename-it.nl";
 
 	if not header :is "from" "nico@vestingbar.nl" {
-    	discard;
-    	stop;
+    	test_fail "Message data not set properly.";
 	} 
 
 	keep;
diff --git a/src/testsuite/testsuite-common.c b/src/testsuite/testsuite-common.c
index b03846b65036894d8a269a25138e533d70b23926..ae5ced7ec2312d079a658de117d91ea703c65000 100644
--- a/src/testsuite/testsuite-common.c
+++ b/src/testsuite/testsuite-common.c
@@ -127,7 +127,7 @@ bool testsuite_validator_context_initialize(struct sieve_validator *valdtr)
 	struct testsuite_validator_context *ctx = 
 		p_new(pool, struct testsuite_validator_context, 1);
 	
-	/* Setup comparator registry */
+	/* Setup object registry */
 	ctx->object_registrations = hash_create
 		(pool, pool, 0, str_hash, (hash_cmp_callback_t *) strcmp);
 
@@ -137,3 +137,22 @@ bool testsuite_validator_context_initialize(struct sieve_validator *valdtr)
 
 	return TRUE;
 }
+
+/* 
+ * Generator context 
+ */
+
+bool testsuite_generator_context_initialize(struct sieve_generator *gentr)
+{
+	pool_t pool = sieve_validator_pool(gentr);
+	struct sieve_binary *sbin = sieve_generator_get_binary(gentr);
+	struct testsuite_generator_context *ctx = 
+		p_new(pool, struct testsuite_generator_context, 1);
+	
+	/* Setup exit jumplist */
+	ctx->exit_jumps = sieve_jumplist_create(pool, sbin);
+	
+	sieve_generator_extension_set_context(gentr, ext_testsuite_my_id, ctx);
+
+	return TRUE;
+}
diff --git a/src/testsuite/testsuite-common.h b/src/testsuite/testsuite-common.h
index c866dd849af0ffc03d002d5085987c0984b0af94..b5bb806e38767a55a1ba3592098932b70edbc008 100644
--- a/src/testsuite/testsuite-common.h
+++ b/src/testsuite/testsuite-common.h
@@ -26,13 +26,26 @@ struct testsuite_validator_context {
 
 bool testsuite_validator_context_initialize(struct sieve_validator *valdtr);
 
+/* Testsuite generator context */
+
+struct testsuite_generator_context {
+	struct sieve_jumplist *exit_jumps;
+};
+
+bool testsuite_generator_context_initialize(struct sieve_generator *gentr);
+
 /* Testsuite operations */
 
 enum testsuite_operation_code {
 	TESTSUITE_OPERATION_TEST,
+	TESTSUITE_OPERATION_TEST_FAIL,
 	TESTSUITE_OPERATION_TEST_SET
 };
 
+extern const struct sieve_operation test_operation;
+extern const struct sieve_operation test_fail_operation;
+extern const struct sieve_operation test_set_operation;
+
 /* Testsuite operands */
 
 extern const struct sieve_operand testsuite_object_operand;