Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
91d77e0d
Unverified
Commit
91d77e0d
authored
Dec 13, 2012
by
Michal 'vorner' Vaner
Browse files
Merge
#2378
The Zone loader class (glue class between zone updater and MasterLoader).
parents
70f71c54
27033b59
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/lib/datasrc/Makefile.am
View file @
91d77e0d
...
...
@@ -38,6 +38,7 @@ libb10_datasrc_la_SOURCES += client_list.h client_list.cc
libb10_datasrc_la_SOURCES
+=
memory_datasrc.h memory_datasrc.cc
libb10_datasrc_la_SOURCES
+=
master_loader_callbacks.h
libb10_datasrc_la_SOURCES
+=
master_loader_callbacks.cc
libb10_datasrc_la_SOURCES
+=
zone_loader.h zone_loader.cc
nodist_libb10_datasrc_la_SOURCES
=
datasrc_messages.h datasrc_messages.cc
libb10_datasrc_la_LDFLAGS
=
-no-undefined
-version-info
1:0:1
...
...
src/lib/datasrc/memory/memory_client.cc
View file @
91d77e0d
...
...
@@ -209,14 +209,20 @@ private:
RdataIteratorPtr
rdata_iterator_
;
bool
separate_rrs_
;
bool
ready_
;
bool
examined_rrsigs_
;
// In case there's nsec3 namespace in the zone, it is represented the same
// way as the usual namespace. So we reuse the iterator implementation for
// it.
ZoneIteratorPtr
nsec3_namespace_
;
public:
MemoryIterator
(
const
RRClass
&
rrclass
,
const
ZoneTree
&
tree
,
const
N
ame
&
origin
,
bool
separate_rrs
)
:
const
ZoneTree
&
tree
,
const
N
SEC3Data
*
nsec3_data
,
const
Name
&
origin
,
bool
separate_rrs
)
:
rrclass_
(
rrclass
),
tree_
(
tree
),
separate_rrs_
(
separate_rrs
),
ready_
(
true
)
ready_
(
true
),
examined_rrsigs_
(
false
)
{
// Find the first node (origin) and preserve the node chain for future
// searches
...
...
@@ -235,10 +241,25 @@ public:
rdata_iterator_
=
rrset_
->
getRdataIterator
();
}
}
// If we have the NSEC3 namespace, get an iterator for it so we can
// delegate to it later.
if
(
nsec3_data
!=
NULL
)
{
nsec3_namespace_
=
ZoneIteratorPtr
(
new
MemoryIterator
(
rrclass
,
nsec3_data
->
getNSEC3Tree
(),
NULL
,
origin
,
separate_rrs
));
}
}
virtual
ConstRRsetPtr
getNextRRset
()
{
if
(
!
ready_
)
{
// We are done iterating. But in case there's the nsec3 one,
// iterate through that one.
if
(
nsec3_namespace_
!=
ZoneIteratorPtr
())
{
return
(
nsec3_namespace_
->
getNextRRset
());
}
isc_throw
(
Unexpected
,
"Iterating past the zone end"
);
}
/*
...
...
@@ -259,13 +280,19 @@ public:
rrset_
.
reset
(
new
TreeNodeRRset
(
rrclass_
,
node_
,
set_node_
,
true
));
rdata_iterator_
=
rrset_
->
getRdataIterator
();
examined_rrsigs_
=
false
;
}
}
}
if
(
node_
==
NULL
)
{
// That's all, folks
ready_
=
false
;
return
(
ConstRRsetPtr
());
if
(
nsec3_namespace_
!=
ZoneIteratorPtr
())
{
// In case we have the NSEC3 namespace, get one from there.
return
(
nsec3_namespace_
->
getNextRRset
());
}
else
{
return
(
ConstRRsetPtr
());
}
}
if
(
separate_rrs_
)
{
...
...
@@ -273,10 +300,24 @@ public:
// 'current' rdata
RRsetPtr
result
(
new
RRset
(
rrset_
->
getName
(),
rrset_
->
getClass
(),
rrset_
->
getType
(),
// If we are looking into the signature,
// we need to adjust the type too.
examined_rrsigs_
?
RRType
::
RRSIG
()
:
rrset_
->
getType
(),
rrset_
->
getTTL
()));
result
->
addRdata
(
rdata_iterator_
->
getCurrent
());
rdata_iterator_
->
next
();
if
(
!
examined_rrsigs_
&&
rdata_iterator_
->
isLast
())
{
// We got to the last RR of the RRset, but we need to look at
// the signatures too, if there are any.
examined_rrsigs_
=
true
;
const
ConstRRsetPtr
rrsig
=
rrset_
->
getRRsig
();
if
(
rrsig
!=
ConstRRsetPtr
())
{
rrset_
=
rrsig
;
rdata_iterator_
=
rrsig
->
getRdataIterator
();
}
// else - no RRSIG. rdata_iterator_ stays at last, next
// condition applies
}
if
(
rdata_iterator_
->
isLast
())
{
// all used up, next.
set_node_
=
set_node_
->
getNext
();
...
...
@@ -286,6 +327,7 @@ public:
rrset_
.
reset
(
new
TreeNodeRRset
(
rrclass_
,
node_
,
set_node_
,
true
));
rdata_iterator_
=
rrset_
->
getRdataIterator
();
examined_rrsigs_
=
false
;
}
}
return
(
result
);
...
...
@@ -317,7 +359,8 @@ InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
return
(
ZoneIteratorPtr
(
new
MemoryIterator
(
getClass
(),
result
.
zone_data
->
getZoneTree
(),
name
,
result
.
zone_data
->
getZoneTree
(),
result
.
zone_data
->
getNSEC3Data
(),
name
,
separate_rrs
)));
}
...
...
src/lib/datasrc/tests/Makefile.am
View file @
91d77e0d
...
...
@@ -60,6 +60,7 @@ run_unittests_SOURCES += zone_finder_context_unittest.cc
run_unittests_SOURCES
+=
faked_nsec3.h faked_nsec3.cc
run_unittests_SOURCES
+=
client_list_unittest.cc
run_unittests_SOURCES
+=
master_loader_callbacks_test.cc
run_unittests_SOURCES
+=
zone_loader_unittest.cc
# We need the actual module implementation in the tests (they are not part
# of libdatasrc)
...
...
src/lib/datasrc/tests/memory/memory_client_unittest.cc
View file @
91d77e0d
...
...
@@ -690,6 +690,25 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
EXPECT_EQ
(
ConstRRsetPtr
(),
iterator2
->
getNextRRset
());
}
// Test we get RRSIGs and NSEC3s too for iterating with separate RRs
TEST_F
(
MemoryClientTest
,
getIteratorSeparateSigned
)
{
client_
->
load
(
Name
(
"example.org"
),
TEST_DATA_DIR
"/example.org-nsec3-signed.zone"
);
ZoneIteratorPtr
iterator
(
client_
->
getIterator
(
Name
(
"example.org"
),
true
));
bool
seen_rrsig
=
false
,
seen_nsec3
=
false
;
for
(
ConstRRsetPtr
rrset
=
iterator
->
getNextRRset
();
rrset
!=
ConstRRsetPtr
();
rrset
=
iterator
->
getNextRRset
())
{
if
(
rrset
->
getType
()
==
RRType
::
RRSIG
())
{
seen_rrsig
=
true
;
}
else
if
(
rrset
->
getType
()
==
RRType
::
NSEC3
())
{
seen_nsec3
=
true
;
}
}
EXPECT_TRUE
(
seen_rrsig
);
EXPECT_TRUE
(
seen_nsec3
);
}
TEST_F
(
MemoryClientTest
,
getIteratorGetSOAThrowsNotImplemented
)
{
client_
->
load
(
Name
(
"example.org"
),
TEST_DATA_DIR
"/example.org-empty.zone"
);
ZoneIteratorPtr
iterator
(
client_
->
getIterator
(
Name
(
"example.org"
)));
...
...
src/lib/datasrc/tests/zone_loader_unittest.cc
0 → 100644
View file @
91d77e0d
// 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.
#include <datasrc/zone_loader.h>
#include <datasrc/data_source.h>
#include <datasrc/memory/zone_table_segment.h>
#include <datasrc/memory/memory_client.h>
#include <dns/rrclass.h>
#include <dns/name.h>
#include <dns/rrset.h>
#include <util/memory_segment_local.h>
#include <exceptions/exceptions.h>
#include <gtest/gtest.h>
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
using
isc
::
dns
::
RRClass
;
using
isc
::
dns
::
Name
;
using
isc
::
dns
::
RRType
;
using
isc
::
dns
::
ConstRRsetPtr
;
using
std
::
string
;
using
std
::
vector
;
using
boost
::
shared_ptr
;
using
namespace
isc
::
datasrc
;
namespace
{
class
MockClient
:
public
DataSourceClient
{
public:
MockClient
()
:
commit_called_
(
false
),
missing_zone_
(
false
),
rrclass_
(
RRClass
::
IN
())
{}
virtual
FindResult
findZone
(
const
Name
&
)
const
{
isc_throw
(
isc
::
NotImplemented
,
"Method not used in tests"
);
};
virtual
std
::
pair
<
ZoneJournalReader
::
Result
,
ZoneJournalReaderPtr
>
getJournalReader
(
const
Name
&
,
uint32_t
,
uint32_t
)
const
{
isc_throw
(
isc
::
NotImplemented
,
"Method not used in tests"
);
}
virtual
ZoneUpdaterPtr
getUpdater
(
const
Name
&
name
,
bool
replace
,
bool
journaling
)
const
;
// We store some information about what was happening here.
// It is publicly accessible, since this is private testing class
// anyway, so no need to dress it fancy into getters. Some are mutable,
// since many client methods are const, but we still want to know they
// were called.
mutable
vector
<
Name
>
provided_updaters_
;
// We store string representations of the RRsets. This is simpler than
// copying them and we can't really put them into shared pointers, because
// we get them as references.
vector
<
string
>
rrsets_
;
bool
commit_called_
;
// If set to true, getUpdater returns NULL
bool
missing_zone_
;
// The pretended class of the client. Usualy IN, but can be overriden.
RRClass
rrclass_
;
};
// The updater isn't really correct according to the API. For example,
// the whole client can be committed only once in its lifetime. The
// updaters would influence each other if there were more. But we
// don't need more updaters in the same test, so it doesn't matter
// and this way, it is much simpler.
class
Updater
:
public
ZoneUpdater
{
public:
Updater
(
MockClient
*
client
)
:
client_
(
client
),
finder_
(
client_
->
rrclass_
)
{}
virtual
ZoneFinder
&
getFinder
()
{
return
(
finder_
);
}
virtual
void
addRRset
(
const
isc
::
dns
::
AbstractRRset
&
rrset
)
{
if
(
client_
->
commit_called_
)
{
isc_throw
(
DataSourceError
,
"Add after commit"
);
}
client_
->
rrsets_
.
push_back
(
rrset
.
toText
());
}
virtual
void
deleteRRset
(
const
isc
::
dns
::
AbstractRRset
&
)
{
isc_throw
(
isc
::
NotImplemented
,
"Method not used in tests"
);
}
virtual
void
commit
()
{
client_
->
commit_called_
=
true
;
}
private:
MockClient
*
client_
;
class
Finder
:
public
ZoneFinder
{
public:
Finder
(
const
RRClass
&
rrclass
)
:
class_
(
rrclass
)
{}
virtual
RRClass
getClass
()
const
{
return
(
class_
);
}
virtual
Name
getOrigin
()
const
{
isc_throw
(
isc
::
NotImplemented
,
"Method not used in tests"
);
}
virtual
shared_ptr
<
Context
>
find
(
const
Name
&
,
const
RRType
&
,
const
FindOptions
)
{
isc_throw
(
isc
::
NotImplemented
,
"Method not used in tests"
);
}
virtual
shared_ptr
<
Context
>
findAll
(
const
Name
&
,
vector
<
ConstRRsetPtr
>&
,
const
FindOptions
)
{
isc_throw
(
isc
::
NotImplemented
,
"Method not used in tests"
);
}
virtual
FindNSEC3Result
findNSEC3
(
const
Name
&
,
bool
)
{
isc_throw
(
isc
::
NotImplemented
,
"Method not used in tests"
);
}
private:
const
RRClass
class_
;
}
finder_
;
};
ZoneUpdaterPtr
MockClient
::
getUpdater
(
const
Name
&
name
,
bool
replace
,
bool
journaling
)
const
{
if
(
missing_zone_
)
{
return
(
ZoneUpdaterPtr
());
}
EXPECT_TRUE
(
replace
);
EXPECT_FALSE
(
journaling
);
provided_updaters_
.
push_back
(
name
);
// const_cast is bad. But the const on getUpdater seems wrong in the first
// place, since updater will be modifying the data there. And the updater
// wants to store data into the client so we can examine it later.
return
(
ZoneUpdaterPtr
(
new
Updater
(
const_cast
<
MockClient
*>
(
this
))));
}
class
ZoneLoaderTest
:
public
::
testing
::
Test
{
protected:
ZoneLoaderTest
()
:
rrclass_
(
RRClass
::
IN
()),
ztable_segment_
(
memory
::
ZoneTableSegment
::
create
(
isc
::
data
::
NullElement
(),
rrclass_
)),
source_client_
(
ztable_segment_
,
rrclass_
)
{}
void
prepareSource
(
const
Name
&
zone
,
const
char
*
filename
)
{
// TODO:
// Currently, load uses an urelated implementation. In the long term,
// the method will probably be deprecated. At that time, we should
// probably prepare the data in some other way (using sqlite3 or
// something). This is simpler for now.
source_client_
.
load
(
zone
,
string
(
TEST_DATA_DIR
)
+
"/"
+
filename
);
}
private:
const
RRClass
rrclass_
;
// This is because of the in-memory client. We use it to read data
// from. It is still easier than setting up sqlite3 client, since
// we have this one in the linked library.
// FIXME: We should be destroying it by ZoneTableSegment::destroy.
// But the shared pointer won't let us, will it?
shared_ptr
<
memory
::
ZoneTableSegment
>
ztable_segment_
;
protected:
memory
::
InMemoryClient
source_client_
;
// This one is mocked. It will help us see what is happening inside.
// Also, mocking it is simpler than setting up an sqlite3 client.
MockClient
destination_client_
;
};
// Use the loader to load an unsigned zone.
TEST_F
(
ZoneLoaderTest
,
copyUnsigned
)
{
prepareSource
(
Name
::
ROOT_NAME
(),
"root.zone"
);
ZoneLoader
loader
(
destination_client_
,
Name
::
ROOT_NAME
(),
source_client_
);
// It gets the updater directly in the constructor
ASSERT_EQ
(
1
,
destination_client_
.
provided_updaters_
.
size
());
EXPECT_EQ
(
Name
::
ROOT_NAME
(),
destination_client_
.
provided_updaters_
[
0
]);
// Now load the whole zone
loader
.
load
();
EXPECT_TRUE
(
destination_client_
.
commit_called_
);
// We don't check the whole zone. We check the first and last and the
// count, which should be enough.
// The count is 34 because we expect the RRs to be separated.
EXPECT_EQ
(
34
,
destination_client_
.
rrsets_
.
size
());
// Ensure known order.
std
::
sort
(
destination_client_
.
rrsets_
.
begin
(),
destination_client_
.
rrsets_
.
end
());
EXPECT_EQ
(
". 518400 IN NS a.root-servers.net.
\n
"
,
destination_client_
.
rrsets_
.
front
());
EXPECT_EQ
(
"m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
\n
"
,
destination_client_
.
rrsets_
.
back
());
// It isn't possible to try again now
EXPECT_THROW
(
loader
.
load
(),
isc
::
InvalidOperation
);
EXPECT_THROW
(
loader
.
loadIncremental
(
1
),
isc
::
InvalidOperation
);
// Even 0, which should load nothing, returns the error
EXPECT_THROW
(
loader
.
loadIncremental
(
0
),
isc
::
InvalidOperation
);
}
// Try loading incrementally.
TEST_F
(
ZoneLoaderTest
,
copyUnsignedIncremental
)
{
prepareSource
(
Name
::
ROOT_NAME
(),
"root.zone"
);
ZoneLoader
loader
(
destination_client_
,
Name
::
ROOT_NAME
(),
source_client_
);
// Try loading few RRs first.
loader
.
loadIncremental
(
10
);
// We should get the 10 we asked for
EXPECT_EQ
(
10
,
destination_client_
.
rrsets_
.
size
());
// Not committed yet, we didn't complete the loading
EXPECT_FALSE
(
destination_client_
.
commit_called_
);
// This is unusual, but allowed. Check it doesn't do anything
loader
.
loadIncremental
(
0
);
EXPECT_EQ
(
10
,
destination_client_
.
rrsets_
.
size
());
EXPECT_FALSE
(
destination_client_
.
commit_called_
);
// We can finish the rest
loader
.
loadIncremental
(
30
);
EXPECT_EQ
(
34
,
destination_client_
.
rrsets_
.
size
());
EXPECT_TRUE
(
destination_client_
.
commit_called_
);
// No more loading now
EXPECT_THROW
(
loader
.
load
(),
isc
::
InvalidOperation
);
EXPECT_THROW
(
loader
.
loadIncremental
(
1
),
isc
::
InvalidOperation
);
EXPECT_THROW
(
loader
.
loadIncremental
(
0
),
isc
::
InvalidOperation
);
}
// Check we can load RRSIGs and NSEC3 (which could break due to them being
// in separate namespace)
TEST_F
(
ZoneLoaderTest
,
copySigned
)
{
prepareSource
(
Name
(
"example.org"
),
"example.org.nsec3-signed"
);
ZoneLoader
loader
(
destination_client_
,
Name
(
"example.org"
),
source_client_
);
loader
.
load
();
// All the RRs are there, including the ones in NSEC3 namespace
EXPECT_EQ
(
14
,
destination_client_
.
rrsets_
.
size
());
EXPECT_TRUE
(
destination_client_
.
commit_called_
);
// Same trick with sorting to know where they are
std
::
sort
(
destination_client_
.
rrsets_
.
begin
(),
destination_client_
.
rrsets_
.
end
());
// Due to the R at the beginning, this one should be last
EXPECT_EQ
(
"09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 "
"1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
\n
"
,
destination_client_
.
rrsets_
[
0
]);
EXPECT_EQ
(
"09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG "
"NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org."
" EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKOyfZc8w"
"KRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVvcD3dFksPyiKHf"
"/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3CTM=
\n
"
,
destination_client_
.
rrsets_
[
1
]);
}
// If the destination zone does not exist, it throws
TEST_F
(
ZoneLoaderTest
,
copyMissingDestination
)
{
destination_client_
.
missing_zone_
=
true
;
prepareSource
(
Name
::
ROOT_NAME
(),
"root.zone"
);
EXPECT_THROW
(
ZoneLoader
(
destination_client_
,
Name
::
ROOT_NAME
(),
source_client_
),
DataSourceError
);
}
// If the source zone does not exist, it throws
TEST_F
(
ZoneLoaderTest
,
copyMissingSource
)
{
EXPECT_THROW
(
ZoneLoader
(
destination_client_
,
Name
::
ROOT_NAME
(),
source_client_
),
DataSourceError
);
}
// The class of the source and destination are different
TEST_F
(
ZoneLoaderTest
,
classMismatch
)
{
destination_client_
.
rrclass_
=
RRClass
::
CH
();
prepareSource
(
Name
::
ROOT_NAME
(),
"root.zone"
);
EXPECT_THROW
(
ZoneLoader
(
destination_client_
,
Name
::
ROOT_NAME
(),
source_client_
),
isc
::
InvalidParameter
);
}
// Load an unsigned zone, all at once
TEST_F
(
ZoneLoaderTest
,
loadUnsigned
)
{
ZoneLoader
loader
(
destination_client_
,
Name
::
ROOT_NAME
(),
TEST_DATA_DIR
"/root.zone"
);
// It gets the updater directly in the constructor
ASSERT_EQ
(
1
,
destination_client_
.
provided_updaters_
.
size
());
EXPECT_EQ
(
Name
::
ROOT_NAME
(),
destination_client_
.
provided_updaters_
[
0
]);
// Now load the whole zone
loader
.
load
();
EXPECT_TRUE
(
destination_client_
.
commit_called_
);
// We don't check the whole zone. We check the first and last and the
// count, which should be enough.
// The count is 34 because we expect the RRs to be separated.
EXPECT_EQ
(
34
,
destination_client_
.
rrsets_
.
size
());
// Ensure known order.
std
::
sort
(
destination_client_
.
rrsets_
.
begin
(),
destination_client_
.
rrsets_
.
end
());
EXPECT_EQ
(
". 518400 IN NS a.root-servers.net.
\n
"
,
destination_client_
.
rrsets_
.
front
());
EXPECT_EQ
(
"m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
\n
"
,
destination_client_
.
rrsets_
.
back
());
// It isn't possible to try again now
EXPECT_THROW
(
loader
.
load
(),
isc
::
InvalidOperation
);
EXPECT_THROW
(
loader
.
loadIncremental
(
1
),
isc
::
InvalidOperation
);
// Even 0, which should load nothing, returns the error
EXPECT_THROW
(
loader
.
loadIncremental
(
0
),
isc
::
InvalidOperation
);
}
// Try loading from master file incrementally.
TEST_F
(
ZoneLoaderTest
,
loadUnsignedIncremental
)
{
ZoneLoader
loader
(
destination_client_
,
Name
::
ROOT_NAME
(),
TEST_DATA_DIR
"/root.zone"
);
// Try loading few RRs first.
loader
.
loadIncremental
(
10
);
// We should get the 10 we asked for
EXPECT_EQ
(
10
,
destination_client_
.
rrsets_
.
size
());
// Not committed yet, we didn't complete the loading
EXPECT_FALSE
(
destination_client_
.
commit_called_
);
// This is unusual, but allowed. Check it doesn't do anything
loader
.
loadIncremental
(
0
);
EXPECT_EQ
(
10
,
destination_client_
.
rrsets_
.
size
());
EXPECT_FALSE
(
destination_client_
.
commit_called_
);
// We can finish the rest
loader
.
loadIncremental
(
30
);
EXPECT_EQ
(
34
,
destination_client_
.
rrsets_
.
size
());
EXPECT_TRUE
(
destination_client_
.
commit_called_
);
// No more loading now
EXPECT_THROW
(
loader
.
load
(),
isc
::
InvalidOperation
);
EXPECT_THROW
(
loader
.
loadIncremental
(
1
),
isc
::
InvalidOperation
);
EXPECT_THROW
(
loader
.
loadIncremental
(
0
),
isc
::
InvalidOperation
);
}
// If the destination zone does not exist, it throws
TEST_F
(
ZoneLoaderTest
,
loadMissingDestination
)
{
destination_client_
.
missing_zone_
=
true
;
EXPECT_THROW
(
ZoneLoader
(
destination_client_
,
Name
::
ROOT_NAME
(),
TEST_DATA_DIR
"/root.zone"
),
DataSourceError
);
}
// Check we can load RRSIGs and NSEC3 (which could break due to them being
// in separate namespace)
TEST_F
(
ZoneLoaderTest
,
loadSigned
)
{
ZoneLoader
loader
(
destination_client_
,
Name
(
"example.org"
),
TEST_DATA_DIR
"/example.org.nsec3-signed"
);
loader
.
load
();
// All the RRs are there, including the ones in NSEC3 namespace
EXPECT_EQ
(
14
,
destination_client_
.
rrsets_
.
size
());
EXPECT_TRUE
(
destination_client_
.
commit_called_
);
// Same trick with sorting to know where they are
std
::
sort
(
destination_client_
.
rrsets_
.
begin
(),
destination_client_
.
rrsets_
.
end
());
// Due to the R at the beginning, this one should be last
EXPECT_EQ
(
"09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 "
"1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
\n
"
,
destination_client_
.
rrsets_
[
0
]);
EXPECT_EQ
(
"09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG "
"NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org."
" EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKOyfZc8w"
"KRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVvcD3dFksPyiKHf"
"/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3CTM=
\n
"
,
destination_client_
.
rrsets_
[
1
]);
}
// Test it throws when there's no such file
TEST_F
(
ZoneLoaderTest
,
loadNoSuchFile
)
{
ZoneLoader
loader
(
destination_client_
,
Name
::
ROOT_NAME
(),
"This file does not exist"
);
EXPECT_THROW
(
loader
.
load
(),
MasterFileError
);
EXPECT_FALSE
(
destination_client_
.
commit_called_
);
}
// And it also throws when there's a syntax error in the master file
TEST_F
(
ZoneLoaderTest
,
loadSyntaxError
)
{
ZoneLoader
loader
(
destination_client_
,
Name
::
ROOT_NAME
(),
// This is not a master file for sure
// (misusing a file that happens to be there
// already).
TEST_DATA_DIR
"/example.org.sqlite3"
);
EXPECT_THROW
(
loader
.
load
(),
MasterFileError
);
EXPECT_FALSE
(
destination_client_
.
commit_called_
);
}
}
src/lib/datasrc/zone_loader.cc
0 → 100644
View file @
91d77e0d
// 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.
#include <datasrc/zone_loader.h>
#include <datasrc/master_loader_callbacks.h>
#include <datasrc/client.h>
#include <datasrc/data_source.h>
#include <datasrc/iterator.h>
#include <datasrc/zone.h>
#include <dns/rrset.h>
using
isc
::
dns
::
Name
;
using
isc
::
dns
::
ConstRRsetPtr
;
using
isc
::
dns
::
MasterLoader
;
namespace
isc
{
namespace
datasrc
{
ZoneLoader
::
ZoneLoader
(
DataSourceClient
&
destination
,
const
Name
&
zone_name
,
DataSourceClient
&
source
)
:
// Separate the RRsets as that is possibly faster (the data source doesn't
// have to aggregate them) and also because our limit semantics.
iterator_
(
source
.
getIterator
(
zone_name
,
true
)),
updater_
(
destination
.
getUpdater
(
zone_name
,
true
,
false
)),
complete_
(
false
)
{
// The getIterator should never return NULL. So we check it.
// Or should we throw instead?
assert
(
iterator_
!=
ZoneIteratorPtr
());
// In case the zone doesn't exist in the destination, throw
if
(
updater_
==
ZoneUpdaterPtr
())
{
isc_throw
(
DataSourceError
,
"Zone "
<<
zone_name
<<
" not found in "
"destination data source, can't fill it with data"
);
}
// The dereference of zone_finder is safe, if we ca