Commit Graph

161 Commits

Author SHA1 Message Date
Barnabás Pőcze
b1c189fa86 test: rewrite test which destroys active source before dispatching
Rewrite the test that destroys an active managed source
right after polling is done. There is no need to use a
thread loop because the same thing can be simulated using
the before/after loop control hooks in a more controlled
manner.
2022-03-06 18:40:43 +00:00
Barnabás Pőcze
1e99551233 test: loop: do not use NULL as event handler 2022-03-06 18:40:43 +00:00
Pauli Virtanen
7ade8fa8fb pwtest: fix daemon log scrambling
Nonblocking pipes can scramble logs if we read too slow, so use max size
buffers.

Also use CLOEXEC for the pipes to be safer, and minor other fixes.
2022-03-06 02:29:35 +02:00
Pauli Virtanen
8673f8c03d pwtest: shorter default timeout 2022-03-05 17:51:22 +00:00
Pauli Virtanen
f3831da67a pwtest: ARG_DAEMON tests don't work on valgrind 2022-03-05 17:51:22 +00:00
Pauli Virtanen
c604f1608a test: add simple functional tests
Try running openal-info.
2022-03-05 17:51:22 +00:00
Pauli Virtanen
76bab25afb pwtest: handle SIGTERM/SIGINT in runner
Catch SIGTERM/SIGINT in test runner, and clean up any spawned processes.

Fixes printing test output on termination by signal (e.g. meson
timeout), and doesn't leave spawned processes running.
2022-03-05 17:51:22 +00:00
Pauli Virtanen
ad3c90dbb9 pwtest: use default debug level 4 for spawned daemons 2022-03-05 17:51:22 +00:00
Pauli Virtanen
a7bd52d07d pwtest/Makefile: set SPA_DATA_DIR 2022-03-05 17:51:22 +00:00
Pauli Virtanen
581f6c7f1d pwtest: add pwtest_spawn for running external programs 2022-03-05 17:51:22 +00:00
Pauli Virtanen
df4f844daa pwtest: ensure all spawned daemons are terminated
Set process group, and send signal to them all.
2022-03-05 17:51:22 +00:00
Barnabás Pőcze
d1f7e96f82 test: loop: add test for destroying source of thread loop
Add test which tries to destroy an active source precisely
after the loop has returned from polling but has not yet
acquired the thread loop lock.
2022-02-18 20:31:49 +01:00
Wim Taymans
231cc88cad test: don't leak the two objects 2022-02-08 19:04:08 +01:00
Barnabás Pőcze
bf886ba209 support: also protect against recursive invocations
Add an extra private field to the source to store the pollevent of
the current iteration. This changes ABI but it seems an embedded source
is not used outside of our own plugins and the unit test doesn't test
this ABI case.

Whenever a source is removed, we can set the data field of the
pollevent to NULL so that it won't be handled in any iteration anymore.

Avoid dispatching the same event multiple times when doing recursive
iterations.

Add some more unit tests for this.

Fixes #2114
2022-02-08 17:21:10 +01:00
Wim Taymans
834ecd733d test: call pw_deinit() at end of test 2022-02-08 11:34:08 +01:00
Wim Taymans
d28af43689 test: fix dll unload
Call spa_handle_clear() on the handle before freeing.
Actually store the loaded dll in the right array.
First clear the handle, then close the dll.
Fix iteration of the dlls.
2022-02-08 11:31:38 +01:00
Wim Taymans
5ac5ebfe19 test: add test for the loop 2022-02-08 11:08:16 +01:00
Barnabás Pőcze
15e7a61aa7 treewide: only define feature macros when the feature is available
Most feature checks already use #ifdef, and do not care about
the value of the macro. Convert all feature checks to do that,
and simplify the meson build scripts by replacing

  if cond
    cdata.set('X', 1)
  endif

with

  cdata.set('X', cond)
