1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//
6// Helper functions for setting up and tearing down a test fixture which
7// manages the trace engine on behalf of a test.
8//
9
10#pragma once
11
12#include <stddef.h>
13
14#ifdef __cplusplus
15#include <fbl/string.h>
16#include <fbl/vector.h>
17#include <trace-engine/buffer_internal.h>
18#include <trace-reader/records.h>
19#endif
20
21#include <lib/async-loop/loop.h>
22#include <trace-engine/types.h>
23#include <unittest/unittest.h>
24#include <zircon/compiler.h>
25
26// Specifies whether the trace engine async loop uses the same thread as the
27// app or a different thread.
28typedef enum {
29    // Use different thread from app.
30    kNoAttachToThread,
31    // Use same thread as app.
32    kAttachToThread,
33} attach_to_thread_t;
34
35#ifdef __cplusplus
36
37// FixtureSquelch is used to filter out elements of a trace record that may
38// vary run to run or even within a run and are not germaine to determining
39// correctness. The canonical example is record timestamps.
40// The term "squelch" derives from radio circuitry used to remove noise.
41struct FixtureSquelch;
42
43// |regex_str| is a regular expression consistenting of one or more
44// subexpressions, the text in the parenthesis of each matching expressions
45// is replaced with '<>'.
46// Best illustration is an example. This example removes decimal numbers,
47// koids, timestamps ("ts"), and lowercase hex numbers.
48// const char regex[] = "([0-9]+/[0-9]+)"
49//   "|koid\\(([0-9]+)\\)"
50//   "|koid: ([0-9]+)"
51//   "|ts: ([0-9]+)"
52//   "|(0x[0-9a-f]+)";
53// So "ts: 123 42 mumble koid(456) foo koid: 789, bar 0xabcd"
54// becomes "ts: <> <> mumble koid(<>) foo koid: <>, bar <>".
55bool fixture_create_squelch(const char* regex_str, FixtureSquelch** out_squelch);
56void fixture_destroy_squelch(FixtureSquelch* squelch);
57fbl::String fixture_squelch(FixtureSquelch* squelch, const char* str);
58
59bool fixture_compare_raw_records(const fbl::Vector<trace::Record>& records,
60                                 size_t start_record, size_t max_num_records,
61                                 const char* expected);
62bool fixture_compare_n_records(size_t max_num_records, const char* expected,
63                               fbl::Vector<trace::Record>* records);
64
65using trace::internal::trace_buffer_header;
66void fixture_snapshot_buffer_header(trace_buffer_header* header);
67
68#endif
69
70__BEGIN_CDECLS
71
72void fixture_set_up(attach_to_thread_t attach_to_thread,
73                    trace_buffering_mode_t mode, size_t buffer_size);
74void fixture_tear_down(void);
75void fixture_start_tracing(void);
76
77// There are two ways of stopping tracing.
78// 1) |fixture_stop_tracing()|:
79//    a) stops the engine,
80//    b) waits for everything to quiesce,
81//    c) shuts down the dispatcher loop.
82//    A variant of this is |fixture_stop_tracing_hard()| which is for
83//    specialized cases where the async loop exits forcing the engine to
84//    quit on its own.
85// 2) |fixture_stop_engine(),fixture_shutdown()|: This variant splits out
86//    steps (a) and (c) above, leaving the test free to manage step (b): the
87//    quiescence.
88void fixture_stop_tracing(void);
89void fixture_stop_tracing_hard(void);
90void fixture_stop_engine(void);
91void fixture_shutdown(void);
92
93async_loop_t* fixture_async_loop(void);
94zx_status_t fixture_get_disposition(void);
95bool fixture_wait_buffer_full_notification(void);
96uint32_t fixture_get_buffer_full_wrapped_count(void);
97void fixture_reset_buffer_full_notification(void);
98bool fixture_compare_records(const char* expected);
99
100static inline void fixture_scope_cleanup(bool* scope) {
101    fixture_tear_down();
102}
103
104#define DEFAULT_BUFFER_SIZE_BYTES (1024u * 1024u)
105
106// This isn't a do-while because of the cleanup.
107#define BEGIN_TRACE_TEST_ETC(attach_to_thread, mode, buffer_size) \
108    BEGIN_TEST;                                                   \
109    __attribute__((cleanup(fixture_scope_cleanup))) bool __scope; \
110    (void)__scope;                                                \
111    fixture_set_up((attach_to_thread), (mode), (buffer_size))
112
113#define BEGIN_TRACE_TEST \
114    BEGIN_TRACE_TEST_ETC(kNoAttachToThread, TRACE_BUFFERING_MODE_ONESHOT, \
115                         DEFAULT_BUFFER_SIZE_BYTES)
116
117#define END_TRACE_TEST \
118    END_TEST;
119
120#ifndef NTRACE
121#ifdef __cplusplus
122#define ASSERT_RECORDS(expected_c, expected_cpp) \
123    ASSERT_TRUE(fixture_compare_records(expected_c expected_cpp), "record mismatch")
124#define ASSERT_N_RECORDS(max_num_recs, expected_c, expected_cpp, records) \
125    ASSERT_TRUE(fixture_compare_n_records((max_num_recs), expected_c expected_cpp, (records)), "record mismatch")
126#else
127#define ASSERT_RECORDS(expected_c, expected_cpp) \
128    ASSERT_TRUE(fixture_compare_records(expected_c), "record mismatch")
129#endif // __cplusplus
130#else
131#define ASSERT_RECORDS(expected_c, expected_cpp) \
132    ASSERT_TRUE(fixture_compare_records(""), "record mismatch")
133#ifdef __cplusplus
134#define ASSERT_N_RECORDS(max_num_recs, expected_c, expected_cpp, records) \
135    ASSERT_TRUE(fixture_compare_records((max_num_recs), "", (records)), "record mismatch")
136#endif
137#endif // NTRACE
138
139__END_CDECLS
140