diff --git a/sonar-project.properties b/sonar-project.properties index 09f19e256..0950549e3 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,5 @@ # must be unique in a given SonarQube instance -sonar.projectKey=utPLSQL:utPLSQL +sonar.projectKey=utPLSQL # this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. sonar.projectName=utPLSQL sonar.projectVersion=v3.0.2 diff --git a/source/core/types/ut_executable.tpb b/source/core/types/ut_executable.tpb index 1b294faef..9709dff5f 100644 --- a/source/core/types/ut_executable.tpb +++ b/source/core/types/ut_executable.tpb @@ -66,15 +66,16 @@ create or replace type body ut_executable is end do_execute; member function do_execute(self in out nocopy ut_executable, a_item in out nocopy ut_suite_item, a_listener in out nocopy ut_event_listener_base) return boolean is - l_statement varchar2(4000); - l_status number; - l_cursor_number number; - l_owner varchar2(200) := self.owner_name; - l_object_name varchar2(200) := self.object_name; - l_procedure_name varchar2(200) := self.procedure_name; + l_statement varchar2(4000); + l_status number; + l_cursor_number number; + l_owner varchar2(200) := self.owner_name; + l_object_name varchar2(200) := self.object_name; + l_procedure_name varchar2(200) := self.procedure_name; l_completed_without_errors boolean := true; - + l_start_transaction_id varchar2(250); + l_end_transaction_id varchar2(250); procedure save_dbms_output is l_status number; l_line varchar2(32767); @@ -94,6 +95,7 @@ create or replace type body ut_executable is end save_dbms_output; begin if self.is_defined() then + l_start_transaction_id := dbms_transaction.local_transaction_id(true); --listener - before call to executable a_listener.fire_before_event(self.associated_event_name, a_item); @@ -135,9 +137,15 @@ create or replace type body ut_executable is l_completed_without_errors := (self.error_stack||self.error_backtrace) is null; - a_listener.fire_after_event(self.associated_event_name, a_item); --listener - after call to executable + a_listener.fire_after_event(self.associated_event_name, a_item); + + l_end_transaction_id := dbms_transaction.local_transaction_id(); + if l_start_transaction_id != l_end_transaction_id or l_end_transaction_id is null then + a_item.add_transaction_invalidator(self.form_name()); + end if; end if; + return l_completed_without_errors; end do_execute; diff --git a/source/core/types/ut_logical_suite.tpb b/source/core/types/ut_logical_suite.tpb index 983a7c5a9..1da3828c7 100644 --- a/source/core/types/ut_logical_suite.tpb +++ b/source/core/types/ut_logical_suite.tpb @@ -115,5 +115,21 @@ create or replace type body ut_logical_suite as return null; end; + overriding member function get_transaction_invalidators return ut_varchar2_list is + l_result ut_varchar2_list; + l_child_results ut_varchar2_list; + begin + l_result := self.transaction_invalidators; + for i in 1 .. self.items.count loop + l_child_results := self.items(i).get_transaction_invalidators(); + for j in 1 .. l_child_results.count loop + if l_child_results(j) not member of l_result then + l_result.extend; l_result(l_result.last) := l_child_results(j); + end if; + end loop; + end loop; + return l_result; + end; + end; / diff --git a/source/core/types/ut_logical_suite.tps b/source/core/types/ut_logical_suite.tps index fd6d6121e..804c54592 100644 --- a/source/core/types/ut_logical_suite.tps +++ b/source/core/types/ut_logical_suite.tps @@ -33,7 +33,8 @@ create or replace type ut_logical_suite under ut_suite_item ( overriding member function do_execute(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base) return boolean, overriding member procedure calc_execution_result(self in out nocopy ut_logical_suite), overriding member procedure mark_as_errored(self in out nocopy ut_logical_suite, a_listener in out nocopy ut_event_listener_base, a_error_stack_trace varchar2), - overriding member function get_error_stack_traces return ut_varchar2_list, - overriding member function get_serveroutputs return clob + overriding member function get_error_stack_traces return ut_varchar2_list, + overriding member function get_serveroutputs return clob, + overriding member function get_transaction_invalidators return ut_varchar2_list ) not final / diff --git a/source/core/types/ut_results_counter.tpb b/source/core/types/ut_results_counter.tpb index e3136102f..61bf320ed 100644 --- a/source/core/types/ut_results_counter.tpb +++ b/source/core/types/ut_results_counter.tpb @@ -25,14 +25,12 @@ create or replace type body ut_results_counter as return; end; - constructor function ut_results_counter(self in out nocopy ut_results_counter, a_status integer) return self as result is + member procedure set_counter_values(self in out nocopy ut_results_counter, a_status integer) is begin self.disabled_count := case when a_status = ut_utils.tr_disabled then 1 else 0 end; self.success_count := case when a_status = ut_utils.tr_success then 1 else 0 end; self.failure_count := case when a_status = ut_utils.tr_failure then 1 else 0 end; self.errored_count := case when a_status = ut_utils.tr_error then 1 else 0 end; - self.warnings_count := 0; - return; end; member procedure sum_counter_values(self in out nocopy ut_results_counter, a_item ut_results_counter) is diff --git a/source/core/types/ut_results_counter.tps b/source/core/types/ut_results_counter.tps index d2be0aa50..15d950f3e 100644 --- a/source/core/types/ut_results_counter.tps +++ b/source/core/types/ut_results_counter.tps @@ -21,7 +21,7 @@ create or replace type ut_results_counter as object( errored_count integer, warnings_count integer, constructor function ut_results_counter(self in out nocopy ut_results_counter) return self as result, - constructor function ut_results_counter(self in out nocopy ut_results_counter, a_status integer) return self as result, + member procedure set_counter_values(self in out nocopy ut_results_counter, a_status integer), member procedure sum_counter_values(self in out nocopy ut_results_counter, a_item ut_results_counter), member procedure increase_warning_count(self in out nocopy ut_results_counter), member function total_count return integer, diff --git a/source/core/types/ut_suite_item.tpb b/source/core/types/ut_suite_item.tpb index 825fc4da5..27aebd3ef 100644 --- a/source/core/types/ut_suite_item.tpb +++ b/source/core/types/ut_suite_item.tpb @@ -16,20 +16,18 @@ create or replace type body ut_suite_item as limitations under the License. */ - member procedure init( - self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, - a_description varchar2, a_path varchar2, a_rollback_type integer, a_disabled_flag boolean - ) is + member procedure init(self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_description varchar2, a_path varchar2, a_rollback_type integer, a_disabled_flag boolean) is begin - self.object_owner := a_object_owner; - self.object_name := lower(trim(a_object_name)); - self.name := lower(trim(a_name)); - self.description := a_description; - self.path := nvl(lower(trim(a_path)), self.object_name); + self.object_owner := a_object_owner; + self.object_name := lower(trim(a_object_name)); + self.name := lower(trim(a_name)); + self.description := a_description; + self.path := nvl(lower(trim(a_path)), self.object_name); self.rollback_type := a_rollback_type; self.disabled_flag := ut_utils.boolean_to_int(a_disabled_flag); self.results_count := ut_results_counter(); - self.warnings := ut_varchar2_list(); + self.warnings := ut_varchar2_list(); + self.transaction_invalidators := ut_varchar2_list(); end; member procedure set_disabled_flag(self in out nocopy ut_suite_item, a_disabled_flag boolean) is @@ -67,7 +65,13 @@ create or replace type body ut_suite_item as end if; exception when ex_savepoint_not_exists then - put_warning('Savepoint not established. Implicit commit might have occured.'); + put_warning( + 'Unable to perform automatic rollback after test' + || case when self_type like '%SUITE' then ' suite' end || '. ' + ||'An implicit or explicit commit/rollback occurred in procedures:'||chr(10) + ||lower(ut_utils.indent_lines(ut_utils.table_to_clob(self.get_transaction_invalidators()), 2, true))||chr(10) + ||'Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue.' + ); end; member function execution_time return number is @@ -82,5 +86,18 @@ create or replace type body ut_suite_item as self.results_count.increase_warning_count; end; + member function get_transaction_invalidators return ut_varchar2_list is + begin + return transaction_invalidators; + end; + + member procedure add_transaction_invalidator(a_object_name varchar2) is + begin + if a_object_name not member of transaction_invalidators then + transaction_invalidators.extend(); + transaction_invalidators(transaction_invalidators.last) := a_object_name; + end if; + end; + end; / diff --git a/source/core/types/ut_suite_item.tps b/source/core/types/ut_suite_item.tps index e57cf9cb3..7a7a43d8c 100644 --- a/source/core/types/ut_suite_item.tps +++ b/source/core/types/ut_suite_item.tps @@ -17,6 +17,7 @@ create or replace type ut_suite_item force under ut_suite_item_base ( */ results_count ut_results_counter, + transaction_invalidators ut_varchar2_list, member procedure init( self in out nocopy ut_suite_item, a_object_owner varchar2, a_object_name varchar2, a_name varchar2, a_description varchar2, a_path varchar2, a_rollback_type integer, a_disabled_flag boolean), @@ -24,6 +25,8 @@ create or replace type ut_suite_item force under ut_suite_item_base ( member function get_disabled_flag return boolean, member function create_savepoint_if_needed return varchar2, member procedure rollback_to_savepoint(self in out nocopy ut_suite_item, a_savepoint varchar2), + member function get_transaction_invalidators return ut_varchar2_list, + member procedure add_transaction_invalidator(a_object_name varchar2), /* Returns execution time in seconds (with miliseconds) */ diff --git a/source/core/types/ut_test.tpb b/source/core/types/ut_test.tpb index 5d576f44c..50a6f4882 100644 --- a/source/core/types/ut_test.tpb +++ b/source/core/types/ut_test.tpb @@ -58,7 +58,7 @@ create or replace type body ut_test as if self.get_disabled_flag() then self.result := ut_utils.tr_disabled; ut_utils.debug_log('ut_test.execute - disabled'); - self.results_count := ut_results_counter(self.result); + self.results_count.set_counter_values(self.result); self.end_time := self.start_time; else if self.is_valid() then @@ -100,7 +100,7 @@ create or replace type body ut_test as end if; --expectation results need to be part of test results self.results := ut_expectation_processor.get_expectations_results(); - self.results_count := ut_results_counter(self.result); + self.results_count.set_counter_values(self.result); end; overriding member procedure mark_as_errored(self in out nocopy ut_test, a_listener in out nocopy ut_event_listener_base, a_error_stack_trace varchar2) is diff --git a/source/core/ut_annotations.pkb b/source/core/ut_annotations.pkb index ccf8bda66..7a04e8b6b 100644 --- a/source/core/ut_annotations.pkb +++ b/source/core/ut_annotations.pkb @@ -78,7 +78,7 @@ create or replace package body ut_annotations as ,'%(' || c_rgexp_identifier || ')' ,modifier => 'i' ,subexpression => 1)); - l_annotation_params_str := trim(regexp_substr(l_annotation_str, '\((.*?)\)$', subexpression => 1)); + l_annotation_params_str := trim(regexp_substr(l_annotation_str, '\((.*?)\)\s*$', subexpression => 1)); if l_annotation_params_str is not null then diff --git a/source/reporters/ut_documentation_reporter.tpb b/source/reporters/ut_documentation_reporter.tpb index a099d4d9b..08f6aeeaa 100644 --- a/source/reporters/ut_documentation_reporter.tpb +++ b/source/reporters/ut_documentation_reporter.tpb @@ -88,7 +88,7 @@ create or replace type body ut_documentation_reporter is l_warning_index pls_integer := 0; -- make all warning indexes uniformly indented c_warnings_lpad constant integer := length(to_char(a_run.results_count.warnings_count)); - + procedure print_failure_for_expectation(a_expectation ut_expectation_result) is l_lines ut_varchar2_list; begin @@ -144,14 +144,17 @@ create or replace type body ut_documentation_reporter is end if; end; - procedure print_item_warnings(a_item in ut_logical_suite) is - l_suite ut_logical_suite; + procedure print_item_warnings(a_item in ut_suite_item) is + l_items ut_suite_items; begin - for i in 1 .. a_item.items.count loop - if a_item.items(i) is of(ut_logical_suite) then - print_item_warnings(treat(a_item.items(i) as ut_logical_suite)); - end if; - end loop; + if a_item is of (ut_logical_suite) then + l_items := treat(a_item as ut_logical_suite).items; + for i in 1 .. l_items.count loop + if l_items(i) is of(ut_suite_item) then + print_item_warnings(l_items(i)); + end if; + end loop; + end if; if a_item.warnings is not null and a_item.warnings.count > 0 then for i in 1 .. a_item.warnings.count loop @@ -166,14 +169,13 @@ create or replace type body ut_documentation_reporter is end; procedure print_warnings(a_run in ut_run) is - l_suite ut_logical_suite; begin if a_run.results_count.warnings_count > 0 then self.print_text(' '); self.print_text('Warnings:'); self.print_text(' '); for i in 1 .. a_run.items.count loop - print_item_warnings(treat(a_run.items(i) as ut_logical_suite)); + print_item_warnings(treat(a_run.items(i) as ut_suite_item)); end loop; end if; end; @@ -182,7 +184,7 @@ create or replace type body ut_documentation_reporter is print_failures_details(a_run); print_warnings(a_run); self.print_text('Finished in ' || a_run.execution_time || ' seconds'); - + l_summary_text := a_run.results_count.total_count || ' tests, ' || a_run.results_count.failure_count || ' failed, ' || a_run.results_count.errored_count || ' errored, ' diff --git a/tests/ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql b/tests/ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql index 00a9794d2..1a2073b8d 100644 --- a/tests/ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql +++ b/tests/ut_reporters/ut_documentation_reporter.reportMultipleWarnings.sql @@ -1,26 +1,30 @@ set termout off -create or replace package tst_documrep_mult_warn as +create or replace package ut_output_test_rollback as --%suite + --%beforeall + procedure ba; + --%beforeeach + procedure be; --%test - procedure test1; -end; -/ - -create or replace package body tst_documrep_mult_warn as - procedure test1 is begin commit; end; -end; -/ -create or replace package tst_documrep_mult_warn2 as - --%suite - + procedure test; --%test - procedure test1; + --%rollback(manual) + procedure t_manual; + --%afterall + procedure aa; + --%aftereach + procedure ae; end; / -create or replace package body tst_documrep_mult_warn2 as - procedure test1 is begin commit; end; +create or replace package body ut_output_test_rollback as + procedure ba is begin commit; end; + procedure be is begin commit; end; + procedure test is begin null; end; + procedure t_manual is begin commit; end; + procedure aa is begin commit; end; + procedure ae is begin commit; end; end; / @@ -32,14 +36,29 @@ declare l_output varchar2(32767); l_expected varchar2(32767); begin - l_expected := q'[%Warnings: -%1)%tst_documrep_mult_warn% -%2)%tst_documrep_mult_warn%]'; + l_expected := q'[% + 1) ut_output_test_rollback.test + Unable to perform automatic rollback after test. An implicit or explicit commit/rollback occurred in procedures: + ut3.ut_output_test_rollback.be + ut3.ut_output_test_rollback.ae + Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. +% + 2) ut_output_test_rollback + Unable to perform automatic rollback after test suite. An implicit or explicit commit/rollback occurred in procedures: + ut3.ut_output_test_rollback.ba + ut3.ut_output_test_rollback.aa + ut3.ut_output_test_rollback.be + ut3.ut_output_test_rollback.ae + ut3.ut_output_test_rollback.t_manual + Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. +% +Finished in % seconds +2 tests, 0 failed, 0 errored, 0 disabled, 2 warning(s)%]'; --act select * bulk collect into l_output_data - from table(ut.run(ut_varchar2_list('tst_documrep_mult_warn','tst_documrep_mult_warn2'),ut_documentation_reporter())); + from table(ut.run(ut_varchar2_list('ut_output_test_rollback'),ut_documentation_reporter())); l_output := ut_utils.table_to_clob(l_output_data); @@ -48,9 +67,9 @@ begin :test_result := ut_utils.tr_success; else dbms_output.put_line('Actual:"'||l_output||'"'); + dbms_output.put_line('Expected:"'||l_expected||'"'); end if; end; / -drop package tst_documrep_mult_warn; -drop package tst_documrep_mult_warn2; +drop package ut_output_test_rollback; diff --git a/tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql b/tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql index e090e92ba..7c7878981 100644 --- a/tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql +++ b/tests/ut_test/ut_test.ReportWarningOnRollbackFailed.sql @@ -1,10 +1,10 @@ create or replace package ut_output_test_rollback as --%suite - + --%test procedure tt; - + end; / @@ -20,27 +20,33 @@ end; / declare - l_output_data dbms_output.chararr; - l_num_lines integer := 100000; - l_output clob; + l_lines ut_varchar2_list; + l_results clob; begin --act - ut.run('ut_output_test_rollback'); + select * bulk collect into l_lines from table(ut.run('ut_output_test_rollback')); + + l_results := ut_utils.table_to_clob(l_lines); --assert - dbms_output.get_lines( l_output_data, l_num_lines); - dbms_lob.createtemporary(l_output,true); - for i in 1 .. l_num_lines loop - dbms_lob.append(l_output,l_output_data(i)); - end loop; - - if l_output like '%Warnings:%Savepoint not established. Implicit commit might have occured.%0 disabled, 1 warning(s)%' then + if l_results like q'[%Warnings: +% + 1) ut_output_test_rollback.tt + Unable to perform automatic rollback after test. An implicit or explicit commit/rollback occurred in procedures: + ut3.ut_output_test_rollback.tt + Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. +% + 2) ut_output_test_rollback + Unable to perform automatic rollback after test suite. An implicit or explicit commit/rollback occurred in procedures: + ut3.ut_output_test_rollback.tt + Use the "--%rollback(manual)" annotation or remove commit/rollback/ddl statements that are causing the issue. +% +Finished in % seconds +1 tests, 0 failed, 0 errored, 0 disabled, 2 warning(s)%]' then :test_result := ut_utils.tr_success; - end if; - - if :test_result != ut_utils.tr_success or :test_result is null then - for i in 1 .. l_num_lines loop - dbms_output.put_line(l_output_data(i)); + else + for i in 1 .. l_lines.count loop + dbms_output.put_line(l_lines(i)); end loop; dbms_output.put_line('Failed: Wrong output'); end if;