2022-02-04 00:15:59 +01:00
Wim Taymans
9bac90882d test: disable broken test
When a prefix is given, the file should not be found.
2022-02-01 18:15:16 +01:00
Wim Taymans
611591d0fc json: add spa_json_parse_stringn()
It also checks the destination size.
2022-01-04 12:37:00 +01:00
Barnabás Pőcze
8ed46a283f treewide: meson.build: use project_{build,source}_root()
Use `meson.project_{build,source}_root()` instead of
`meson.{build,source}_root()` because those functions
do not work as expected when used inside a subproject,
and they have been deprecated in meson 0.56.0.
2021-12-28 18:37:18 +01:00
Barnabás Pőcze
2b110af366 treewide: meson.build: use dependency variable for SPA
Use `spa_dep` everywhere instead of `spa_inc`,
and remove `spa_inc` altogether.
2021-12-28 18:34:06 +01:00
Barnabás Pőcze
0680e249e5 test: test-logger: ignore some systemd journal error codes
Some errors from `sd_journal_get_data()` are not (and
should not be considered) fatal from the point of view of
the test. Ignore them.

See #1710
2021-12-01 11:13:50 +01:00
Barnabás Pőcze
3d152db758 test: null terminate output buffers
Previously, the standard i/o stream and daemon logs
were not properly null terminated, which could cause
issues in `print_lines()` inside `log_test_result()`.

See #1710
2021-12-01 11:12:58 +01:00
Peter Hutterer
07c5511aed test: handle chdir errors correctly
When we get to this code, we already updated the environment variables
so we need to use the usual error path to restore them.

And where chdir does fail, print an error to the log. 256 chars should
be enough here, if your tmpdir exceeds that you just have the error
message cut off.
2021-10-26 11:15:35 +10:00
Peter Hutterer
cf3c0431c3 test: fix tmpdir value after setenv
Introduced in a2856c6e0f

set_test_env() modifies TMPDIR so we must not use getenv until after
that call.

Fixes #1736
2021-10-26 11:15:34 +10:00
Wim Taymans
c07f0ccb71 map: make _insert_at() fail on a removed item
You are only supposed to use _insert_new()/_remove() or _insert_at()
on the map, If we detect a _insert_at() to a removed item,
return an error because else we might corrupt the free list.

Update unit test accordingly.
2021-10-25 16:17:35 +02:00
Gleb Popov
e26b40a75f Fix compiler warning by spelling the initializer properly. 2021-10-22 19:04:47 +03:00
Peter Hutterer
a2856c6e0f test: silence coverity warnings about potential tmpdir being NULL 2021-10-15 14:42:26 +10:00
Peter Hutterer
04d32ba794 test: fix a variable initialization
Technically valid since it's a null pointer but let's not do this.
2021-10-12 08:58:39 +00:00
Peter Hutterer
36c1917a16 test: use a function-specific token instead of a common one
This avoid false detections of the MARK token from other tetsts when
tests are run in parallel.
2021-10-12 08:58:39 +00:00
Peter Hutterer
e7ac8adaa5 test: wait up to a second for our MARK message to appear in the journal
The previous code exposed a race condition, it assumed that our MARK
message was in the next lot of messages by the journal. If something
else would write to the journal in the meantime and our message took
time to arrive, the test would fail.

Fixes #1710
2021-10-12 08:58:39 +00:00
Peter Hutterer
1f497f3248 test: call pw_deinit() at the end of the context tests 2021-10-12 09:45:33 +10:00
Peter Hutterer
ff85c2835f test: enable debug logging for the valgrind test
Valgrind tests are running under different conditions than normal tests,
specifically they all run in the same process rather than running one
fork per test. This means one test can affect another test's result if
the test doesn't clean up propertly.

This makes them harder to debug from the logs, so let's give us a
fighting chance by having debug logging enabled.
2021-10-12 09:45:33 +10:00
Peter Hutterer
5ac456f294 test: match the meson test names with the binary names
Easier to find this way what caused a test suite failure.
2021-10-12 09:45:33 +10:00
Peter Hutterer
c44d0a6bbc spa: declare a dependency for the dbus lib
When running meson test without a preceding ninja build, we end up with
missing libraries. This somehow happened to work until recently but now
it triggers an issue with libspa-dbus.so not being available during the
valgrind test run, causing a test case to fail.
2021-10-12 09:45:33 +10:00
Peter Hutterer
6df8ce3031 test: fix a race condition with the journal test
The docs are slightly ambiguous here but it appears a call to
sd_journal_next() is required at least once before the actual data
message.

journalctl positions the cursor with sd_journal_seek_tail() followed by
sd_journal_seek_previous(). The actual enty is then fetched with
sd_journal_next().

