1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   core.cpp
9  * \author Andrey Semashev
10  * \date   08.02.2009
11  *
12  * \brief  This header contains tests for the logging core.
13  */
14 
15 #define BOOST_TEST_MODULE core
16 
17 #include <cstddef>
18 #include <map>
19 #include <string>
20 #include <boost/smart_ptr/shared_ptr.hpp>
21 #include <boost/move/utility.hpp>
22 #include <boost/test/unit_test.hpp>
23 #include <boost/log/core/core.hpp>
24 #include <boost/log/attributes/constant.hpp>
25 #include <boost/log/attributes/attribute_set.hpp>
26 #include <boost/log/attributes/attribute_value_set.hpp>
27 #include <boost/log/expressions.hpp>
28 #include <boost/log/sinks/sink.hpp>
29 #include <boost/log/core/record.hpp>
30 #ifndef BOOST_LOG_NO_THREADS
31 #include <boost/thread/thread.hpp>
32 #endif // BOOST_LOG_NO_THREADS
33 #include "char_definitions.hpp"
34 #include "test_sink.hpp"
35 
36 namespace logging = boost::log;
37 namespace attrs = logging::attributes;
38 namespace sinks = logging::sinks;
39 namespace expr = logging::expressions;
40 
41 // The test checks that message filtering works
BOOST_AUTO_TEST_CASE(filtering)42 BOOST_AUTO_TEST_CASE(filtering)
43 {
44     typedef logging::attribute_set attr_set;
45     typedef logging::core core;
46     typedef logging::record record_type;
47     typedef test_data< char > data;
48 
49     attrs::constant< int > attr1(10);
50     attrs::constant< double > attr2(5.5);
51 
52     attr_set set1;
53     set1[data::attr1()] = attr1;
54     set1[data::attr2()] = attr2;
55 
56     boost::shared_ptr< core > pCore = core::get();
57     boost::shared_ptr< test_sink > pSink(new test_sink());
58     pCore->add_sink(pSink);
59 
60     // No filtering at all
61     {
62         record_type rec = pCore->open_record(set1);
63         BOOST_REQUIRE(rec);
64         pCore->push_record(boost::move(rec));
65         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
66         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
67         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
68         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
69         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
70         pSink->clear();
71     }
72 
73     // Core-level filtering
74     {
75         pCore->set_filter(expr::has_attr(data::attr3()));
76         record_type rec = pCore->open_record(set1);
77         BOOST_CHECK(!rec);
78         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 0UL);
79         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
80         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 0UL);
81         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
82         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
83         pSink->clear();
84     }
85     {
86         pCore->set_filter(expr::has_attr(data::attr2()));
87         record_type rec = pCore->open_record(set1);
88         BOOST_REQUIRE(rec);
89         pCore->push_record(boost::move(rec));
90         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
91         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
92         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
93         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
94         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
95         pSink->clear();
96     }
97 
98     // Sink-level filtering
99     {
100         pCore->reset_filter();
101         pSink->set_filter(expr::has_attr(data::attr2()));
102         record_type rec = pCore->open_record(set1);
103         BOOST_REQUIRE(rec);
104         pCore->push_record(boost::move(rec));
105         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
106         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
107         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
108         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
109         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
110         pSink->clear();
111     }
112     {
113         pSink->set_filter(expr::has_attr(data::attr3()));
114         record_type rec = pCore->open_record(set1);
115         BOOST_CHECK(!rec);
116         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 0UL);
117         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
118         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 0UL);
119         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
120         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
121         pSink->clear();
122         pSink->reset_filter();
123     }
124     // Only one sink of the two accepts the record
125     {
126         pSink->set_filter(expr::has_attr(data::attr2()));
127 
128         boost::shared_ptr< test_sink > pSink2(new test_sink());
129         pCore->add_sink(pSink2);
130         pSink2->set_filter(expr::has_attr(data::attr3()));
131 
132         record_type rec = pCore->open_record(set1);
133         BOOST_REQUIRE(rec);
134         pCore->push_record(boost::move(rec));
135 
136         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
137         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
138         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
139         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
140         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
141         pSink->clear();
142 
143         BOOST_CHECK_EQUAL(pSink2->m_RecordCounter, 0UL);
144         BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr1()], 0UL);
145         BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr2()], 0UL);
146         BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr3()], 0UL);
147         BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr4()], 0UL);
148         pCore->remove_sink(pSink2);
149     }
150 
151     pCore->remove_sink(pSink);
152     pCore->reset_filter();
153 }
154 
155 #ifndef BOOST_LOG_NO_THREADS
156 namespace {
157 
158     //! A test routine that runs in a separate thread
thread_attributes_test()159     void thread_attributes_test()
160     {
161         typedef test_data< char > data;
162         typedef logging::core core;
163         typedef logging::record record_type;
164         typedef logging::attribute_set attr_set;
165         attrs::constant< short > attr4(255);
166 
167         boost::shared_ptr< core > pCore = core::get();
168         pCore->add_thread_attribute(data::attr4(), attr4);
169 
170         attr_set set1;
171         record_type rec = pCore->open_record(set1);
172         BOOST_CHECK(rec);
173         if (rec)
174             pCore->push_record(boost::move(rec));
175     }
176 
177 } // namespace
178 #endif // BOOST_LOG_NO_THREADS
179 
180 // The test checks that global and thread-specific attributes work
BOOST_AUTO_TEST_CASE(attributes)181 BOOST_AUTO_TEST_CASE(attributes)
182 {
183     typedef logging::attribute_set attr_set;
184     typedef logging::core core;
185     typedef logging::record record_type;
186     typedef test_data< char > data;
187 
188     attrs::constant< int > attr1(10);
189     attrs::constant< double > attr2(5.5);
190     attrs::constant< std::string > attr3("Hello, world!");
191 
192     attr_set set1;
193     set1[data::attr1()] = attr1;
194 
195     boost::shared_ptr< core > pCore = core::get();
196     boost::shared_ptr< test_sink > pSink(new test_sink());
197     pCore->add_sink(pSink);
198 
199     attr_set::iterator itGlobal = pCore->add_global_attribute(data::attr2(), attr2).first;
200     attr_set::iterator itThread = pCore->add_thread_attribute(data::attr3(), attr3).first;
201 
202     {
203         attr_set glob = pCore->get_global_attributes();
204         BOOST_CHECK_EQUAL(glob.size(), 1UL);
205         BOOST_CHECK_EQUAL(glob.count(data::attr2()), 1UL);
206 
207         attr_set thr = pCore->get_thread_attributes();
208         BOOST_CHECK_EQUAL(thr.size(), 1UL);
209         BOOST_CHECK_EQUAL(thr.count(data::attr3()), 1UL);
210     }
211     {
212         record_type rec = pCore->open_record(set1);
213         BOOST_REQUIRE(rec);
214         pCore->push_record(boost::move(rec));
215         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
216         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
217         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
218         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 1UL);
219         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
220         pSink->clear();
221     }
222 #ifndef BOOST_LOG_NO_THREADS
223     {
224         boost::thread th(&thread_attributes_test);
225         th.join();
226         BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
227         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
228         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
229         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
230         BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 1UL);
231         pSink->clear();
232 
233         // Thread-specific attributes must not interfere
234         attr_set thr = pCore->get_thread_attributes();
235         BOOST_CHECK_EQUAL(thr.size(), 1UL);
236         BOOST_CHECK_EQUAL(thr.count(data::attr3()), 1UL);
237     }
238 #endif // BOOST_LOG_NO_THREADS
239 
240     pCore->remove_global_attribute(itGlobal);
241     pCore->remove_thread_attribute(itThread);
242     pCore->remove_sink(pSink);
243 }
244