Skip to content

Test for dbms_session.sleep #1155

@VladDr85

Description

@VladDr85

How to cover the sleep branch with a test: dbms_session.sleep(1). The test should work quickly.
We have the code


/*
  calculation log table
  status 0-the calculation has started and is continuing now
  status 1-the calculation was completed successfully
  status 2-the calculation failed with an error
*/
create table log_calc_tbl 
(	
  id number not null enable, 
	startdate date not null enable, 
	enddate date, 
	status number(1) not null enable, 
	id_calc_type number not null enable, 
	calcdate date
);

create or replace procedure wait_end_calcul is
  l_enddate log_calc_tbl.t_enddate%type;
  l_status  log_calc_tbl.t_status%type;
begin
  loop
    -- смотрим последний запуск за сегодня
    select max(l.t_enddate) keep(dense_rank first order by l.t_startdate desc)
          ,max(l.t_status) keep(dense_rank first order by l.t_startdate desc)
      into l_enddate
          ,l_status
      from log_calc_tbl l
     where l.t_id_calc_type = 99
       and l.t_startdate >= trunc(sysdate)
       and l.t_startdate < trunc(sysdate) + 1;
  
    if (l_status = 1 and l_enddate is not null)
    then
      --if the calculation was completed successfully then we exit
      exit;
    elsif l_status = 2
    then
      --if the calculation was completed with an error, we will return an error message
      raise_application_error(-20213,
                              'Oh, something fell');
    elsif l_status = 0 or
          l_status is null
    then
      -- if the calculation is not completed or has not started, then we are waiting
      dbms_session.sleep(60);
    end if;
  end loop;
end;
/

delete log_calc_tbl;
--calculation number 99 begins
insert into log_calc_tbl(t_id,t_startdate,t_enddate,t_status,t_id_calc_type,t_calcdate)values(1,sysdate,null,0,99,trunc(sysdate));

select * From log_calc_tbl;

begin
  wait_end_calcul;
end;

--in another session, we will set the successful completion of the calculation
update log_calc_tbl
   set t_status  = 1
      ,t_enddate = sysdate
 where t_id = 1;

--in another session, we will set an error in the calculation
update log_calc_tbl
   set t_status  = 2
      ,t_enddate = sysdate
 where t_id = 1;

Or will I have to change the production code?
Add parameters: sleep_time, loop_count

create or replace procedure wait_end_calcul(p_sleep_time number default 60, p_loop_count number default 180) is
  l_enddate log_calc_tbl.t_enddate%type;
  l_status  log_calc_tbl.t_status%type;
  i number := 0;
begin
  loop
    -- смотрим последний запуск за сегодня
    select max(l.t_enddate) keep(dense_rank first order by l.t_startdate desc)
          ,max(l.t_status) keep(dense_rank first order by l.t_startdate desc)
      into l_enddate
          ,l_status
      from log_calc_tbl l
     where l.t_id_calc_type = 99
       and l.t_startdate >= trunc(sysdate)
       and l.t_startdate < trunc(sysdate) + 1;
  
    if (l_status = 1 and l_enddate is not null)
    then
      --if the calculation was completed successfully then we exit
      exit;
    elsif l_status = 2
    then
      --if the calculation was completed with an error, we will return an error message
      raise_application_error(-20213,
                              'something fell');
    elsif i > p_loop_count
    then
      --How long can I wait? It's time to fall!
      raise_application_error(-20215,
                              'time to fall');
    elsif l_status = 0 or
          l_status is null
    then
      -- if the calculation is not completed or has not started, then we are waiting
      dbms_session.sleep(p_sleep_time);
      i := i + 1;
    end if;
  end loop;
end;
/

Change the procedure call to

begin
  wait_end_calcul(p_sleep_time => 1, p_loop_count => 1);
end;

and add test

--%test
--%throws(-20215)
procedure long_sleep;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions