>>> from blessed import Terminal
>>> from pgactivity.types import *
>>> from pgactivity.views import *

>>> term = Terminal(force_styling=None)
>>> term.width
80

Tests for help()
----------------

>>> help(term, "2.1", True)
pg_activity 2.1 - https://github.com/dalibo/pg_activity
Released under PostgreSQL License.
<BLANKLINE>
   Up/Down: scroll process list
     Space: pause/unpause
         c: sort by CPU% desc. (activities)
         m: sort by MEM% desc. (activities)
         r: sort by READ/s desc. (activities)
         w: sort by WRITE/s desc. (activities)
         t: sort by TIME+ desc. (activities)
         +: increase refresh time (max:5s)
         -: decrease refresh time (min:0.5s)
         v: change display mode
         T: change duration mode
         D: force refresh database size
         R: force refresh
         q: quit
Mode
      F1/1: running queries
      F2/2: waiting queries
      F3/3: blocking queries
<BLANKLINE>
Press any key to exit.

>>> help(term, "5.0", False)
pg_activity 5.0 - https://github.com/dalibo/pg_activity
Released under PostgreSQL License.
<BLANKLINE>
   Up/Down: scroll process list
     Space: pause/unpause
         +: increase refresh time (max:5s)
         -: decrease refresh time (min:0.5s)
         v: change display mode
         T: change duration mode
         D: force refresh database size
         R: force refresh
         q: quit
Mode
      F1/1: running queries
      F2/2: waiting queries
      F3/3: blocking queries
<BLANKLINE>
Press any key to exit.


Tests for header()
------------------


>>> ui = UI.make(refresh_time=10, duration_mode=DurationMode.backend)

Remote host:

>>> host = Host("server", "pgadm", "server.prod.tld", 5433, "app")
>>> dbinfo = DBInfo(10203040506070809, 9999)

>>> header(term, ui, host=host, dbinfo=dbinfo, pg_version="PostgreSQL 9.6", tps=12, active_connections=0,
...        width=200)
PostgreSQL 9.6 - server - pgadm@server.prod.tld:5433/app - Ref.: 10s
 Size: 9.06P - 9.76K/s ⋅ TPS: 12 ⋅ Active connections: 0 ⋅ Duration mode: backend
>>> header(term, ui, host=host, dbinfo=dbinfo, pg_version="PostgreSQL 9.6", tps=12, active_connections=0)
PostgreSQL 9.6 - server - pgadm@server.prod.tld:5433/app - Ref.: 10s
 Size: 9.06P - 9.76K/s ⋅ TPS: 12 ⋅ Active connections: 0 ⋅ Duration mode:

Local host, with priviledged access:

>>> host = Host("localhost", "tester", "host", 5432, "postgres")
>>> dbinfo = DBInfo(123456789, 12)
>>> vmem = MemoryInfo(total=6175825920, percent=42.5, used=2007146496)
>>> swap = MemoryInfo(total=6312423424, used=2340, percent=0.0)
>>> io_read = IOCounter(bytes=128, count=6)
>>> io_write = IOCounter(bytes=8, count=9)
>>> load = LoadAverage(25.0, 0.19, 0.39)
>>> sysinfo = SystemInfo(vmem, swap, load, io_read, io_write, 12)

>>> ui = UI.make(refresh_time=2, min_duration=1.2)
>>> header(term, ui, host=host, dbinfo=dbinfo, pg_version="PostgreSQL 13.1", tps=1, active_connections=79,
...        system_info=sysinfo, width=150)
PostgreSQL 13.1 - localhost - tester@host:5432/postgres - Ref.: 2s - Min. duration: 1.2s
 Size: 117.74M - 12B/s ⋅ TPS: 1 ⋅ Active connections: 79 ⋅ Duration mode: query
 Mem.: 42.5% - 1.87G/5.75G    IO Max: 12/s
 Swap: 0.0% - 2.29K/5.88G     Read:   128B/s - 6/s
 Load: 25.00 0.19 0.39        Write:  8B/s - 9/s


Tests for processes_rows()
--------------------------