Let's do the same here and let's hope this fixes the current race
condition with the test sometimes failing.
2021-10-11 07:23:38 +00:00
Wim Taymans
5f7c4dec34 meson: make it possible to compile without dbus
Make an option to disable dbus and all the code that depends on
it.

Fixes #1685
2021-10-09 15:00:04 +02:00
Peter Hutterer
3f6521819f test: add a filter for iteration
Debugging is easier if we can explicitly run a single iteration only.
This filter could be a range but for now it's sufficient to be able to
run a single test only.
2021-10-08 07:06:42 +00:00
Peter Hutterer
626d30e4bd map: fix free_list corruption when re-using removed ids
Re-using an id after removing it is a bug in the caller but there are
two cases where we corrupt the free list without warning:

Removing an object twice:

   id = pw_map_insert_new(object);
   pw_map_remove(map, id);
   pw_map_remove(map, id);

And inserting an element at an index previously removed:

   id = pw_map_insert_new(object);
   pw_map_remove(map, id);
   pw_map_insert_at(map, id, new_object);

The latter is arguably valid code, or at least it'll look like it's
valid code.

For both cases, check if the id to remove/insert at is a free item and
handle that accordingly.
2021-10-08 12:40:23 +10:00
Peter Hutterer
5b9447c2a4 test: add some map tests 2021-10-08 12:40:23 +10:00
Björn Daase
cf38b7bdc4 fix codespell issues 2021-10-07 15:26:18 +00:00
Peter Hutterer
e36183d3cf array: re-initialize the array in pw_array_clear()
Leaving the data nonzero is a use-after-free bug waiting to happen.
2021-10-07 15:08:57 +10:00
Pauli Virtanen
8159797f89 doc: reorganize Doxygen groups/modules to make more sense
The Doxygen "Modules" page is not very illuminative, as different parts
of the API are mixed together and not all parts are included.

Try to address this:

Put all parts of the public API to some Doxygen group, usually one group
per header file. Use short, systematic names.

Make these groups sub-groups of a few top-level groups, roughly
corresponding to the different logical parts of the API (core, impl,
stream, filter, spa, utilities).
2021-10-03 15:39:27 +03:00
Wim Taymans
33787ffe1c tests: fix log test 2021-09-29 17:06:35 +02:00
Wim Taymans
a9c64e1609 fix versions of the log interface 2021-09-29 17:03:26 +02:00
Peter Hutterer
52bd80aaa4 log: add topic loggers and a default topic
pw_log_log/logv now go through the topic-based logger using the
"default" topic. Log topics themselves can be allocated by the call
sites. The simplest way to use a topic from e.g. a module:

    PW_LOG_TOPIC_STATIC(mod_topic, "mod.foo");
    #define PW_LOG_TOPIC_DEFAULT mod_topic
    ...
    void pipewire__module_init() {
  	  PW_LOG_TOPIC_INIT(mod_topic);
  	  ...
    }

With the #define all pw_log_foo() are now routed through the custom
topic. For the cases where the log topic must be specified, a
pw_logt_foo() set of macros is available.

Log topics are enabled through the PIPEWIRE_DEBUG environment variable
which now supports globs, e.g. PIPEWIRE_DEBUG="*:I;mod.access:D"
to enable global INFO but DEBUG for the access module.

Namespaces documented are "pw", "mod" and "conn", for pipewire-internal
stuff, modules and connection dumping. The latter is special-cased to
avoid spamming the log files, it requires an expcit "conn.<glob>"
pattern to enable.

The "default" topic always exists and is the fallback for any
pw_log_foo() invocation that does not use a topic.
2021-09-28 09:35:38 +02:00
Peter Hutterer
59a5791d41 spa: implement the new topic logging for the provided loggers
Both simple log implementation now support the new topic-based
functions, and so does the journal logger too.
2021-09-28 09:35:38 +02:00
Peter Hutterer
0e60e9c063 spa: add topic-based logging
Add a struct spa_log_topic that allows for logical grouping of messages.
The new macros spa_log_logt() and spa_log_logtv() take a topic as
argument, the topic's level acts as filter.
A new macro spa_log_topic_init() initializes a topic. By default a topic
inherits its logger's debug level but a logger implementation may set
that topic to a specific fixed log level.

The various spa_log_*() macros transparently wrap new and old
implementations:
- if the implementation is version 0, the new logt() calls drop the
  topic and get routed into the old log() calls
