Skip to content

Commit 5cf7f34

Browse files
authored
Merge pull request #1243 from utPLSQL/feature/output_buffer_sync
Allow for test runs over 4 hours
2 parents f72db1e + 865785a commit 5cf7f34

16 files changed

+314
-244
lines changed

development/refresh_sources.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ git clone --depth=1 --branch=${SELFTESTING_BRANCH:-main} https://github.com/utPL
1212

1313
rm -rf utPLSQL-cli/*
1414
# download latest release version of utPLSQL-cli
15-
curl -Lk -o utPLSQL-cli.zip https://github.com/utPLSQL/utPLSQL-cli/releases/download/v${UTPLSQL_CLI_VERSION}/utPLSQL-cli.zip
15+
curl -Lk -o utPLSQL-cli.zip https://github.com/utPLSQL/utPLSQL-cli/releases/download/${UTPLSQL_CLI_VERSION}/utPLSQL-cli.zip
1616
# unzip utPLSQL-cli and remove the zip file
1717
unzip utPLSQL-cli.zip && chmod u+x utPLSQL-cli/bin/utplsql && rm utPLSQL-cli.zip
1818

docs/userguide/install.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ The headless scripts accept three optional parameters that define:
121121
The scripts need to be executed by `SYSDBA`, in order to grant access to `DBMS_LOCK` and `DBMS_CRYPTO` system packages.
122122

123123
!!! warning "Important"
124-
- Grant on `DBMS_LOCK` is required only for installation on Oracle versions below 18c. For versions 18c and above, utPLSQL uses `DBMS_SESSION.SLEEP` so access to `DBMS_LOCK` package is no longer needed.<br>
124+
- `DBMS_LOCK` is required for session synchronization between main session and session consuming realtime reports.<br>
125125
- The user performing the installation must have the `ADMINISTER DATABASE TRIGGER` privilege. This is required for installation of trigger that is responsible for parsing annotations at at compile-time of a package.<br>
126126
- When installed with DDL trigger, utPLSQL will not be registering unit tests for any of oracle-maintained schemas.<br>
127127
- For Oracle 11g following users are excluded:<br>

examples/developer_examples/RunExampleTestSuiteWithCompositeReporter.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ begin
2020
ut_event_manager.initialize();
2121
ut_event_manager.add_listener(l_doc_reporter);
2222
ut_event_manager.add_listener(l_tc_reporter);
23+
ut_event_manager.trigger_event(ut_event_manager.gc_initialize, l_run);
2324

2425
l_suite := ut_suite(user, 'ut_exampletest',a_line_no=>1);
2526
l_suite.description := 'Test Suite Name';

source/core/coverage/ut_coverage_reporter_base.tpb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ create or replace type body ut_coverage_reporter_base is
9292
ut_coverage_helper.cleanup_tmp_table();
9393
(l_reporter as ut_output_reporter_base).before_calling_run(null);
9494
l_reporter.after_calling_run( ut_run( a_coverage_options => a_coverage_options, a_client_character_set => a_client_character_set ) );
95-
l_reporter.on_finalize(null);
9695
for i in (select /*+ no_parallel */ x.text from table(l_reporter.get_lines(1, 1)) x ) loop
9796
pipe row (i.text);
9897
end loop;
@@ -106,7 +105,6 @@ create or replace type body ut_coverage_reporter_base is
106105
ut_coverage_helper.cleanup_tmp_table();
107106
(l_reporter as ut_output_reporter_base).before_calling_run(null);
108107
l_reporter.after_calling_run( ut_run( a_coverage_options => a_coverage_options, a_client_character_set => a_client_character_set ) );
109-
l_reporter.on_finalize(null);
110108
open l_result for select /*+ no_parallel */ x.text from table(l_reporter.get_lines(1, 1)) x;
111109
return l_result;
112110
end;

