zone_writer_unittest.cc 8.53 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
#include <datasrc/memory/zone_writer.h>
16
#include <datasrc/memory/zone_table_segment_local.h>
17
18
19
20
21
#include <datasrc/memory/zone_data.h>

#include <dns/rrclass.h>
#include <dns/name.h>

22
23
24
#include <datasrc/tests/memory/memory_segment_test.h>
#include <datasrc/tests/memory/zone_table_segment_test.h>

25
26
27
28
29
30
31
32
33
34
#include <gtest/gtest.h>

#include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>

using boost::scoped_ptr;
using boost::bind;
using isc::dns::RRClass;
using isc::dns::Name;
using namespace isc::datasrc::memory;
35
using namespace isc::datasrc::memory::test;
36
37
38
39
40

namespace {

class TestException {};

41
class ZoneWriterTest : public ::testing::Test {
42
protected:
43
    ZoneWriterTest() :
44
        segment_(ZoneTableSegment::create(RRClass::IN(), "local")),
45
        writer_(new
46
            ZoneWriter(*segment_,
47
48
                       bind(&ZoneWriterTest::loadAction, this, _1),
                       Name("example.org"), RRClass::IN())),
49
50
        load_called_(false),
        load_throw_(false),
51
52
        load_null_(false),
        load_data_(false)
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
53
    {}
54
    virtual void TearDown() {
55
56
        // Release the writer
        writer_.reset();
57
58
    }
    scoped_ptr<ZoneTableSegment> segment_;
59
    scoped_ptr<ZoneWriter> writer_;
60
61
    bool load_called_;
    bool load_throw_;
62
    bool load_null_;
63
    bool load_data_;
64
public:
65
66
67
68
    ZoneData* loadAction(isc::util::MemorySegment& segment) {
        // Make sure it is the correct segment passed. We know the
        // exact instance, can compare pointers to them.
        EXPECT_EQ(&segment_->getMemorySegment(), &segment);
69
70
71
72
73
        // We got called
        load_called_ = true;
        if (load_throw_) {
            throw TestException();
        }
74

75
76
77
78
        if (load_null_) {
            // Be nasty to the caller and return NULL, which is forbidden
            return (NULL);
        }
79
80
81
82
83
84
85
86
87
        ZoneData* data = ZoneData::create(segment, Name("example.org"));
        if (load_data_) {
            // Put something inside. The node itself should be enough for
            // the tests.
            ZoneNode* node(NULL);
            data->insertName(segment, Name("subdomain.example.org"), &node);
            EXPECT_NE(static_cast<ZoneNode*>(NULL), node);
        }
        return (data);
88
89
90
    }
};

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
class ReadOnlySegment : public ZoneTableSegmentTest {
public:
    ReadOnlySegment(const isc::dns::RRClass& rrclass,
                    isc::util::MemorySegment& mem_sgmt) :
        ZoneTableSegmentTest(rrclass, mem_sgmt)
    {}