>>> processes1 = [
...     LocalRunningProcess(
...         pid="6239",
...         application_name="pgbench",
...         database="pgbench",
...         user="postgres",
...         client="local",
...         cpu=0.1,
...         mem=0.993_254_939_413_836,
...         read=7,
...         write=12.3,
...         state="idle in transaction",
...         query="UPDATE pgbench_accounts SET abalance = abalance + 141 WHERE aid = 1932841;",
...         duration=0.0,
...         wait=False,
...         io_wait=False,
...         is_parallel_worker=False,
...     ),
...     LocalRunningProcess(
...         pid="6228",
...         application_name="pgbench",
...         database="pgbench",
...         user="postgres",
...         client="local",
...         cpu=0.2,
...         mem=1.024_758_418_061_11,
...         read=0.2,
...         write=1_128_201,
...         state="active",
...         query="UPDATE pgbench_accounts SET abalance = abalance + 3062 WHERE aid = 7289374;",
...         duration=0.000413,
...         wait=None,
...         io_wait=True,
...         is_parallel_worker=True,
...     ),
...     LocalRunningProcess(
...         pid="1234",
...         application_name="accounting",
...         database="business",
...         user="bob",
...         client="local",
...         cpu=2.4,
...         mem=1.031_191_760_016_45,
...         read=9_876_543.21,
...         write=1_234,
...         state="active",
...         query="SELECT product_id, p.name FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost HAVING sum(p.price * s.units) > 5000;",
...         duration=1234,
...         wait="BackendRandomLock",
...         io_wait=False,
...         is_parallel_worker=False,
...     ),
... ]

>>> ui = UI.make(flag=Flag.PID|Flag.CPU|Flag.MEM|Flag.DATABASE)
>>> processes_rows(term, ui, SelectableProcesses(processes1), 100)
6239   pgbench          0.1    1.0      idle in trans UPDATE pgbench_accounts
SET abalance = abalance + 141 WHERE aid = 1932841;
6228   pgbench          0.2    1.0             active \_ UPDATE
pgbench_accounts SET abalance = abalance + 3062 WHERE aid = 7289374;
1234   business         2.4    1.0             active SELECT product_id, p.name
FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date > CURRENT_DATE
- INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost HAVING
sum(p.price * s.units) > 5000;

6239   pgbench             0.1  1.0      idle in trans   UPDATE pgbench_accounts
SET abalance = abalance + 141 WHERE aid = 1932841;
6228   pgbench             0.2  1.0             active   \_ UPDATE
pgbench_accounts SET abalance = abalance + 3062 WHERE aid = 7289374;
1234   business            2.4  1.0             active   SELECT product_id,
p.name FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date >
CURRENT_DATE - INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost
HAVING sum(p.price * s.units) > 5000;

>>> ui.evolve(query_display_mode=QueryDisplayMode.truncate)
>>> processes_rows(term, ui, SelectableProcesses(processes1), 100)
6239   pgbench          0.1    1.0      idle in trans UPDATE pgbench_accounts S
6228   pgbench          0.2    1.0             active \_ UPDATE pgbench_account
1234   business         2.4    1.0             active SELECT product_id, p.name

>>> ui.evolve(query_display_mode=QueryDisplayMode.wrap)
>>> processes_rows(term, ui, SelectableProcesses(processes1), 100)
6239   pgbench          0.1    1.0      idle in trans UPDATE pgbench_accounts
                                                       SET abalance = abalance +
                                                       141 WHERE aid = 1932841;
6228   pgbench          0.2    1.0             active \_ UPDATE
                                                       pgbench_accounts SET
                                                       abalance = abalance +
                                                       3062 WHERE aid = 7289374;
1234   business         2.4    1.0             active SELECT product_id, p.name
                                                       FROM products p LEFT JOIN
                                                       sales s USING
                                                       (product_id) WHERE s.date
                                                       > CURRENT_DATE - INTERVAL
                                                       '4 weeks' GROUP BY
                                                       product_id, p.name,
                                                       p.price, p.cost HAVING
                                                       sum(p.price * s.units) >
                                                       5000;

>>> allflags = Flag.all()
>>> ui = UI.make(flag=allflags)
>>> term.width
80