source/core/output_buffers/ut_output_buffer_base.tpb

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,94 @@ create or replace type body ut_output_buffer_base is
2424
self.self_type := coalesce(a_self_type,self.self_type);
2525
self.output_id := coalesce(a_output_id, self.output_id, sys_guid());
2626
self.start_date := coalesce(self.start_date, sysdate);
27-
self.last_message_id := 0;
27+
self.last_write_message_id := 0;
2828
select /*+ no_parallel */ count(*) into l_exists from ut_output_buffer_info_tmp where output_id = self.output_id;
2929
if ( l_exists > 0 ) then
3030
update /*+ no_parallel */ ut_output_buffer_info_tmp set start_date = self.start_date where output_id = self.output_id;
3131
else
3232
insert /*+ no_parallel */ into ut_output_buffer_info_tmp(output_id, start_date) values (self.output_id, self.start_date);
3333
end if;
3434
commit;
35+
dbms_lock.allocate_unique( self.output_id, self.lock_handle);
3536
self.is_closed := 0;
3637
end;
3738

38-
member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor is
39+
member procedure lock_buffer(a_timeout_sec number := null) is
40+
l_status integer;
41+
begin
42+
l_status := dbms_lock.request( self.lock_handle, dbms_lock.x_mode, 5, false );
43+
if l_status != 0 then
44+
raise_application_error(-20000, 'Cannot allocate lock for output buffer of reporter. lock request status = '||l_status||', lock handle = '||self.lock_handle||', self.output_id ='||self.output_id);
45+
end if;
46+
end;
47+
48+
member procedure close(self in out nocopy ut_output_buffer_base) is
49+
l_status integer;
50+
begin
51+
l_status := dbms_lock.release( self.lock_handle );
52+
if l_status != 0 then
53+
raise_application_error(-20000, 'Cannot release lock for output buffer of reporter. Lock_handle = '||self.lock_handle||' status = '||l_status);
54+
end if;
55+
self.is_closed := 1;
56+
end;
57+
58+
59+
member procedure remove_buffer_info(self in ut_output_buffer_base) is
60+
pragma autonomous_transaction;
61+
begin
62+
delete from ut_output_buffer_info_tmp a
63+
where a.output_id = self.output_id;
64+
commit;
65+
end;
66+
67+
member function timeout_producer_not_started( a_producer_started boolean, a_already_waited_sec number, a_init_wait_sec number ) return boolean
68+
is
69+
l_result boolean := false;
70+
begin
71+
if not a_producer_started and a_already_waited_sec >= a_init_wait_sec then
72+
if a_init_wait_sec > 0 then
73+
self.remove_buffer_info();
74+
raise_application_error(
75+
ut_utils.gc_out_buffer_timeout,
76+
'Timeout occurred while waiting for report data producer to start. Waited for: '||ut_utils.to_string( a_already_waited_sec )||' seconds.'
77+
);
78+
else
79+
l_result := true;
80+
end if;
81+
end if;
82+
return l_result;
83+
end;
84+
85+
member function timeout_producer_not_finished(a_producer_finished boolean, a_already_waited_sec number, a_timeout_sec number) return boolean
86+
is
87+
l_result boolean := false;
88+
begin
89+
if not a_producer_finished and a_timeout_sec is not null and a_already_waited_sec >= a_timeout_sec then
90+
if a_timeout_sec > 0 then
91+
self.remove_buffer_info();
92+
raise_application_error(
93+
ut_utils.gc_out_buffer_timeout,
94+
'Timeout occurred while waiting for more data from producer. Waited for: '||ut_utils.to_string( a_already_waited_sec )||' seconds.'
95+
);
96+
else
97+
l_result := true;
98+
end if;
99+
end if;
100+
return l_result;
101+
end;
102+
103+
member function get_lock_status return integer is
104+
l_result integer;
105+
l_release_status integer;
106+
begin
107+
l_result := dbms_lock.request( self.lock_handle, dbms_lock.s_mode, 0, false );
108+
if l_result = 0 then
109+
l_release_status := dbms_lock.release( self.lock_handle );
110+
end if;
111+
return l_result;
112+
end;
113+
114+
member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor is
39115
l_lines sys_refcursor;
40116
begin
41117
open l_lines for
@@ -44,7 +120,7 @@ create or replace type body ut_output_buffer_base is
44120
return l_lines;
45121
end;
46122