    // Returns false indicating it is a read-only segment. It is used in
    // the ZoneWriter tests.
    virtual bool isWritable() const {
        return (false);
    }
};

TEST_F(ZoneWriterTest, constructForReadOnlySegment) {
    MemorySegmentTest mem_sgmt;
    ReadOnlySegment ztable_segment(RRClass::IN(), mem_sgmt);
108
    EXPECT_THROW(ZoneWriter(ztable_segment,
109
110
                            bind(&ZoneWriterTest::loadAction, this, _1),
                            Name("example.org"), RRClass::IN()),
111
                 isc::InvalidOperation);
112
113
}

114
115
// We call it the way we are supposed to, check every callback is called in the
// right moment.
116
TEST_F(ZoneWriterTest, correctCall) {
117
118
119
120
    // Nothing called before we call it
    EXPECT_FALSE(load_called_);

    // Just the load gets called now
121
    EXPECT_NO_THROW(writer_->load());
122
123
124
    EXPECT_TRUE(load_called_);
    load_called_ = false;

125
    EXPECT_NO_THROW(writer_->install());
126
127
128
129
    EXPECT_FALSE(load_called_);

    // We don't check explicitly how this works, but call it to free memory. If
    // everything is freed should be checked inside the TearDown.
130
    EXPECT_NO_THROW(writer_->cleanup());
131
132
}

133
TEST_F(ZoneWriterTest, loadTwice) {
134
    // Load it the first time
135
    EXPECT_NO_THROW(writer_->load());
136
137
138
139
    EXPECT_TRUE(load_called_);
    load_called_ = false;

    // The second time, it should not be possible
140
    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
141
142
143
    EXPECT_FALSE(load_called_);

    // The object should not be damaged, try installing and clearing now
144
    EXPECT_NO_THROW(writer_->install());
145
146
147
148
    EXPECT_FALSE(load_called_);

    // We don't check explicitly how this works, but call it to free memory. If
    // everything is freed should be checked inside the TearDown.
149
    EXPECT_NO_THROW(writer_->cleanup());
150
151
152
153
}

// Try loading after call to install and call to cleanup. Both is
// forbidden.
154
TEST_F(ZoneWriterTest, loadLater) {
155
    // Load first, so we can install
156
157
    EXPECT_NO_THROW(writer_->load());
    EXPECT_NO_THROW(writer_->install());
158
    // Reset so we see nothing is called now
159
    load_called_ = false;
160

161
    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
162
163
164
    EXPECT_FALSE(load_called_);

    // Cleanup and try loading again. Still shouldn't work.
165
    EXPECT_NO_THROW(writer_->cleanup());
166

167
    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
168
169
170
171
    EXPECT_FALSE(load_called_);
}

// Try calling install at various bad times
172
TEST_F(ZoneWriterTest, invalidInstall) {
173
    // Nothing loaded yet
174
    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
175
176
    EXPECT_FALSE(load_called_);

177
    EXPECT_NO_THROW(writer_->load());
178
179
    load_called_ = false;
    // This install is OK
180
    EXPECT_NO_THROW(writer_->install());
181
    // But we can't call it second time now
182
    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
183
184
185
186
187
188
    EXPECT_FALSE(load_called_);
}

// We check we can clean without installing first and nothing bad
// happens. We also misuse the testcase to check we can't install
// after cleanup.
189
TEST_F(ZoneWriterTest, cleanWithoutInstall) {
190
191
    EXPECT_NO_THROW(writer_->load());
    EXPECT_NO_THROW(writer_->cleanup());
192
193
194
195

    EXPECT_TRUE(load_called_);

    // We cleaned up, no way to install now
196
    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
197
198
199
}

// Test the case when load callback throws
200
TEST_F(ZoneWriterTest, loadThrows) {
201
    load_throw_ = true;
202
    EXPECT_THROW(writer_->load(), TestException);
203
204

    // We can't install now
205
    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
206
207
208
    EXPECT_TRUE(load_called_);

    // But we can cleanup
209
    EXPECT_NO_THROW(writer_->cleanup());
210
211
}

212
213
// Check the strong exception guarantee - if it throws, nothing happened
// to the content.
214
TEST_F(ZoneWriterTest, retry) {
215
    // First attempt fails due to some exception.
216
217
    load_throw_ = true;
    EXPECT_THROW(writer_->load(), TestException);
218
    // This one shall succeed.
219
    load_called_ = load_throw_ = false;
220
221
    // We want some data inside.
    load_data_ = true;
222
    EXPECT_NO_THROW(writer_->load());
223
224
225
    // And this one will fail again. But the old data will survive.
    load_data_ = false;
    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
226
227
228

    // The rest still works correctly
    EXPECT_NO_THROW(writer_->install());
229
230
231
    ZoneTable* const table(segment_->getHeader().getTable());
    const ZoneTable::FindResult found(table->findZone(Name("example.org")));
    ASSERT_EQ(isc::datasrc::result::SUCCESS, found.code);
232
    // For some reason it doesn't seem to work by the ZoneNode typedef, using
233
    // the full definition instead. At least on some compilers.
234
235
236
237
    const isc::datasrc::memory::DomainTreeNode<RdataSet>* node;
    EXPECT_EQ(isc::datasrc::memory::DomainTree<RdataSet>::EXACTMATCH,
              found.zone_data->getZoneTree().
              find(Name("subdomain.example.org"), &node));
238
239
240
    EXPECT_NO_THROW(writer_->cleanup());
}

241
// Check the writer defends itsefl when load action returns NULL
242
TEST_F(ZoneWriterTest, loadNull) {
243
    load_null_ = true;
244
    EXPECT_THROW(writer_->load(), isc::InvalidOperation);
245
246

    // We can't install that
247
    EXPECT_THROW(writer_->install(), isc::InvalidOperation);
248
249

    // It should be possible to clean up safely
250
    EXPECT_NO_THROW(writer_->cleanup());
251
252
}

253
// Check the object cleans up in case we forget it.
254
TEST_F(ZoneWriterTest, autoCleanUp) {
255
256
257
258
259
    // Load data and forget about it. It should get released
    // when the writer itself is destroyed.
    EXPECT_NO_THROW(writer_->load());
}

260
}