Terminal is too narrow given selected flags, we switch to wrap_noindent mode
(TODO: this is buggy, the first line should be wrapped as well if too long)
>>> processes_rows(term, ui, SelectableProcesses(processes1), 100, width=250)
6239   pgbench                   pgbench         postgres            local 0.1    1.0  7B       12B       0.000000                N N        idle in trans UPDATE pgbench_accounts SET abalance = abalance + 141 WHERE aid = 1932841;
6228   pgbench                   pgbench         postgres            local 0.2    1.0  0B       1.08M     0.000413                  Y               active \_ UPDATE pgbench_accounts SET abalance = abalance + 3062 WHERE aid = 7289374;
1234   business               accounting              bob            local 2.4    1.0  9.42M    1.21K     20:34.00 BackendRandomLoc N               active SELECT product_id, p.name FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date >
CURRENT_DATE - INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost HAVING sum(p.price * s.units) > 5000;

>>> ui = UI.make(flag=Flag.PID|Flag.DATABASE,
...              query_display_mode=QueryDisplayMode.truncate)
>>> processes_rows(term, ui, SelectableProcesses(processes1), 100)
6239   pgbench              idle in trans UPDATE pgbench_accounts SET abalance
6228   pgbench                     active \_ UPDATE pgbench_accounts SET abalan
1234   business                    active SELECT product_id, p.name FROM produc

>>> ui.evolve(query_display_mode=QueryDisplayMode.wrap)
>>> processes_rows(term, ui, SelectableProcesses(processes1), 100)
6239   pgbench              idle in trans UPDATE pgbench_accounts SET abalance
                                           = abalance + 141 WHERE aid = 1932841;
6228   pgbench                     active \_ UPDATE pgbench_accounts SET
                                           abalance = abalance + 3062 WHERE aid
                                           = 7289374;
1234   business                    active SELECT product_id, p.name FROM
                                           products p LEFT JOIN sales s USING
                                           (product_id) WHERE s.date >
                                           CURRENT_DATE - INTERVAL '4 weeks'
                                           GROUP BY product_id, p.name, p.price,
                                           p.cost HAVING sum(p.price * s.units)
                                           > 5000;


>>> processes2 = [
...     BlockingProcess(
...         pid="6239",
...         application_name="pgbench",
...         database="pgbench",
...         user="postgres",
...         client="1.2.3.4",
...         mode="ExclusiveLock",
...         type="transactionid",
...         relation="None",
...         duration=666,
...         wait="Client Read",
...         state="active",
...         query="END;"
...     ),
...     BlockingProcess(
...         pid="6228",
...         application_name="pgbench",
...         database="pgbench",
...         user="postgres",
...         client="local",
...         mode="RowExclusiveLock",
...         type="tuple",
...         relation="ahah",
...         duration=0.000413,
...         wait="Client Read",
...         state="idle in transaction",
...         query="UPDATE pgbench_branches SET bbalance = bbalance + 1788 WHERE bid = 68;",
...     ),
... ]
>>> ui.evolve(query_mode=QueryMode.waiting)
>>> processes_rows(term, ui, SelectableProcesses(processes2), 100)
6239   pgbench                     active END;
6228   pgbench              idle in trans UPDATE pgbench_branches SET bbalance
                                           = bbalance + 1788 WHERE bid = 68;
>>> ui = UI.make(query_mode=QueryMode.blocking, flag=allflags)
>>> processes_rows(term, ui, SelectableProcesses(processes2), 100, width=250)
6239   pgbench                   pgbench         postgres          1.2.3.4      None    transactionid    ExclusiveLock  11:06.00      Client Read            active END;
6228   pgbench                   pgbench         postgres            local      ahah            tuple RowExclusiveLock  0.000413      Client Read     idle in trans UPDATE pgbench_branches SET bbalance = bbalance + 1788 WHERE bid = 68;