- if the implementation is version 1, the old log() calls use a NULL
  topic and get routed into the new logt() calls

All spa_log_* macros use the SPA_LOG_DEFAULT_TOPIC topic (NULL), it is
up to the caller to redefine that. Alternatively, use spa_logt_* to pass
an explicit topic.

There is one crucial flaw in this implementation: log topics are
initialized to their target level by the current logger. Where a topic
is initialized but the logger is switched later, the topic is not
automatically re-initialized. Ultimately this shouldn't matter for
real-world use-cases.
2021-09-28 09:35:38 +02:00
Peter Hutterer
cbcf62f341 spa: add a macro to check for a callback version
spa_interface_call() and friends will quietly do nothing if the version
doesn't match so we need an extra macro to know whether we can
spa_interface_call() for any given version.

This allows us to implement things like:
   if (spa_interface_callback_version_min(1)
        spa_interface_call(..., 1, func_v1)
   else
        spa_interface_call(..., 0, func_v0)
2021-09-28 09:35:38 +02:00
Peter Hutterer
6668d5bbc4 test: fix the environment variable name to disable systemd logging
Fixes 165bc7e289
2021-09-24 12:33:15 +10:00
Peter Hutterer
2b65fb36f2 test: simplify the logger test a bit
The tests using this function use the pw_log* macros which invoke
whichever logger pipewire has set. Since the default logging
implementation supports logging to a file anyway, let's just use that
instead of having to load the plugin ourselves.
2021-09-24 12:33:02 +10:00
Peter Hutterer
165bc7e289 test: disable the journal logger for tests
No point spamming the journal here.
2021-09-23 15:40:47 +10:00
Peter Hutterer
29fdd10066 test: add two tests for the spa_interface callback versioning 2021-09-23 15:30:22 +10:00
Peter Hutterer
c6f0ac7ff0 test: fix the calls to pw_deinit()
Missing from some tests, superfluous in the other test because it was
already called in the test_log_levels() helper function
2021-09-22 12:15:35 +10:00
Peter Hutterer
48cff597a6 test: don't try to log for LOG_LEVEL_NONE
We can only log for a level below our current one if we are two above
NONE. And by the same instance, we don't expect NONE messages to show
up.
2021-09-22 12:15:34 +10:00
Peter Hutterer
b00bc81929 test: fix a use-of-uninitialized-variable compiler warning
False positive, we abort in the cases where this isn't initialized.

Fixes e1672f9762
2021-09-22 12:15:33 +10:00
Peter Hutterer
dfb40fb714 test: implement a test for the journal logger 2021-09-20 07:29:03 +00:00
Peter Hutterer
0cbd56f0cd spa: declare a dependency for each used library in meson.build
For SPA libraries that we link against elsewhere in the tree, declare a
declare a dependency "foo_dep" for that library that specifies how to
link to it. Then use that dependency in the various targets.

This removes the knowledge of how to link with the library from the
target which can treat it as just another dependency.

In the case of optional libraries (e.g. the journal support lib) we can
then use declare_dependency() to declare an empty dependencies and thus
link them unconditionally in the target.
2021-09-20 07:29:03 +00:00
Peter Hutterer
e1672f9762 pipewire: allow for log level names in PIPEWIRE_DEBUG
Allow one of "XEWIDT" to refer to none, errors, warnings, info, debug
and trace, respectively because they're immediately recognizable. Well,
except maybe the X.

PIPEWIRE_DEBUG="I" is equivalent to PIPEWIRE_DEBUG="3" for example.
2021-09-10 07:38:20 +00:00
Peter Hutterer
0a21d76334 test: add tests for the log levels to show up correctly
Two tests, once with pw_log_set_level(), once with PIPEWIRE_DEBUG
2021-09-10 07:38:20 +00:00
Nils Tonnätt
dd12910769 Revert "[Meson] Fix all deprecation warnings"
This reverts commit f7e1175ef0.
2021-08-08 19:18:40 +00:00
Nils Tonnätt
f7e1175ef0 [Meson] Fix all deprecation warnings 2021-08-06 07:56:16 +00:00
Nils Tonnätt
761fa6f59d meson: fix meson test without building pipewire before
This adds project internal dependencies to some tests to let all
tests succeed. It is not adding all dependencies those tests actually
need.
2021-08-04 20:38:30 +02:00
Peter Hutterer
d0060fbddd test: move the client and utils tests over here 2021-08-04 07:45:06 +00:00
Peter Hutterer
49f3d5842e test: replace all spa_assert() macros with spa_assert_se()
These are tests, we never want those to be optimized away.
2021-07-27 10:24:44 +10:00
Peter Hutterer
731888fcdd test: fix a memleak in the config tests
Fixes bba9edabee
2021-07-07 11:03:23 +00:00
Peter Hutterer
4f49e893c1 test: init the pod test buffer with a fixed value
Works around the valgrind complaints when we call spa_debug_mem() on the
buffer with various sizes.
2021-07-07 11:03:23 +00:00
Peter Hutterer
5ebfbccd16 pwtest: if a test expects a signal, skip it under valgrind
Running under valgrind enforces --no-fork so any signal will cause valgrind
to error out, failing the test abnormally. This prevents us from running
our test suite through valgrind, we'd have to mark every test specifically
whether it should run under valgrind or not.

Easier is just to automatically skip tests expecting signals.
2021-07-07 11:03:23 +00:00
Peter Hutterer
bba9edabee conf: don't allow a NULL config name
No functional changes, this is enforced by the only in-tree callers of
pw_conf_load_conf() but let's enforce this properly.
2021-07-06 07:14:21 +00:00
Peter Hutterer
fb2d35895e conf: ignore the prefix if the config file name is an absolute path
Fixes:
$ export PIPEWIRE_CONFIG_PREFIX=/usr/share/pipewire
$ pipewire -c /etc/pipewire/bar.conf
[W][11925.530591][          conf.c:  253 conf_load()] config 0x560039ac6510: error loading config '/usr/share/pipewire//etc/pipewire/pipewire.conf': No such file or directory
[W][11925.530721][       context.c:  178 try_load_conf()] context 0x560039ac6190: can't load config /usr/share/pipewire//etc/pipewire/pipewire.conf: No such file or directory
2021-07-06 07:14:21 +00:00
Peter Hutterer
b1ac776ff0 test: remove duplicate test invocation 2021-07-06 07:14:21 +00:00
Barnabás Pőcze
f5d51162c4 treewide: mark things static and const
Mark some structures, arrays static/const at various places.
In some cases this prevents unnecessary initialization
when a function is entered.

All in all, the text segments across all shared
libraries are reduced by about 2 KiB. However,
the total size increases by about 2 KiB as well.
2021-06-30 14:44:08 +02:00
Niklāvs Koļesņikovs
e062c4d8de meson.build: adds summary() to optional programs 2021-06-29 17:23:37 +00:00
Peter Hutterer
0880ff9a84 spa: add spa_strendswith (copy from protocol-pulse)
Useful function, let's make it generally available.
2021-06-25 08:42:24 +00:00
Peter Hutterer
01c2cb3d45 test: shut up coverity complaints about side effects
CID 1457494:  Incorrect expression  (ASSERT_SIDE_EFFECT)
Assignment "ai = (void *)((uint8_t *)pod + 16)" has a side effect.  This code will work differently in a non-debug build.
550             spa_assert((ai = SPA_POD_ARRAY_VALUES(pod)) != NULL);

Patch generated with coccinelle snippet
	@@
	expression E1, E2;
	@@
	- spa_assert((E1 = E2) != NULL);
	+ E1 = E2;
	+ spa_assert(E1 != NULL);

And run again for == NULL
2021-06-24 11:14:27 +00:00
Wim Taymans
575d4456e1 tests: fix test 2021-06-22 16:31:51 +02:00
Evgeniy Khramtsov
c3d7561d17 test: unbreak FreeBSD 2021-06-21 09:28:02 +00:00
Peter Hutterer
a4bdf83e39 test: explicitly ignore the read() result from the timerfd/pidfd
We don't care about the actual read() being successful - it won't be on pidfd
and on timerfd it's just a timestamp we don't need.
2021-06-21 07:17:10 +00:00
Peter Hutterer
f9985636de test: fail if we can't chdir to $TMPDIR
Otherwise our tests may have unpredictable behavior depending on leftover
files in $PWD.
2021-06-21 07:17:10 +00:00
Peter Hutterer
3c798ea413 test: force TMPDIR to /tmp if it is unset
This way we can rely on it everywhere without having multiple checks for it.
2021-06-21 07:17:10 +00:00
Peter Hutterer
00bc5f0e3b test: drop duplicate init of test->result
Set to the same value 5 lines above
2021-06-21 07:17:10 +00:00
Wim Taymans
c46cb0645e test: fix test
There is now one more global item.
2021-06-17 11:14:20 +02:00
Peter Hutterer
62e98aa836 test: move some of the property tests to pwtest
Mostly 1:1 move of the test-properties.c file in src to the one in test, but a
few checks were merged into the existing functions.
2021-06-17 07:08:53 +00:00
Peter Hutterer
461ae02c50 test: shut up a compiler warning about an unused variable
gcc 9 complains about `v` being potentially uninitialized. This is a false
positive, we'd exit() on any error before using `v` but the compiler doesn't
seem to know that. Let's shut up the warning.
2021-06-10 20:39:58 +10:00
Peter Hutterer
7177d82c34 test: check for CAP_SYS_PTRACE before testing for an attached debugger
If we don't have the capability to ptrace, we are probably running inside a
container, not the debugger. Check this first so we don't disable forking
mode.

Make this conditional on libcap - where libcap is not available always assume
we *do not* have a debugger attached. This is easier than telling everyone who
runs the tests in a confined system to install libcap.

Fixes #1285
2021-06-10 09:36:12 +02:00
Peter Hutterer
14eb43ea86 meson.build: check for SYS_pidfd_open 2021-06-10 15:19:20 +10:00
Peter Hutterer
731f45ed50 test: add sigabbrev_np() for systems where it's not available
sigabbrev_np() was first added to glibc 2.32 (Aug 2020) which is too recent
for some of the distributions we support.
2021-06-10 15:13:57 +10:00
Peter Hutterer
da339c286f meson.build: drop HAVE_CONFIG_H
This is an autotools leftover, with meson we're always guaranteed to have
the config.h file.
2021-06-10 09:04:16 +10:00
Peter Hutterer
b2206e2530 test: change VERSION to HOOK_VERSION for the spa hooks test
VERSION is defined in config.h for the project version which will cause a
conflict here.
2021-06-10 09:04:16 +10:00
Wim Taymans
667fa18526 test: fix property test
The long key is now ignored instead of truncated.
2021-06-09 18:17:31 +02:00
Peter Hutterer
d09df66aec test: drop the valgrind timeout multiplier to 3
30s * 100 as timeout for a single test is a bit too much.
2021-06-09 19:41:07 +10:00
Peter Hutterer
9a65d90e88 test: move the spa tests to pwtest
Move the spa tests to the pwtest framework. The pod tests have only been
wrapped in the function callers, they don't use the variuos pwtest helpers -
too much work for very little gain here. Can be done incrementally if needed.

Note that this removes the spa tests from the installed tests. Arguably,
installing those tests was unnecessary anyway since they are static binaries
and don't load anything. So having them installed runs the same tests as
having them run in the source tree.

Goal for the pwtest framework is to allow for installed tests, just not there
yet.
2021-06-09 18:00:59 +10:00
Peter Hutterer
008195924c test: add a test for the properties stack overflow
See #1249
2021-06-09 18:00:58 +10:00
Peter Hutterer
7240058bee test: add test for logger's ANSI escape sequences
Set up the logger with colors enabled but since our log file is not a tty,
this should not print any ansi sequences into the log.
2021-06-09 18:00:39 +10:00
Peter Hutterer
518ffde9ec test: add a test for the logger truncation
See c851349f17
2021-06-09 18:00:39 +10:00
Peter Hutterer
dcfd6745d0 test: move the context tests to here 2021-06-09 18:00:39 +10:00
Peter Hutterer
53215a66b9 test: hook up a valgrind test run in meson
Use with:
	meson test -C builddir --setup=valgrind
2021-06-09 18:00:39 +10:00
Peter Hutterer
7909c99ead test: convert two spa tests to pwtest 2021-06-09 18:00:39 +10:00
Peter Hutterer
493f0724b5 test: move the array tests to pwtest
Add them to the existing pw_properties test binary and rename that to
pw-utils.

Same functionality as before for the pw_array tests.
2021-06-09 18:00:39 +10:00