47-
member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout natural := null, a_timeout_sec natural := null) is
123+
member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout number := null, a_timeout_sec number := null) is
48124
l_data sys_refcursor;
49125
l_clob clob;
50126
l_item_type varchar2(32767);
@@ -54,16 +130,20 @@ create or replace type body ut_output_buffer_base is
54130
loop
55131
fetch l_data into l_clob, l_item_type;
56132
exit when l_data%notfound;
57-
l_lines := ut_utils.clob_to_table(l_clob);
58-
for i in 1 .. l_lines.count loop
59-
dbms_output.put_line(l_lines(i));
60-
end loop;
133+
if dbms_lob.getlength(l_clob) > 32767 then
134+
l_lines := ut_utils.clob_to_table(l_clob);
135+
for i in 1 .. l_lines.count loop
136+
dbms_output.put_line(l_lines(i));
137+
end loop;
138+
else
139+
dbms_output.put_line(l_clob);
140+
end if;
61141
end loop;
62142
close l_data;
63143
end;
64144

65145
member procedure cleanup_buffer(self in ut_output_buffer_base, a_retention_time_sec natural := null) is
66-
gc_buffer_retention_sec constant naturaln := coalesce(a_retention_time_sec, 60 * 60 * 24); -- 24 hours
146+
gc_buffer_retention_sec constant naturaln := coalesce(a_retention_time_sec, 60 * 60 * 24 * 5); -- 5 days
67147
l_retention_days number := gc_buffer_retention_sec / (60 * 60 * 24);
68148
l_max_retention_date date := sysdate - l_retention_days;
69149
pragma autonomous_transaction;

source/core/output_buffers/ut_output_buffer_base.tps

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,22 @@ create or replace type ut_output_buffer_base force authid definer as object(
1919
output_id raw(32),
2020
is_closed number(1,0),
2121
start_date date,
22-
last_message_id number(38,0),
22+
last_write_message_id number(38,0),
23+
lock_handle varchar2(30 byte),
2324
self_type varchar2(250 byte),
2425
member procedure init(self in out nocopy ut_output_buffer_base, a_output_id raw := null, a_self_type varchar2 := null),
25-
member function get_lines_cursor(a_initial_timeout natural := null, a_timeout_sec natural := null) return sys_refcursor,
26-
member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout natural := null, a_timeout_sec natural := null),
26+
member procedure lock_buffer(a_timeout_sec number := null),
27+
member function timeout_producer_not_started( a_producer_started boolean, a_already_waited_sec number, a_init_wait_sec number ) return boolean,
28+
member function timeout_producer_not_finished(a_producer_finished boolean, a_already_waited_sec number, a_timeout_sec number) return boolean,
29+
member function get_lock_status return integer,
30+
member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor,
31+
member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout number := null, a_timeout_sec number := null),
2732
member procedure cleanup_buffer(self in ut_output_buffer_base, a_retention_time_sec natural := null),
28-
not instantiable member procedure close(self in out nocopy ut_output_buffer_base),
33+
member procedure remove_buffer_info(self in ut_output_buffer_base),
34+
member procedure close(self in out nocopy ut_output_buffer_base),
2935
not instantiable member procedure send_line(self in out nocopy ut_output_buffer_base, a_text varchar2, a_item_type varchar2 := null),
3036
not instantiable member procedure send_lines(self in out nocopy ut_output_buffer_base, a_text_list ut_varchar2_rows, a_item_type varchar2 := null),
3137
not instantiable member procedure send_clob(self in out nocopy ut_output_buffer_base, a_text clob, a_item_type varchar2 := null),
32-
not instantiable member function get_lines(a_initial_timeout natural := null, a_timeout_sec natural := null) return ut_output_data_rows pipelined
38+
not instantiable member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined
3339
) not final not instantiable
3440
/

0 commit comments

Comments
 (0)