>>> processes1b = [
...     RunningProcess(
...         pid=6239,
...         application_name="pgbench",
...         database="pgbench",
...         user="postgres",
...         client="local",
...         state="idle in transaction",
...         query="UPDATE pgbench_accounts SET abalance = abalance + 141 WHERE aid = 1932841;",
...         duration=0.0,
...         wait=False,
...         is_parallel_worker=False,
...     ),
...     RunningProcess(
...         pid=6228,
...         application_name="none",
...         database="pgbench",
...         user="postgres",
...         client="local",
...         state="active",
...         query="UPDATE pgbench_accounts SET abalance = abalance + 3062 WHERE aid = 7289374;",
...         duration=0.000413,
...         wait=True,
...         is_parallel_worker=True,
...     ),
...     RunningProcess(
...         pid=1234,
...         application_name="accounting",
...         database="business",
...         user="bob",
...         client="192.168.0.47",
...         state="active",
...         query="SELECT product_id, p.name FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost HAVING sum(p.price * s.units) > 5000;",
...         duration=1234,
...         wait="clog",
...         is_parallel_worker=False,
...     ),
... ]
>>> all_but_local_flags = Flag.PID|Flag.DATABASE|Flag.APPNAME|Flag.USER|Flag.CLIENT|Flag.TIME|Flag.WAIT
>>> ui = UI.make(query_mode=QueryMode.activities,flag=all_but_local_flags)
>>> processes_rows(term, ui, SelectableProcesses(processes1b), 100, width=200)
6239   pgbench                   pgbench         postgres            local  0.000000                N     idle in trans UPDATE pgbench_accounts SET abalance = abalance + 141 WHERE aid = 1932841;
6228   pgbench                      none         postgres            local  0.000413                Y            active \_ UPDATE pgbench_accounts SET abalance = abalance + 3062 WHERE aid = 7289374;
1234   business               accounting              bob     192.168.0.47  20:34.00             clog            active SELECT product_id, p.name FROM products p LEFT JOIN sales s USING (product_id)
WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost HAVING sum(p.price * s.units) > 5000;

Tests scrolling in processes_rows()
-----------------------------------

>>> processes_scroll = [
...     RunningProcess(
...         pid=x,
...         application_name="pgbench",
...         database="pgbench",
...         user="postgres",
...         client="local",
...         state="active",
...         query=f"SELECT {x}",
...         duration=0.0,
...         wait=False,
...         is_parallel_worker=False,
...     ) for x in range(0, 10)]
>>> ui = UI.make(flag=Flag.PID|Flag.DATABASE)
>>> sproc = SelectableProcesses(processes_scroll)
>>> _ = sproc.focus_next()
>>> sproc.position()
0
>>> lc = line_counter(4)
>>> processes_rows(term, ui, sproc, lc.value, width=200, lines_counter=lc)
0      pgbench                     active SELECT 0
1      pgbench                     active SELECT 1
2      pgbench                     active SELECT 2
3      pgbench                     active SELECT 3
>>> for x in range(9):
...     _ = sproc.focus_next()
>>> sproc.position()
9
>>> lc = line_counter(5)
>>> processes_rows(term, ui, sproc, lc.value, width=200, lines_counter=lc)
6      pgbench                     active SELECT 6
7      pgbench                     active SELECT 7
8      pgbench                     active SELECT 8
9      pgbench                     active SELECT 9
>>> _ = sproc.focus_next()
>>> sproc.position()
0
>>> lc = line_counter(5)
>>> processes_rows(term, ui, sproc, lc.value, width=200, lines_counter=lc)
0      pgbench                     active SELECT 0
1      pgbench                     active SELECT 1
2      pgbench                     active SELECT 2
3      pgbench                     active SELECT 3
4      pgbench                     active SELECT 4
>>> for x in range(9):
...     _ = sproc.focus_next()
>>> sproc.position()
9

We never put the focus on the lower 1/5th of the screen.
For 5 display lines, the focus will be on the 4th .

>>> lc = line_counter(5)
>>> processes_rows(term, ui, sproc, lc.value, width=200, lines_counter=lc)
6      pgbench                     active SELECT 6
7      pgbench                     active SELECT 7
8      pgbench                     active SELECT 8
9      pgbench                     active SELECT 9

For 10 display lines, it should be at 8th line.

>>> lc = line_counter(10)
>>> processes_rows(term, ui, sproc, lc.value, width=200, lines_counter=lc)
2      pgbench                     active SELECT 2
3      pgbench                     active SELECT 3
4      pgbench                     active SELECT 4
5      pgbench                     active SELECT 5
6      pgbench                     active SELECT 6
7      pgbench                     active SELECT 7
8      pgbench                     active SELECT 8
9      pgbench                     active SELECT 9

Tests for footer_*()
--------------------

>>> footer_help(term)
F1/1 Running F2/2 Waiting F3/3 Blockin Space Pause/ q Quit       h Help         
>>> footer_interative_help(term)
C Cancel curre K Terminate cu Space Tag/unta Other Back to  q Quit              
>>> footer_message(term, "process 123 cancelled")
                             process 123 cancelled                              



Tests for screen()
------------------

>>> processes3 = [processes1[0], processes1[2]]

>>> host = Host("testhost", "pgadm", "server.prod.tld", 5433, "app")
>>> dbinfo = DBInfo(10203040506070809, 9999)
>>> vmem = MemoryInfo(total=4_220_876_001, percent=2.5, used=1_001_232_608)
>>> swap = MemoryInfo(total=6_312_423_424, used=2_340, percent=1.0)
>>> io_read = IOCounter(bytes=128, count=6)
>>> io_write = IOCounter(bytes=8, count=9)
>>> load = LoadAverage(0.5, 1.9, 0.93)
>>> sysinfo = SystemInfo(vmem, swap, load, io_read, io_write, 76)
>>> ui = UI.make(
...     duration_mode=DurationMode.backend,
...     refresh_time=10,
...     min_duration=1,
...     query_mode=QueryMode.activities,
...     flag=Flag.PID|Flag.CPU|Flag.MEM|Flag.DATABASE,
...     sort_key=SortKey.cpu,
...     query_display_mode=QueryDisplayMode.truncate,
...     in_pause=False,
... )
>>> screen(
...     term,
...     ui,
...     host=host,
...     dbinfo=dbinfo,
...     pg_version="PostgreSQL 13",
...     tps=5,
...     active_connections=7,
...     activity_stats=(SelectableProcesses(processes3), sysinfo),
...     message=None,
...     width=150,
... )
PostgreSQL 13 - testhost - pgadm@server.prod.tld:5433/app - Ref.: 10s - Min. duration: 1s
 Size: 9.06P - 9.76K/s ⋅ TPS: 5 ⋅ Active connections: 7 ⋅ Duration mode: backend
 Mem.: 2.5% - 954.85M/3.93G    IO Max: 76/s
 Swap: 1.0% - 2.29K/5.88G      Read:   128B/s - 6/s
 Load: 0.50 1.90 0.93          Write:  8B/s - 9/s
                                RUNNING QUERIES
PID    DATABASE         CPU%   MEM%             state Query
1234   business         2.4    1.0             active SELECT product_id, p.name FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date > C
6239   pgbench          0.1    1.0      idle in trans UPDATE pgbench_accounts SET abalance = abalance + 141 WHERE aid = 1932841;
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
F1/1 Running queries    F2/2 Waiting queries    F3/3 Blocking queries   Space Pause/unpause     q Quit                  h Help                        

(using terminal width)
>>> screen(
...     term,
...     ui,
...     host=host,
...     dbinfo=dbinfo,
...     pg_version="PostgreSQL 13",
...     tps=5,
...     active_connections=7,
...     activity_stats=(SelectableProcesses(processes3[:-1]), sysinfo),
...     message=f"Process {processes3[-1].pid} killed",
... )
PostgreSQL 13 - testhost - pgadm@server.prod.tld:5433/app - Ref.: 10s - Min.
 Size: 9.06P - 9.76K/s ⋅ TPS: 5 ⋅ Active connections: 7 ⋅ Duration mode: backend
 Mem.: 2.5% - 954.85M/3.93G    IO Max: 76/s
 Swap: 1.0% - 2.29K/5.88G      Read:   128B/s - 6/s
 Load: 0.50 1.90 0.93          Write:  8B/s - 9/s
                                RUNNING QUERIES
PID    DATABASE         CPU%   MEM%             state Query
1234   business         2.4    1.0             active SELECT product_id, p.name
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
                              Process 6239 killed                               
